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