Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit abcbbd0

Browse files
author
Jakob Ovrum
committed
Make .destroy() work with attribute inference
Also adds postblitRecurse() to enable attribute inference for explicit copying
1 parent 268a940 commit abcbbd0

File tree

2 files changed

+321
-17
lines changed

2 files changed

+321
-17
lines changed

src/object.di

Lines changed: 114 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,111 @@ inout(V) get(K, V)(inout(V[K])* aa, K key, lazy inout(V) defaultValue)
595595
return (*aa).get(key, defaultValue);
596596
}
597597

598+
private template object_anySatisfy(alias F, T...)
599+
{
600+
static if (T.length == 0)
601+
{
602+
enum object_anySatisfy = false;
603+
}
604+
else static if (T.length == 1)
605+
{
606+
enum object_anySatisfy = F!(T[0]);
607+
}
608+
else
609+
{
610+
enum object_anySatisfy =
611+
object_anySatisfy!(F, T[ 0 .. $/2]) ||
612+
object_anySatisfy!(F, T[$/2 .. $ ]);
613+
}
614+
}
615+
616+
// Somehow fails for non-static nested structs without support for aliases
617+
private template object_hasElaborateDestructor(T...)
618+
{
619+
static if (is(T[0]))
620+
alias S = T[0];
621+
else
622+
alias S = typeof(T[0]);
623+
624+
static if (is(S : E[n], E, size_t n) && S.length)
625+
{
626+
enum bool object_hasElaborateDestructor = object_hasElaborateDestructor!E;
627+
}
628+
else static if (is(S == struct))
629+
{
630+
enum object_hasElaborateDestructor = __traits(hasMember, S, "__dtor")
631+
|| object_anySatisfy!(.object_hasElaborateDestructor, S.tupleof);
632+
}
633+
else
634+
enum bool object_hasElaborateDestructor = false;
635+
}
636+
637+
private void destructRecurse(S)(ref S s)
638+
if (is(S == struct))
639+
{
640+
static if (__traits(hasMember, S, "__dtor"))
641+
s.__dtor();
642+
643+
foreach_reverse (i, ref field; s.tupleof)
644+
{
645+
static if (object_hasElaborateDestructor!(typeof(field)))
646+
destructRecurse(field);
647+
}
648+
}
649+
650+
private void destructRecurse(E, size_t n)(ref E[n] arr)
651+
{
652+
static if (object_hasElaborateDestructor!E)
653+
{
654+
foreach_reverse (ref elem; arr)
655+
destructRecurse(elem);
656+
}
657+
}
658+
659+
// Somehow fails for non-static nested structs without support for aliases
660+
private template object_hasElaborateCopyConstructor(T...)
661+
{
662+
static if (is(T[0]))
663+
alias S = T[0];
664+
else
665+
alias S = typeof(T[0]);
666+
667+
static if (is(S : E[n], E, size_t n) && S.length)
668+
{
669+
enum bool object_hasElaborateCopyConstructor = object_hasElaborateCopyConstructor!E;
670+
}
671+
else static if (is(S == struct))
672+
{
673+
enum object_hasElaborateCopyConstructor = __traits(hasMember, S, "__postblit")
674+
|| object_anySatisfy!(.object_hasElaborateCopyConstructor, S.tupleof);
675+
}
676+
else
677+
enum bool object_hasElaborateCopyConstructor = false;
678+
}
679+
680+
// Public and explicitly undocumented
681+
void postblitRecurse(S)(ref S s)
682+
if (is(S == struct))
683+
{
684+
foreach (ref field; s.tupleof)
685+
{
686+
static if (object_hasElaborateCopyConstructor!(typeof(field)))
687+
postblitRecurse(field);
688+
}
689+
static if (__traits(hasMember, S, "__postblit"))
690+
s.__postblit();
691+
}
692+
693+
// Ditto
694+
void postblitRecurse(E, size_t n)(ref E[n] arr)
695+
{
696+
static if (object_hasElaborateCopyConstructor!E)
697+
{
698+
foreach (ref elem; arr)
699+
postblitRecurse(elem);
700+
}
701+
}
702+
598703
// Explicitly undocumented. It will be removed in March 2015.
599704
deprecated("Please use destroy instead.")
600705
alias clear = destroy;
@@ -611,13 +716,15 @@ void destroy(T)(T obj) if (is(T == interface))
611716

