1 /// Qualified (`@safe pure nothrow @nogc`) C memory management.
2 module nxt.qcmeman;
3 
4 extern(C)
5 {
6     // qualified C memory allocations
7     pure nothrow @nogc:
8 
9     /* See_Also:
10      * https://forum.dlang.org/post/mailman.1130.1521239659.3374.digitalmars-d@puremagic.com
11      * for an explanation of why `pureMalloc` and `pureCalloc` both can
12      * be @trusted. */
13     void* malloc(size_t size) @trusted;
14 
15     void* calloc(size_t nmemb, size_t size) @trusted;
16 
17     void* realloc(void* ptr, size_t size) @system;
18 
19     void* alloca(size_t length) @safe;
20 
21     void free(void* ptr) @system;
22 
23     void gc_addRange(in void* p, size_t sz, const TypeInfo ti = null);
24     void gc_removeRange(in void* p );
25 }
26 
27 /**
28  * Pure variants of C's memory allocation functions `malloc`, `calloc`, and
29  * `realloc` and deallocation function `free`.
30  *
31  * Purity is achieved by saving and restoring the value of `errno`, thus
32  * behaving as if it were never changed.
33  *
34  * See_Also:
35  *     $(LINK2 https://dlang.org/spec/function.html#pure-functions, D's rules for purity),
36  *     which allow for memory allocation under specific circumstances.
37  */
38 private void* pureMalloc(size_t size) @trusted pure @nogc nothrow
39 {
40     debug const errno = fakePureGetErrno();
41     void* ret = fakePureMalloc(size);
42     debug if (!ret || errno != 0)
43     {
44         cast(void)fakePureSetErrno(errno);
45     }
46     return ret;
47 }
48 /// ditto
49 private void* pureCalloc(size_t nmemb, size_t size) @trusted pure @nogc nothrow
50 {
51     debug const errno = fakePureGetErrno();
52     void* ret = fakePureCalloc(nmemb, size);
53     debug if (!ret || errno != 0)
54     {
55         cast(void)fakePureSetErrno(errno);
56     }
57     return ret;
58 }
59 /// ditto
60 private void* pureRealloc(void* ptr, size_t size) @system pure @nogc nothrow
61 {
62     debug const errno = fakePureGetErrno();
63     void* ret = fakePureRealloc(ptr, size);
64     debug if (!ret || errno != 0)
65     {
66         cast(void)fakePureSetErrno(errno);
67     }
68     return ret;
69 }
70 /// ditto
71 void pureFree(void* ptr) @system pure @nogc nothrow
72 {
73     debug const errno = fakePureGetErrno();
74     fakePureFree(ptr);
75     debug cast(void)fakePureSetErrno(errno);
76 }
77 
78 // locally purified for internal use here only
79 extern (C) private pure @system @nogc nothrow
80 {
81     pragma(mangle, "getErrno") int fakePureGetErrno();
82     pragma(mangle, "setErrno") int fakePureSetErrno(int);
83 
84     pragma(mangle, "malloc") void* fakePureMalloc(size_t);
85     pragma(mangle, "calloc") void* fakePureCalloc(size_t nmemb, size_t size);
86     pragma(mangle, "realloc") void* fakePureRealloc(void* ptr, size_t size);
87 
88     pragma(mangle, "free") void fakePureFree(void* ptr);
89 }