1module core.internal.lifetime; 2 3import core.lifetime : forward; 4 5/+ 6emplaceRef is a package function for druntime internal use. It works like 7emplace, but takes its argument by ref (as opposed to "by pointer"). 8This makes it easier to use, easier to be safe, and faster in a non-inline 9build. 10Furthermore, emplaceRef optionally takes a type parameter, which specifies 11the type we want to build. This helps to build qualified objects on mutable 12buffer, without breaking the type system with unsafe casts. 13+/ 14void emplaceRef(T, UT, Args...)(ref UT chunk, auto ref Args args) 15{ 16 static if (args.length == 0) 17 { 18 static assert(is(typeof({static T i;})), 19 "Cannot emplace a " ~ T.stringof ~ " because " ~ T.stringof ~ 20 ".this() is annotated with @disable."); 21 static if (is(T == class)) static assert(!__traits(isAbstractClass, T), 22 T.stringof ~ " is abstract and it can't be emplaced"); 23 emplaceInitializer(chunk); 24 } 25 else static if ( 26 !is(T == struct) && Args.length == 1 /* primitives, enums, arrays */ 27 || 28 Args.length == 1 && is(typeof({T t = forward!(args[0]);})) /* conversions */ 29 || 30 is(typeof(T(forward!args))) /* general constructors */) 31 { 32 static struct S 33 { 34 T payload; 35 this()(auto ref Args args) 36 { 37 static if (__traits(compiles, payload = forward!args)) 38 payload = forward!args; 39 else 40 payload = T(forward!args); 41 } 42 } 43 if (__ctfe) 44 { 45 static if (__traits(compiles, chunk = T(forward!args))) 46 chunk = T(forward!args); 47 else static if (args.length == 1 && __traits(compiles, chunk = forward!(args[0]))) 48 chunk = forward!(args[0]); 49 else assert(0, "CTFE emplace doesn't support " 50 ~ T.stringof ~ " from " ~ Args.stringof); 51 } 52 else 53 { 54 S* p = () @trusted { return cast(S*) &chunk; }(); 55 static if (UT.sizeof > 0) 56 emplaceInitializer(*p); 57 p.__ctor(forward!args); 58 } 59 } 60 else static if (is(typeof(chunk.__ctor(forward!args)))) 61 { 62 // This catches the rare case of local types that keep a frame pointer 63 emplaceInitializer(chunk); 64 chunk.__ctor(forward!args); 65 } 66 else 67 { 68 //We can't emplace. Try to diagnose a disabled postblit. 69 static assert(!(Args.length == 1 && is(Args[0] : T)), 70 "Cannot emplace a " ~ T.stringof ~ " because " ~ T.stringof ~ 71 ".this(this) is annotated with @disable."); 72 73 //We can't emplace. 74 static assert(false, 75 T.stringof ~ " cannot be emplaced from " ~ Args[].stringof ~ "."); 76 } 77} 78 79// ditto 80static import core.internal.traits; 81void emplaceRef(UT, Args...)(ref UT chunk, auto ref Args args) 82if (is(UT == core.internal.traits.Unqual!UT)) 83{ 84 emplaceRef!(UT, UT)(chunk, forward!args); 85} 86 87/+ 88Emplaces T.init. 89In contrast to `emplaceRef(chunk)`, there are no checks for disabled default 90constructors etc. 91+/ 92void emplaceInitializer(T)(scope ref T chunk) nothrow pure @trusted 93if (!is(T == const) && !is(T == immutable) && !is(T == inout)) 94{ 95 import core.internal.traits : hasElaborateAssign; 96 97 static if (__traits(isZeroInit, T)) 98 { 99 import core.stdc.string : memset; 100 memset(cast(void*) &chunk, 0, T.sizeof); 101 } 102 else static if (__traits(isScalar, T) || 103 T.sizeof <= 16 && !hasElaborateAssign!T && __traits(compiles, (){ T chunk; chunk = T.init; })) 104 { 105 chunk = T.init; 106 } 107 else static if (__traits(isStaticArray, T)) 108 { 109 // For static arrays there is no initializer symbol created. Instead, we emplace elements one-by-one. 110 foreach (i; 0 .. T.length) 111 { 112 emplaceInitializer(chunk[i]); 113 } 114 } 115 else 116 { 117 import core.stdc.string : memcpy; 118 const initializer = __traits(initSymbol, T); 119 memcpy(cast(void*)&chunk, initializer.ptr, initializer.length); 120 } 121} 122 123@safe unittest 124{ 125 static void testInitializer(T)() 126 { 127 // mutable T 128 { 129 T dst = void; 130 emplaceInitializer(dst); 131 assert(dst is T.init); 132 } 133 134 // shared T 135 { 136 shared T dst = void; 137 emplaceInitializer(dst); 138 assert(dst is shared(T).init); 139 } 140 141 // const T 142 { 143 const T dst = void; 144 static assert(!__traits(compiles, emplaceInitializer(dst))); 145 } 146 } 147 148 static struct ElaborateAndZero 149 { 150 int a; 151 this(this) {} 152 } 153 154 static struct ElaborateAndNonZero 155 { 156 int a = 42; 157 this(this) {} 158 } 159 160 static union LargeNonZeroUnion 161 { 162 byte[128] a = 1; 163 } 164 165 testInitializer!int(); 166 testInitializer!double(); 167 testInitializer!ElaborateAndZero(); 168 testInitializer!ElaborateAndNonZero(); 169 testInitializer!LargeNonZeroUnion(); 170 171 static if (is(__vector(double[4]))) 172 { 173 // DMD 2.096 and GDC 11.1 can't compare vectors with `is` so can't use 174 // testInitializer. 175 enum VE : __vector(double[4]) 176 { 177 a = [1.0, 2.0, 3.0, double.nan], 178 b = [4.0, 5.0, 6.0, double.nan], 179 } 180 const VE expected = VE.a; 181 VE dst = VE.b; 182 shared VE sharedDst = VE.b; 183 emplaceInitializer(dst); 184 emplaceInitializer(sharedDst); 185 () @trusted { 186 import core.stdc.string : memcmp; 187 assert(memcmp(&expected, &dst, VE.sizeof) == 0); 188 assert(memcmp(&expected, cast(void*) &sharedDst, VE.sizeof) == 0); 189 }(); 190 static assert(!__traits(compiles, emplaceInitializer(expected))); 191 } 192} 193 194/* 195Simple swap function. 196*/ 197void swap(T)(ref T lhs, ref T rhs) 198{ 199 import core.lifetime : move, moveEmplace; 200 201 T tmp = move(lhs); 202 moveEmplace(rhs, lhs); 203 moveEmplace(tmp, rhs); 204} 205