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 ///
68 @system unittest
69 {
70 
71     import std.experimental.allocator: theAllocator, make, makeArray;
72 
73     static int x;
74     static interface I
75     {
76         void method();
77     }
78     static class A : I
79     {
80         int y;
81         override void method() { x = 21; }
82         ~this() { x = 42; }
83     }
84     static class B : A
85     {
86     }
87     auto a = theAllocator.make!A;
88     a.method();
89     assert(x == 21);
90     theAllocator.dispose(a);
91     assert(x == 42);
92 
93     B b = theAllocator.make!B;
94     b.method();
95     assert(x == 21);
96     theAllocator.dispose(b);
97     assert(x == 42);
98 
99     I i = theAllocator.make!B;
100     i.method();
101     assert(x == 21);
102     theAllocator.dispose(i);
103     assert(x == 42);
104 
105     int[] arr = theAllocator.makeArray!int(43);
106     theAllocator.dispose(arr);
107 }
108 
109 ///
110 @system unittest //bugzilla 15721
111 {
112     import std.experimental.allocator: make;
113     import std.experimental.allocator.mallocator : Mallocator;
114 
115     interface Foo {}
116     class Bar: Foo {}
117 
118     Bar bar;
119     Foo foo;
120     bar = Mallocator.instance.make!Bar;
121     foo = cast(Foo) bar;
122     Mallocator.instance.dispose(foo);
123 }