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