1 module nxt.pure_mallocator;
2 
3 // TOODO Use std.experimental.allocator.building_blocks.mallocator instead of this module
4 
5 import std.experimental.allocator.common;
6 
7 /**
8  * The C heap allocator purified.
9  *
10  * TODO Remove when https://github.com/dlang/phobos/pull/6411 has been merged
11  * that adds `calloc`.
12  */
13 struct PureMallocator
14 {
15     const shared pure nothrow @nogc:
16 
17     /**
18      * The alignment is a static constant equal to $(D platformAlignment), which
19      * ensures proper alignment for any D data type.
20     */
21     enum uint alignment = platformAlignment;
22 
23     /**
24      * Standard allocator methods per the semantics defined above. The $(D
25      * deallocate) and $(D reallocate) methods are $(D @system) because they may
26      * move memory around, leaving dangling pointers in user code. Somewhat
27      * paradoxically, $(D malloc) is $(D @safe) but that's only useful to safe
28      * programs that can afford to leak memory allocated.
29      */
30     void[] allocate(size_t bytes) @trusted
31     {
32         version(LDC) pragma(inline, true);
33         if (!bytes) { return null; }
34         void* p = fakePureMalloc(bytes);
35         return p ? p[0 .. bytes] : null;
36     }
37 
38     void[] allocateZeroed(size_t bytes) @trusted
39     {
40         version(LDC) pragma(inline, true);
41         if (!bytes) { return null; }
42         void* p = fakePureCalloc(bytes, 1);
43         return p ? p[0 .. bytes] : null;
44     }
45 
46     /// ditto
47     bool deallocate(void[] b) @system
48     {
49         pragma(inline, true);
50         fakePureFree(b.ptr);        // `free` doesn't need `b.length`
51         // `true` indicates support,
52         // See_Also: https://dlang.org/phobos/std_experimental_allocator.html#.IAllocator.deallocate
53         return true;
54     }
55 
56     /// ditto
57     bool reallocate(ref void[] b, size_t s) @system
58     {
59         if (!s)
60         {
61             // fuzzy area in the C standard, see http://goo.gl/ZpWeSE
62             // so just deallocate and nullify the pointer
63             deallocate(b);
64             b = null;
65             return true;
66         }
67         ubyte* p = cast(ubyte*)fakePureRealloc(b.ptr, s);
68         if (!p) { return false; }
69         b = p[0 .. s];
70         return true;
71     }
72 
73     /// Deallocate using a pointer only like what `free` does.
74     bool deallocatePtr(void* b) @system
75     {
76         pragma(inline, true);
77         fakePureFree(b);            // `free` doesn't need `b.length`
78         return true; // `true` indicates support, https://dlang.org/phobos/std_experimental_allocator.html#.IAllocator.deallocate
79     }
80 
81     /**
82      * Returns the global instance of this allocator type. The C heap allocator is
83      * thread-safe, therefore all of its methods and `it` itself are
84      * $(D x).
85      */
86     static shared PureMallocator instance;
87 }
88 
89 ///
90 @trusted pure nothrow @nogc unittest
91 {
92     auto buf = PureMallocator.instance.allocate(16);
93     assert(&buf[0]);
94     assert(buf.length);
95 
96     assert(PureMallocator.instance.deallocate(buf));
97 
98     import std.experimental.allocator : makeArray;
99     PureMallocator.instance.makeArray!int(64, 42);
100 }
101 
102 extern (C) private pure @system @nogc nothrow
103 {
104     pragma(mangle, "malloc") void* fakePureMalloc(size_t);
105     pragma(mangle, "calloc") void* fakePureCalloc(size_t nmemb, size_t size);
106     pragma(mangle, "realloc") void* fakePureRealloc(void* ptr, size_t size);
107     pragma(mangle, "free") void fakePureFree(void* ptr);
108 }