1 /**
2    Custom versions of std.experimental.allocator functions (unfortunately)
3  */
4 module automem.allocator;
5 
6 import automem.utils: destruct;
7 
8 /**
9 
10 Destroys and then deallocates (using $(D alloc)) the object pointed to by a
11 pointer, the class object referred to by a $(D class) or $(D interface)
12 reference, or an entire array. It is assumed the respective entities had been
13 allocated with the same allocator.
14 
15 */
16 void dispose(A, T)(auto ref A alloc, T* p)
17 {
18     import std.traits: hasElaborateDestructor;
19 
20     static if (hasElaborateDestructor!T)
21     {
22         destruct(*p);
23     }
24     alloc.deallocate((cast(void*) p)[0 .. T.sizeof]);
25 }
26 
27 /// Ditto
28 void dispose(A, T)(auto ref A alloc, T p)
29 if (is(T == class) || is(T == interface))
30 {
31 
32     if (!p) return;
33     static if (is(T == interface))
34     {
35         version(Windows)
36         {
37             import core.sys.windows.unknwn : IUnknown;
38             static assert(!is(T: IUnknown), "COM interfaces can't be destroyed in "
39                 ~ __PRETTY_FUNCTION__);
40         }
41         auto ob = cast(Object) p;
42     }
43     else
44         alias ob = p;
45     auto support = (cast(void*) ob)[0 .. typeid(ob).initializer.length];
46 
47     destruct(p);
48 
49     alloc.deallocate(support);
50 }
51 
52 /// Ditto
53 void dispose(A, T)(auto ref A alloc, T[] array)
54 {
55     import std.traits: hasElaborateDestructor;
56 
57     static if (hasElaborateDestructor!(typeof(array[0])))
58     {
59         foreach (ref e; array)
60         {
61             destruct(e);
62         }
63     }
64     alloc.deallocate(array);
65 }
66 
67 @system unittest
68 {
69 
70     import std.experimental.allocator: theAllocator, make, makeArray;
71 
72     static int x;
73     static interface I
74     {
75         void method();
76     }
77     static class A : I
78     {
79         int y;
80         override void method() { x = 21; }
81         ~this() { x = 42; }
82     }
83     static class B : A
84     {
85     }
86     auto a = theAllocator.make!A;
87     a.method();
88     assert(x == 21);
89     theAllocator.dispose(a);
90     assert(x == 42);
91 
92     B b = theAllocator.make!B;
93     b.method();
94     assert(x == 21);
95     theAllocator.dispose(b);
96     assert(x == 42);
97 
98     I i = theAllocator.make!B;
99     i.method();
100     assert(x == 21);
101     theAllocator.dispose(i);
102     assert(x == 42);
103 
104     int[] arr = theAllocator.makeArray!int(43);
105     theAllocator.dispose(arr);
106 }
107 
108 @system unittest //bugzilla 15721
109 {
110     import std.experimental.allocator: make;
111     import std.experimental.allocator.mallocator : Mallocator;
112 
113     interface Foo {}
114     class Bar: Foo {}
115 
116     Bar bar;
117     Foo foo;
118     bar = Mallocator.instance.make!Bar;
119     foo = cast(Foo) bar;
120     Mallocator.instance.dispose(foo);
121 }