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