1 module cppnew;
2 
3 auto CPPNew(T, A...) (auto ref A args) {
4     import std.experimental.allocator : make;
5     return CPPAllocator.instance.make!T(args);
6 }
7 
8 T[] CPPNewArray(T) (size_t length) {
9     import std.experimental.allocator : makeArray;
10     return CPPAllocator.instance.makeArray!T(length);
11 }
12 
13 T[] CPPNewArray(T) (size_t length, T init) {
14     import std.experimental.allocator : makeArray;
15     return CPPAllocator.instance.makeArray!T(length, init);
16 }
17 
18 Unqual!(ElementEncodingType!R)[] CPPNewArray(R)(R range) if (isInputRange!R && !isInfinite!R) {
19     import std.experimental.allocator : makeArray;
20     return CPPAllocator.instance.makeArray!T(range);
21 }
22 
23 T[] CPPNewArray(T, R)(R range) if (isInputRange!R && !isInfinite!R) {
24     import std.experimental.allocator : makeArray;
25     return CPPAllocator.instance.makeArray!T(range);
26 }
27 
28 auto CPPNewMultidimensionalArray(T, size_t N)(size_t[N] lengths...) {
29     import std.experimental.allocator : makeMultidimensionalArray;
30     return CPPAllocator.instance.makeMultidimensionalArray!T(lengths);
31 }
32 
33 void CPPDelete(T) (auto ref T* p) {
34     import std.experimental.allocator : dispose;
35     CPPAllocator.instance.dispose(p);
36 }
37 
38 void CPPDelete(T) (auto ref T p) if (is(T == class) || is(T == interface)) {
39     import std.experimental.allocator : dispose;
40     
41     if (!p) {
42         return;
43     }
44     
45     destroy(p);
46     CPPAllocator.instance.dispose(cast(void*) p); //Workaround for prevent error "Runtime type information is not supported for extern(C++) classes"
47 }
48 
49 void CPPDelete(T) (auto ref T[] array) {
50     import std.experimental.allocator : dispose;
51     CPPAllocator.instance.dispose(array);
52 }
53 
54 void CPPDeleteMultidimensionalArray(T)(auto ref T[] array) {
55     import std.experimental.allocator : disposeMultidimensionalArray;
56     CPPAllocator.instance.disposeMultidimensionalArray(array);
57 }
58 
59 struct CPPAllocator {
60     import std.experimental.allocator.common : platformAlignment;
61     import core.stdcpp.xutility : __cpp_aligned_new;
62 
63     /**
64      * Returns the global instance of this allocator type.
65      * CppNew is thread-safe, all methods are shared.
66      */
67     static shared CPPAllocator instance;
68 
69     /**
70      * The alignment is a static constant equal to `platformAlignment`, which
71      * ensures proper alignment for any D data type.
72      */    
73     enum uint alignment = platformAlignment;
74 
75     /**
76      * Allocates the size expressed in bytes.
77      *
78      * Params:
79      *      bytes = Number of bytes to allocate.
80      *
81      * Returns:
82      *      An array with allocated memory or null if out of memory. Returns null if called with size 0.
83      */
84     @trusted @nogc nothrow void[] allocate(size_t bytes) shared {
85         import core.stdcpp.new_ : __cpp_new_nothrow;
86 
87         if (bytes == 0) {
88             return null;
89         }
90 
91         auto p = __cpp_new_nothrow(bytes);
92         return p ? p[0 .. bytes] : null;
93     }
94 
95     /**
96      * Allocates the size expressed in bytes aligned by alignment.
97      *
98      * Params:
99      *      bytes = Number of bytes to allocate.
100      *      alignment = the minimal alignment of the allocated memory.
101      *
102      * Returns:
103      *      An array with aligned allocated memory or null if out of memory. Returns null if called with size 0.
104      */
105     static if (__cpp_aligned_new) {
106         @trusted @nogc nothrow void[] alignedAllocate(size_t bytes, uint alignment) shared {
107             import core.stdcpp.new_ : __cpp_new_aligned_nothrow;
108             
109             if (bytes == 0) {
110                 return null;
111             }
112             
113             auto p = __cpp_new_aligned_nothrow(bytes, alignment);
114             return p ? p[0 .. bytes] : null;
115         }
116     }
117     
118 
119     /**
120      * Deallocate the specified memory block
121      *
122      * Params:
123      *      b = The memory block to be deallocated.
124      *
125      * Returns:
126      *   false if the array is null, otherwise true. 
127      */
128     @system @nogc nothrow bool deallocate(void[] b) shared {
129         import core.stdcpp.new_ : __cpp_delete_nothrow;
130 
131         if (b is null) {
132             return true;
133         }
134 
135         __cpp_delete_nothrow(b.ptr);
136         return true;
137     }
138 }