612717
void destroy(T)(ref T obj) if (is(T == struct))
613718
{
614-
typeid(T).destroy(&obj);
615-
auto buf = (cast(ubyte*) &obj)[0 .. T.sizeof];
616-
auto init = cast(ubyte[])typeid(T).init();
617-
if(init.ptr is null) // null ptr means initialize to 0s
618-
buf[] = 0;
619-
else
620-
buf[] = init[];
719+
destructRecurse(obj);
720+
() @trusted {
721+
auto buf = (cast(ubyte*) &obj)[0 .. T.sizeof];
722+
auto init = cast(ubyte[])typeid(T).init();
723+
if (init.ptr is null) // null ptr means initialize to 0s
724+
buf[] = 0;
725+
else
726+
buf[] = init[];
727+
} ();
621728
}
622729

623730
void destroy(T : U[n], U, size_t n)(ref T obj) if (!is(T == struct))

src/object_.d

Lines changed: 207 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2439,6 +2439,201 @@ unittest
24392439
}
24402440
}
24412441

2442+
private template object_anySatisfy(alias F, T...)
2443+
{
2444+
static if ((T.length == 0)
2445+
{
2446+
enum object_anySatisfy = false;
2447+
}
2448+
else static if (T.length == 1)
2449+
{
2450+
enum object_anySatisfy = F!(T[0]);
2451+
}
2452+
else
2453+
{
2454+
enum object_anySatisfy =
2455+
object_anySatisfy!(F, T[ 0 .. $/2]) ||
2456+
object_anySatisfy!(F, T[$/2 .. $ ]);
2457+
}
2458+
}
2459+
2460+
// Somehow fails for non-static nested structs without support for aliases
2461+
private template object_hasElaborateDestructor(T...)
2462+
{
2463+
static if (is(T[0]))
2464+
alias S = T[0];
2465+
else
2466+
alias S = typeof(T[0]);
2467+
2468+
static if (is(S : E[n], E, size_t n) && S.length)
2469+
{
2470+
enum bool object_hasElaborateDestructor = object_hasElaborateDestructor!E;
2471+
}
2472+
else static if (is(S == struct))
2473+
{
2474+
enum object_hasElaborateDestructor = __traits(hasMember, S, "__dtor")
2475+
|| object_anySatisfy!(.object_hasElaborateDestructor, S.tupleof);
2476+
}
2477+
else
2478+
enum bool object_hasElaborateDestructor = false;
2479+
}
2480+
2481+
private void destructRecurse(S)(ref S s)
2482+
if (is(S == struct))
2483+
{
2484+
static if (__traits(hasMember, S, "__dtor"))
2485+
s.__dtor();
2486+
2487+
foreach_reverse (i, ref field; s.tupleof)
2488+
{
2489+
static if (object_hasElaborateDestructor!(typeof(field)))
2490+
destructRecurse(field);
2491+
}
2492+
}
2493+
2494+
private void destructRecurse(E, size_t n)(ref E[n] arr)
2495+
{
2496+
static if (object_hasElaborateDestructor!E)
2497+
{
2498+
foreach_reverse (ref elem; arr)
2499+
destructRecurse(elem);
2500+
}
2501+
}
2502+
2503+
// Somehow fails for non-static nested structs without support for aliases
2504+
private template object_hasElaborateCopyConstructor(T...)
2505+
{
2506+
static if (is(T[0]))
2507+
alias S = T[0];
2508+
else
2509+
alias S = typeof(T[0]);
2510+
2511+
static if (is(S : E[n], E, size_t n) && S.length)
2512+
{
2513+
enum bool object_hasElaborateCopyConstructor = object_hasElaborateCopyConstructor!E;
2514+
}
2515+
else static if (is(S == struct))
2516+
{
2517+
enum object_hasElaborateCopyConstructor = __traits(hasMember, S, "__postblit")
2518+
|| object_anySatisfy!(.object_hasElaborateCopyConstructor, S.tupleof);
2519+
}
2520+
else
2521+
enum bool object_hasElaborateCopyConstructor = false;
2522+
}
2523+
2524+
// Public and explicitly undocumented
2525+
void postblitRecurse(S)(ref S s)
2526+
if (is(S == struct))
2527+
{
2528+
foreach (ref field; s.tupleof)
2529+
{
2530+
static if (object_hasElaborateCopyConstructor!(typeof(field)))
2531+
postblitRecurse(field);
2532+
}
2533+
static if (__traits(hasMember, S, "__postblit"))
2534+
s.__postblit();
2535+
}
2536+
2537+
// Ditto
2538+
void postblitRecurse(E, size_t n)(ref E[n] arr)
2539+
{
2540+
static if (object_hasElaborateCopyConstructor!E)
2541+
{
2542+
foreach (ref elem; arr)
2543+
postblitRecurse(elem);
2544+
}
2545+
}
2546+
2547+
@safe nothrow pure unittest
2548+
{
2549+
string[] order;
2550+
2551+
struct InnerTop
2552+
{
2553+
~this() @safe nothrow pure
2554+
{
2555+
order ~= "destroy inner top";
2556+
}
2557+
2558+
this(this) @safe nothrow pure
2559+
{
2560+
order ~= "copy inner top";
2561+
}
2562+
}
2563+
2564+
struct InnerMiddle {}
2565+
2566+
version(none)
2567+
struct InnerElement
2568+
{
2569+
static char counter = '1';
2570+
2571+
~this() @safe nothrow pure
2572+
{
2573+
order ~= "destroy inner element #" ~ counter++;
2574+
}
2575+
2576+
this(this) @safe nothrow pure
2577+
{
2578+
order ~= "copy inner element #" ~ counter++;
2579+
}
2580+
}
2581+
2582+
struct InnerBottom
2583+
{
2584+
~this() @safe nothrow pure
2585+
{
2586+
order ~= "destroy inner bottom";
2587+
}
2588+
2589+
this(this) @safe nothrow pure
2590+
{
2591+
order ~= "copy inner bottom";
2592+
}
2593+
}
2594+
2595+
struct S
2596+
{
2597+
char[] s;
2598+
InnerTop top;
2599+
InnerMiddle middle;
2600+
//InnerElement[3] array;
2601+
int a;
2602+
InnerBottom bottom;
2603+
~this() @safe nothrow pure { order ~= "destroy outer"; }
2604+
this(this) @safe nothrow pure { order ~= "copy outer"; }
2605+
}
2606+
2607+
string[] destructRecurseOrder;
2608+
{
2609+
S s;
2610+
destructRecurse(s);
2611+
destructRecurseOrder = order;
2612+
order = null;
2613+
}
2614+
2615+
assert(order.length);
2616+
assert(destructRecurseOrder == order);
2617+
order = null;
2618+
2619+
S s;
2620+
postblitRecurse(s);
2621+
assert(order.length);
2622+
auto postblitRecurseOrder = order;
2623+
order = null;
2624+
S s2 = s;
2625+
assert(order.length);
2626+
assert(postblitRecurseOrder == order);
2627+
}
2628+
2629+
nothrow @safe @nogc unittest
2630+
{
2631+
static int i = 0;
2632+
static struct S { ~this() nothrow @safe @nogc { i = 42; } }
2633+
S s;
2634+
destructRecurse(s);
2635+
assert(i == 42);
2636+
}
24422637
// Explicitly undocumented. It will be removed in March 2015.
24432638
deprecated("Please use destroy instead of clear.")
24442639
alias destroy clear;
@@ -2516,16 +2711,18 @@ version(unittest) unittest
25162711

25172712
void destroy(T)(ref T obj) if (is(T == struct))
25182713
{
2519-
typeid(T).destroy( &obj );
2520-
auto buf = (cast(ubyte*) &obj)[0 .. T.sizeof];
2521-
auto init = cast(ubyte[])typeid(T).init();
2522-
if(init.ptr is null) // null ptr means initialize to 0s
2523-
buf[] = 0;
2524-
else
2525-
buf[] = init[];
2714+
destructRecurse(obj);
2715+
() @trusted {
2716+
auto buf = (cast(ubyte*) &obj)[0 .. T.sizeof];
2717+
auto init = cast(ubyte[])typeid(T).init();
2718+
if (init.ptr is null) // null ptr means initialize to 0s
2719+
buf[] = 0;
2720+
else
2721+
buf[] = init[];
2722+
} ();
25262723
}
25272724

2528-
version(unittest) unittest
2725+
version(unittest) nothrow @safe @nogc unittest
25292726
{
25302727
{
25312728
struct A { string s = "A"; }
@@ -2539,7 +2736,7 @@ version(unittest) unittest
25392736
struct C
25402737
{
25412738
string s = "C";
2542-
~this()
2739+
~this() nothrow @safe @nogc
25432740
{
25442741
destroyed ++;
25452742
}
@@ -2549,7 +2746,7 @@ version(unittest) unittest
25492746
{
25502747
C c;
25512748
string s = "B";
2552-
~this()
2749+
~this() nothrow @safe @nogc
25532750
{
25542751
destroyed ++;
25552752
}

0 commit comments

Comments
 (0)