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 /++ Returns: Copy of `x` where each members `m` is duplicated via `m.dup` if 19 possible. +/ 20 T dupMembers(T)(T x) @safe pure nothrow if (is(T == struct)) { 21 typeof(return)ret; 22 foreach (const i, member; x.tupleof) { 23 static if(__traits(compiles, member.dup)) 24 ret.tupleof[i] = member.dup; 25 else 26 ret.tupleof[i] = member; 27 } 28 return ret; 29 } 30 31 /// 32 @safe pure nothrow unittest { 33 struct S { 34 int ia; 35 int ib; 36 string s; // @gc 37 } 38 S x = { ia: 42, ib: 43, s: "abc" }; 39 auto y = x.dupMembers; 40 assert(x == y); 41 assert(x.s !is y.s); 42 } 43 44 ref Unqual!T deepdup(T)(T t) 45 if (is(T == struct) && 46 !is(T.Types)) { 47 staticMap!(TypeofDeepdup, typeof(t.tupleof)) tup; 48 foreach (const i, Type; tup) 49 tup[i] = t.tupleof[i].deepdup; 50 return Unqual!T(tup); 51 } 52 53 Tuple!(staticMap!(TypeofDeepdup, T.Types)) deepdup(T)(T t) 54 if (is(T.Types)) { 55 staticMap!(TypeofDeepdup, T.Types) tup; 56 foreach (const i, Type; tup) 57 tup[i] = t.field[i].deepdup; 58 return tuple(tup); 59 } 60 61 Unqual!T deepdup(T)(T t) 62 if (is(T == class)) { 63 staticMap!(TypeofDeepdup, typeof(t.tupleof)) tup; 64 foreach (const i, Type; tup) 65 tup[i] = t.tupleof[i].deepdup; 66 return new Unqual!T(tup); 67 } 68 69 TypeofDeepdup!(ElementType!T)[] deepdup(T)(T t) 70 if (isDynamicArray!T) { 71 auto result = new TypeofDeepdup!(ElementType!T)[](t.length); 72 foreach (const i, elem; t) 73 result[i] = elem.deepdup; 74 return result; 75 } 76 77 TypeofDeepdup!(ElementType!T)[T.length] deepdup(T)(T t) 78 if (__traits(isStaticArray, T)) { 79 TypeofDeepdup!(ElementType!T)[T.length] result = t; 80 foreach (ref elem; result) 81 elem = elem.deepdup; 82 return result; 83 } 84 85 TypeofDeepdup!T* deepdup(T)(T* t) => &deepdup(*t); 86 87 Unqual!T deepdup(T)(T t) if (!is(T == struct) && 88 !is(T == class) && 89 !isArray!T && 90 !is(T.Types) && 91 !isPointer!T) 92 => cast(Unqual!T)t; 93 94 @safe pure nothrow: 95 96 /// 97 unittest { 98 auto x = [1, 2, 3]; 99 assert(x == x.dup); 100 auto y = x; 101 assert(&x[0] == &y[0]); 102 assert(&x[0] != &x.dup[0]); 103 } 104 105 /// 106 unittest { 107 auto x = [[1], [2], [3]]; 108 auto y = x.dup; 109 x[0][0] = 11; 110 assert(x[0][0] == 11); 111 assert(y[0][0] == 11); 112 } 113 114 /// 115 unittest { 116 auto x = [[1], [2], [3]]; 117 auto y = x.deepdup; 118 x[0][0] = 11; 119 assert(x[0][0] == 11); 120 assert(y[0][0] == 1); 121 } 122 123 /// 124 unittest { 125 auto x = [[1], [2], [3]]; 126 auto y = x.deepdup; 127 x[0][0] = 11; 128 assert(x[0][0] == 11); 129 assert(y[0][0] == 1); 130 } 131 132 /// 133 unittest { 134 auto x = [[[1]], [[2]], [[3]]]; 135 auto y = x.deepdup; 136 x[0][0][0] = 11; 137 assert(x[0][0][0] == 11); 138 assert(y[0][0][0] == 1); 139 } 140 141 /// dup of static array 142 unittest { 143 int[3] x = [1, 2, 3]; 144 auto y = x.dup; 145 x[0] = 11; 146 assert(x[0] == 11); 147 assert(y[0] == 1); 148 } 149 150 /// dup of static array of dynamic arrays 151 unittest { 152 int[][3] x = [[1], [2], [3]]; 153 auto y = x.dup; 154 x[0][0] = 11; 155 assert(x[0][0] == 11); 156 assert(y[0][0] == 11); 157 } 158 159 /// deepdup of static array of dynamic arrays 160 unittest { 161 int[][3] x = [[1], [2], [3]]; 162 auto y = x.deepdup; 163 x[0][0] = 11; 164 assert(x[0][0] == 11); 165 assert(y[0][0] == 1); 166 }