1 /** Deep duplication. 2 3 Move to Phobos somewhere. 4 5 TODO: Support inout relevant for const? 6 See: http://forum.dlang.org/thread/hojk95$4mk$1@digitalmars.com 7 */ 8 module nxt.deepdup; 9 10 import core.internal.traits : Unqual; 11 import std.typecons : tuple, Tuple; 12 import std.meta : staticMap; 13 import std.traits : isDynamicArray, isArray, isPointer; 14 import std.range.primitives : ElementType; 15 16 alias TypeofDeepdup(T) = typeof(deepdup(T.init)); 17 18 ref Unqual!T deepdup(T)(T t) 19 if (is(T == struct) && 20 !is(T.Types)) { 21 staticMap!(TypeofDeepdup, typeof(t.tupleof)) tup; 22 foreach (const i, Type; tup) 23 tup[i] = t.tupleof[i].deepdup; 24 return Unqual!T(tup); 25 } 26 27 Tuple!(staticMap!(TypeofDeepdup, T.Types)) deepdup(T)(T t) 28 if (is(T.Types)) { 29 staticMap!(TypeofDeepdup, T.Types) tup; 30 foreach (const i, Type; tup) 31 tup[i] = t.field[i].deepdup; 32 return tuple(tup); 33 } 34 35 Unqual!T deepdup(T)(T t) 36 if (is(T == class)) { 37 staticMap!(TypeofDeepdup, typeof(t.tupleof)) tup; 38 foreach (const i, Type; tup) 39 tup[i] = t.tupleof[i].deepdup; 40 return new Unqual!T(tup); 41 } 42 43 TypeofDeepdup!(ElementType!T)[] deepdup(T)(T t) 44 if (isDynamicArray!T) { 45 auto result = new TypeofDeepdup!(ElementType!T)[](t.length); 46 foreach (const i, elem; t) 47 result[i] = elem.deepdup; 48 return result; 49 } 50 51 TypeofDeepdup!(ElementType!T)[T.length] deepdup(T)(T t) 52 if (__traits(isStaticArray, T)) { 53 TypeofDeepdup!(ElementType!T)[T.length] result = t; 54 foreach (ref elem; result) 55 elem = elem.deepdup; 56 return result; 57 } 58 59 TypeofDeepdup!T* deepdup(T)(T* t) => &deepdup(*t); 60 61 Unqual!T deepdup(T)(T t) if (!is(T == struct) && 62 !is(T == class) && 63 !isArray!T && 64 !is(T.Types) && 65 !isPointer!T) 66 => cast(Unqual!T)t; 67 68 @safe pure nothrow: 69 70 /// 71 unittest { 72 auto x = [1, 2, 3]; 73 assert(x == x.dup); 74 auto y = x; 75 assert(&x[0] == &y[0]); 76 assert(&x[0] != &x.dup[0]); 77 } 78 79 /// 80 unittest { 81 auto x = [[1], [2], [3]]; 82 auto y = x.dup; 83 x[0][0] = 11; 84 assert(x[0][0] == 11); 85 assert(y[0][0] == 11); 86 } 87 88 /// 89 unittest { 90 auto x = [[1], [2], [3]]; 91 auto y = x.deepdup; 92 x[0][0] = 11; 93 assert(x[0][0] == 11); 94 assert(y[0][0] == 1); 95 } 96 97 /// 98 unittest { 99 auto x = [[1], [2], [3]]; 100 auto y = x.deepdup; 101 x[0][0] = 11; 102 assert(x[0][0] == 11); 103 assert(y[0][0] == 1); 104 } 105 106 /// 107 unittest { 108 auto x = [[[1]], [[2]], [[3]]]; 109 auto y = x.deepdup; 110 x[0][0][0] = 11; 111 assert(x[0][0][0] == 11); 112 assert(y[0][0][0] == 1); 113 } 114 115 /// dup of static array 116 unittest { 117 int[3] x = [1, 2, 3]; 118 auto y = x.dup; 119 x[0] = 11; 120 assert(x[0] == 11); 121 assert(y[0] == 1); 122 } 123 124 /// dup of static array of dynamic arrays 125 unittest { 126 int[][3] x = [[1], [2], [3]]; 127 auto y = x.dup; 128 x[0][0] = 11; 129 assert(x[0][0] == 11); 130 assert(y[0][0] == 11); 131 } 132 133 /// deepdup of static array of dynamic arrays 134 unittest { 135 int[][3] x = [[1], [2], [3]]; 136 auto y = x.deepdup; 137 x[0][0] = 11; 138 assert(x[0][0] == 11); 139 assert(y[0][0] == 1); 140 }