1251875Spetermodule core.internal.lifetime; 2251875Speter 3251875Speterimport core.lifetime : forward; 4251875Speter 5251875Speter/+ 6251875SpeteremplaceRef is a package function for druntime internal use. It works like 7251875Speteremplace, but takes its argument by ref (as opposed to "by pointer"). 8251875SpeterThis makes it easier to use, easier to be safe, and faster in a non-inline 9251875Speterbuild. 10251875SpeterFurthermore, emplaceRef optionally takes a type parameter, which specifies 11251875Speterthe type we want to build. This helps to build qualified objects on mutable 12251875Speterbuffer, without breaking the type system with unsafe casts. 13251875Speter+/ 14251875Spetervoid emplaceRef(T, UT, Args...)(ref UT chunk, auto ref Args args) 15251875Speter{ 16251875Speter static if (args.length == 0) 17251875Speter { 18251875Speter static assert(is(typeof({static T i;})), 19251875Speter "Cannot emplace a " ~ T.stringof ~ " because " ~ T.stringof ~ 20251875Speter ".this() is annotated with @disable."); 21251875Speter static if (is(T == class)) static assert(!__traits(isAbstractClass, T), 22251875Speter T.stringof ~ " is abstract and it can't be emplaced"); 23251875Speter emplaceInitializer(chunk); 24251875Speter } 25251875Speter else static if ( 26251875Speter !is(T == struct) && Args.length == 1 /* primitives, enums, arrays */ 27251875Speter || 28251875Speter Args.length == 1 && is(typeof({T t = forward!(args[0]);})) /* conversions */ 29251875Speter || 30251875Speter is(typeof(T(forward!args))) /* general constructors */) 31251875Speter { 32251875Speter static struct S 33251875Speter { 34251875Speter T payload; 35251875Speter this()(auto ref Args args) 36251875Speter { 37251875Speter static if (__traits(compiles, payload = forward!args)) 38251875Speter payload = forward!args; 39251875Speter else 40251875Speter payload = T(forward!args); 41251875Speter } 42251875Speter } 43251875Speter if (__ctfe) 44251875Speter { 45251875Speter static if (__traits(compiles, chunk = T(forward!args))) 46251875Speter chunk = T(forward!args); 47251875Speter else static if (args.length == 1 && __traits(compiles, chunk = forward!(args[0]))) 48251875Speter chunk = forward!(args[0]); 49251875Speter 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