@@ -3412,10 +3412,9 @@ as $(D chunk)).
34123412T* emplace (T)(T* chunk)
34133413 if (! is (T == class ))
34143414{
3415- auto result = cast (typeof (return )) chunk;
3416- static T i;
3417- memcpy(result, &i, T.sizeof);
3418- return result;
3415+ static T i; // Can't use `= T.init` here because of @@@BUG8902@@@.
3416+ memcpy(chunk, &i, T.sizeof);
3417+ return chunk;
34193418}
34203419// /ditto
34213420T* emplace (T)(T* chunk)
@@ -3425,6 +3424,64 @@ T* emplace(T)(T* chunk)
34253424 return chunk;
34263425}
34273426
3427+ version (unittest ) private struct __conv_EmplaceTest
3428+ {
3429+ int i = 3 ;
3430+ this (int i)
3431+ {
3432+ assert (this .i == 3 && i == 5 );
3433+ this .i = i;
3434+ }
3435+ this (int i, ref int j)
3436+ {
3437+ assert (i == 5 && j == 6 );
3438+ this .i = i;
3439+ ++ j;
3440+ }
3441+
3442+ @disable :
3443+ this ();
3444+ this (this );
3445+ void opAssign ();
3446+ }
3447+
3448+ version (unittest ) private class __conv_EmplaceTestClass
3449+ {
3450+ int i = 3 ;
3451+ this (int i)
3452+ {
3453+ assert (this .i == 3 && i == 5 );
3454+ this .i = i;
3455+ }
3456+ this (int i, ref int j)
3457+ {
3458+ assert (i == 5 && j == 6 );
3459+ this .i = i;
3460+ ++ j;
3461+ }
3462+ }
3463+
3464+ unittest
3465+ {
3466+ struct S { @disable this (); }
3467+ S s = void ;
3468+ static assert (! __traits(compiles, emplace(&s)));
3469+ }
3470+
3471+ unittest
3472+ {
3473+ interface I {}
3474+ class K : I {}
3475+
3476+ K k = void ;
3477+ emplace(&k);
3478+ assert (k is null );
3479+
3480+ I i = void ;
3481+ emplace(&i);
3482+ assert (i is null );
3483+ }
3484+
34283485
34293486/**
34303487Given a pointer $(D chunk) to uninitialized memory (but already typed
@@ -3444,39 +3501,144 @@ T* emplace(T, Args...)(T* chunk, Args args)
34443501 return chunk;
34453502}
34463503
3504+ unittest
3505+ {
3506+ debug (conv) scope (success) writeln(" unittest @" , __FILE__ , " :" , __LINE__ , " succeeded." );
3507+ int a;
3508+ int b = 42 ;
3509+ assert (* emplace! int (&a, b) == 42 );
3510+ }
3511+
3512+ unittest
3513+ {
3514+ interface I {}
3515+ class K : I {}
3516+
3517+ K k = null , k2 = new K;
3518+ assert (k ! is k2);
3519+ emplace! K(&k, k2);
3520+ assert (k is k2);
3521+
3522+ I i = null ;
3523+ assert (i ! is k);
3524+ emplace! I(&i, k);
3525+ assert (i is k);
3526+ }
3527+
34473528// Specialization for struct
3448- T* emplace (T, Args... )(T* chunk, Args args)
3529+ T* emplace (T, Args... )(T* chunk, auto ref Args args)
34493530 if (is (T == struct ))
34503531{
3451- auto result = cast (typeof (return )) chunk;
3452-
34533532 void initialize ()
34543533 {
3455- static T i;
3456- memcpy(chunk, &i, T.sizeof);
3534+ if (auto p = typeid (T).init().ptr)
3535+ memcpy(chunk, p, T.sizeof);
3536+ else
3537+ memset(chunk, 0 , T.sizeof);
34573538 }
34583539
3459- static if (is (typeof (result .__ctor(args))))
3540+ static if (is (typeof (chunk .__ctor(args))))
34603541 {
34613542 // T defines a genuine constructor accepting args
34623543 // Go the classic route: write .init first, then call ctor
34633544 initialize();
3464- result .__ctor(args);
3545+ chunk .__ctor(args);
34653546 }
34663547 else static if (is (typeof (T(args))))
34673548 {
34683549 // Struct without constructor that has one matching field for
34693550 // each argument
3470- * result = T(args);
3551+ * chunk = T(args);
34713552 }
34723553 else // static if (Args.length == 1 && is(Args[0] : T))
34733554 {
34743555 static assert (Args.length == 1 );
34753556 // static assert(0, T.stringof ~ " " ~ Args.stringof);
34763557 // initialize();
3477- * result = args[0 ];
3558+ * chunk = args[0 ];
34783559 }
3479- return result;
3560+ return chunk;
3561+ }
3562+
3563+ // Test constructor branch
3564+
3565+ unittest
3566+ {
3567+ debug (conv) scope (success) writeln(" unittest @" , __FILE__ , " :" , __LINE__ , " succeeded." );
3568+ struct S
3569+ {
3570+ double x = 5 , y = 6 ;
3571+ this (int a, int b)
3572+ {
3573+ assert (x == 5 && y == 6 );
3574+ x = a;
3575+ y = b;
3576+ }
3577+ }
3578+
3579+ auto s1 = new void [S.sizeof];
3580+ auto s2 = S(42 , 43 );
3581+ assert (* emplace! S(cast (S* ) s1.ptr, s2) == s2);
3582+ assert (* emplace! S(cast (S* ) s1, 44 , 45 ) == S(44 , 45 ));
3583+ }
3584+
3585+ unittest
3586+ {
3587+ __conv_EmplaceTest k = void ;
3588+ emplace(&k, 5 );
3589+ assert (k.i == 5 );
3590+ }
3591+
3592+ unittest
3593+ {
3594+ int var = 6 ;
3595+ __conv_EmplaceTest k = void ;
3596+ emplace(&k, 5 , var);
3597+ assert (k.i == 5 );
3598+ assert (var == 7 );
3599+ }
3600+
3601+ // Test matching fields branch
3602+
3603+ unittest
3604+ {
3605+ struct S { uint n; }
3606+ S s;
3607+ emplace! S(&s, 2U );
3608+ assert (s.n == 2 );
3609+ }
3610+
3611+ unittest
3612+ {
3613+ struct S { int a, b; this (int ){} }
3614+ S s;
3615+ static assert (! __traits(compiles, emplace! S(&s, 2 , 3 )));
3616+ }
3617+
3618+ unittest
3619+ {
3620+ struct S { int a, b = 7 ; }
3621+ S s1 = void , s2 = void ;
3622+
3623+ emplace! S(&s1, 2 );
3624+ assert (s1.a == 2 && s1.b == 7 );
3625+
3626+ emplace! S(&s2, 2 , 3 );
3627+ assert (s2.a == 2 && s2.b == 3 );
3628+ }
3629+
3630+ // Test assignment branch
3631+
3632+ // FIXME: no tests
3633+
3634+ private void testEmplaceChunk (void [] chunk, size_t typeSize, size_t typeAlignment, string typeName)
3635+ {
3636+ enforceEx! ConvException(chunk.length >= typeSize,
3637+ xformat(" emplace: Chunk size too small: %s < %s size = %s" ,
3638+ chunk.length, typeName, typeSize));
3639+ enforceEx! ConvException((cast (size_t ) chunk.ptr) % typeAlignment == 0 ,
3640+ xformat(" emplace: Misaligned memory block (0x%X): it must be %s-byte aligned for type %s" ,
3641+ chunk.ptr, typeAlignment, typeName));
34803642}
34813643
34823644/**
@@ -3492,14 +3654,11 @@ $(D T) is $(D @safe).
34923654
34933655Returns: A pointer to the newly constructed object.
34943656 */
3495- T emplace (T, Args... )(void [] chunk, Args args) if (is (T == class ))
3657+ T emplace (T, Args... )(void [] chunk, auto ref Args args) if (is (T == class ))
34963658{
34973659 enum classSize = __traits(classInstanceSize, T);
3498- enforce(chunk.length >= classSize,
3499- new ConvException (" emplace: chunk size too small" ));
3500- auto a = cast (size_t ) chunk.ptr;
3501- enforce(a % T.alignof == 0 , text(a, " vs. " , T.alignof));
3502- auto result = cast (typeof (return )) chunk.ptr;
3660+ testEmplaceChunk(chunk, classSize, classInstanceAlignment! T, T.stringof);
3661+ auto result = cast (T) chunk.ptr;
35033662
35043663 // Initialize the object in its pre-ctor state
35053664 (cast (byte []) chunk)[0 .. classSize] = typeid (T).init[];
@@ -3520,6 +3679,14 @@ T emplace(T, Args...)(void[] chunk, Args args) if (is(T == class))
35203679 return result;
35213680}
35223681
3682+ unittest
3683+ {
3684+ int var = 6 ;
3685+ auto k = emplace! __conv_EmplaceTestClass(new void [__traits(classInstanceSize, __conv_EmplaceTestClass)], 5 , var);
3686+ assert (k.i == 5 );
3687+ assert (var == 7 );
3688+ }
3689+
35233690/**
35243691Given a raw memory area $(D chunk), constructs an object of non-$(D
35253692class) type $(D T) at that address. The constructor is passed the
@@ -3532,15 +3699,11 @@ $(D T) is $(D @safe).
35323699
35333700Returns: A pointer to the newly constructed object.
35343701 */
3535- T* emplace (T, Args... )(void [] chunk, Args args)
3702+ T* emplace (T, Args... )(void [] chunk, auto ref Args args)
35363703 if (! is (T == class ))
35373704{
3538- enforce(chunk.length >= T.sizeof,
3539- new ConvException (" emplace: chunk size too small" ));
3540- auto a = cast (size_t ) chunk.ptr;
3541- enforce(a % T.alignof == 0 , text(a, " vs. " , T.alignof));
3542- auto result = cast (typeof (return )) chunk.ptr;
3543- return emplace (result, args);
3705+ testEmplaceChunk(chunk, T.sizeof, T.alignof, T.stringof);
3706+ return emplace (cast (T* ) chunk.ptr, args);
35443707}
35453708
35463709unittest
@@ -3559,26 +3722,10 @@ unittest
35593722
35603723unittest
35613724{
3562- debug (conv) scope (success) writeln(" unittest @" , __FILE__ , " :" , __LINE__ , " succeeded." );
3563- int a;
3564- int b = 42 ;
3565- assert (* emplace! int (&a, b) == 42 );
3566-
3567- struct S
3568- {
3569- double x = 5 , y = 6 ;
3570- this (int a, int b)
3571- {
3572- assert (x == 5 && y == 6 );
3573- x = a;
3574- y = b;
3575- }
3576- }
3577-
3578- auto s1 = new void [S.sizeof];
3579- auto s2 = S(42 , 43 );
3580- assert (* emplace! S(cast (S* ) s1.ptr, s2) == s2);
3581- assert (* emplace! S(cast (S* ) s1, 44 , 45 ) == S(44 , 45 ));
3725+ int var = 6 ;
3726+ auto k = emplace! __conv_EmplaceTest(new void [__conv_EmplaceTest.sizeof], 5 , var);
3727+ assert (k.i == 5 );
3728+ assert (var == 7 );
35823729}
35833730
35843731unittest
@@ -3617,38 +3764,6 @@ unittest
36173764 assert (equal(map! (to! int )([" 42" , " 34" , " 345" ]), [42 , 34 , 345 ]));
36183765}
36193766
3620- unittest
3621- {
3622- struct Foo
3623- {
3624- uint num;
3625- }
3626-
3627- Foo foo;
3628- emplace! Foo (&foo, 2U );
3629- assert (foo.num == 2 );
3630- }
3631-
3632- unittest
3633- {
3634- interface I {}
3635- class K : I {}
3636-
3637- K k = void ;
3638- emplace! K(&k);
3639- assert (k is null );
3640- K k2 = new K;
3641- assert (k2 ! is null );
3642- emplace! K(&k, k2);
3643- assert (k is k2);
3644-
3645- I i = void ;
3646- emplace! I(&i);
3647- assert (i is null );
3648- emplace! I(&i, k);
3649- assert (i is k);
3650- }
3651-
36523767// Undocumented for the time being
36533768void toTextRange (T, W)(T value, W writer)
36543769 if (isIntegral! T && isOutputRange! (W, char ))
0 commit comments