1 /// Replace a type with an "equivalent" type without constructors, destructors, and mutable. 2 module rebindable.DeepUnqual; 3 4 import std.meta; 5 import std.traits; 6 import std.typecons; 7 8 /** 9 * `DeepUnqual!T` is a data type that is equivalent to `T` in terms of size, alignment, and GC properties, 10 * except that it can be freely reassigned. 11 * 12 * All methods of `T`, including constructors, destructors and overloads, are lost. 13 * In fact, the result type has barely anything to do with `T`, except the following properties: 14 * 15 * $(UL 16 * $(LI mutable) 17 * $(LI pointers where `T` has pointers) 18 * $(LI non-pointer values where `T` has no pointers (best-effort).)) 19 * 20 * In other words, `T` is equivalent to `DeepUnqual!T` for the purpose of memory management, and nothing else. 21 */ 22 public template DeepUnqual(T) 23 { 24 alias DeepUnqual = DeepUnqualImpl!T; 25 26 static assert(T.sizeof == DeepUnqual.sizeof); 27 static assert(T.alignof == DeepUnqual.alignof); 28 static assert(hasIndirections!T == hasIndirections!DeepUnqual); 29 } 30 31 private template DeepUnqualImpl(T) 32 { 33 static if (is(T == struct)) 34 { 35 static if (anyPairwiseEqual!(staticMap!(offsetOf, T.tupleof))) 36 { 37 // Struct with anonymous unions detected! 38 // Danger, danger! 39 // Fall back to void[]. 40 align(T.alignof) 41 struct DeepUnqualImpl 42 { 43 void[T.sizeof] data; 44 } 45 } 46 else 47 { 48 align(T.alignof) 49 struct DeepUnqualImpl 50 { 51 staticMap!(DeepUnqual, typeof(T.init.tupleof)) fields; 52 } 53 } 54 } 55 else static if (is(T == union) || isAssociativeArray!T) 56 { 57 align(T.alignof) 58 struct DeepUnqualImpl 59 { 60 static if (hasIndirections!T) 61 { 62 void[T.sizeof] data; 63 } 64 else 65 { 66 // union of non-pointer types? 67 ubyte[T.sizeof] data; 68 } 69 } 70 } 71 else static if (is(T == class) || is(T == interface) || is(T == function) || is(T : U*, U)) 72 { 73 alias DeepUnqualImpl = void*; 74 } 75 else static if (is(T : K[], K)) 76 { 77 struct DeepUnqualImpl 78 { 79 size_t length; 80 void* ptr; 81 } 82 } 83 else static if (is(T == delegate)) 84 { 85 struct DeepUnqualImpl 86 { 87 void* data; 88 void* funcptr; 89 } 90 } 91 else static if (is(T == enum)) 92 { 93 alias DeepUnqualImpl = DeepUnqual!(OriginalType!T); 94 } 95 else static if (staticIndexOf!(typeof(cast() T.init), 96 bool, byte, ubyte, short, ushort, int, uint, long, ulong, 97 char, wchar, dchar, float, double, real, ifloat, idouble, ireal, cfloat, cdouble, creal) != -1) 98 { 99 alias DeepUnqualImpl = typeof(cast() T.init); 100 } 101 else static if (is(T == U[size], U, size_t size)) 102 { 103 alias DeepUnqualImpl = DeepUnqual!U[size]; 104 } 105 else 106 { 107 static assert(false, "Unsupported type " ~ T.stringof); 108 } 109 } 110 111 private enum offsetOf(alias member) = member.offsetof; 112 113 private template anyPairwiseEqual(T...) 114 { 115 static if (T.length == 0 || T.length == 1) 116 { 117 enum anyPairwiseEqual = false; 118 } 119 else static if (T.length == 2) 120 { 121 enum anyPairwiseEqual = T[0] == T[1]; 122 } 123 else 124 { 125 enum anyPairwiseEqual = T[0] == T[1] || anyPairwiseEqual!(T[1 .. $]); 126 } 127 }