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     CPPAllocator.instance.dispose(p);
41 }
42 
43 void CPPDelete(T) (auto ref T[] array) {
44     import std.experimental.allocator : dispose;
45     CPPAllocator.instance.dispose(array);
46 }
47 
48 void CPPDeleteMultidimensionalArray(T)(auto ref T[] array) {
49     import std.experimental.allocator : disposeMultidimensionalArray;
50     CPPAllocator.instance.disposeMultidimensionalArray(array);
51 }
52 
53 struct CPPAllocator {
54     import std.experimental.allocator.common : platformAlignment;
55     import core.stdcpp.xutility : __cpp_aligned_new;
56 
57     /**
58      * Returns the global instance of this allocator type.
59      * CppNew is thread-safe, all methods are shared.
60      */
61     static shared CPPAllocator instance;
62 
63     /**
64      * The alignment is a static constant equal to `platformAlignment`, which
65      * ensures proper alignment for any D data type.
66      */    
67     enum uint alignment = platformAlignment;
68 
69     /**
70      * Allocates the size expressed in bytes.
71      *
72      * Params:
73      *      bytes = Number of bytes to allocate.
74      *
75      * Returns:
76      *      An array with allocated memory or null if out of memory. Returns null if called with size 0.
77      */
78     @trusted @nogc nothrow void[] allocate(size_t bytes) shared {
79         import core.stdcpp.new_ : __cpp_new_nothrow;
80 
81         if (bytes == 0) {
82             return null;
83         }
84 
85         auto p = __cpp_new_nothrow(bytes);
86         return p ? p[0 .. bytes] : null;
87     }
88 
89     /**
90      * Allocates the size expressed in bytes aligned by alignment.
91      *
92      * Params:
93      *      bytes = Number of bytes to allocate.
94      *      alignment = the minimal alignment of the allocated memory.
95      *
96      * Returns:
97      *      An array with aligned allocated memory or null if out of memory. Returns null if called with size 0.
98      */
99     static if (__cpp_aligned_new) {
100         @trusted @nogc nothrow void[] alignedAllocate(size_t bytes, uint alignment) shared {
101             import core.stdcpp.new_ : __cpp_new_aligned_nothrow;
102             
103             if (bytes == 0) {
104                 return null;
105             }
106             
107             auto p = __cpp_new_aligned_nothrow(bytes, alignment);
108             return p ? p[0 .. bytes] : null;
109         }
110     }
111     
112 
113     /**
114      * Deallocate the specified memory block
115      *
116      * Params:
117      *      b = The memory block to be deallocated.
118      *
119      * Returns:
120      *   false if the array is null, otherwise true. 
121      */
122     @system @nogc nothrow bool deallocate(void[] b) shared {
123         import core.stdcpp.new_ : __cpp_delete_nothrow;
124 
125         if (b is null) {
126             return true;
127         }
128 
129         __cpp_delete_nothrow(b.ptr);
130         return true;
131     }
132 }