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