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 	version (checkErrno) pragma(mangle, "getErrno") int fakePureGetErrno();
16 	version (checkErrno) pragma(mangle, "setErrno") int fakePureSetErrno(int);
17 	pragma(mangle, "malloc") void* fakePureMalloc(size_t);
18 	pragma(mangle, "calloc") void* fakePureCalloc(size_t nmemb, size_t size);
19 	pragma(mangle, "realloc") void* fakePureRealloc(void* ptr, size_t size);
20 	pragma(mangle, "free") void fakePureFree(void* ptr);
21 }
22 
23 // qualified C memory allocations
24 extern(C) pure nothrow @nogc {
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(const scope void* p, size_t sz, const TypeInfo ti = null);
35 	void gc_removeRange(const scope 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 	version (checkErrno) const errno = fakePureGetErrno();
51 	void* ret = fakePureMalloc(size);
52 	version (checkErrno) if (!ret || errno != 0) {
53 		cast(void)fakePureSetErrno(errno);
54 	}
55 	return ret;
56 }
57 /// ditto
58 private void* pureCalloc(size_t nmemb, size_t size) @trusted pure @nogc nothrow {
59 	version (checkErrno) const errno = fakePureGetErrno();
60 	void* ret = fakePureCalloc(nmemb, size);
61 	version (checkErrno) if (!ret || errno != 0) {
62 		cast(void)fakePureSetErrno(errno);
63 	}
64 	return ret;
65 }
66 /// ditto
67 private void* pureRealloc(void* ptr, size_t size) @system pure @nogc nothrow {
68 	version (checkErrno) const errno = fakePureGetErrno();
69 	void* ret = fakePureRealloc(ptr, size);
70 	version (checkErrno) if (!ret || errno != 0) {
71 		cast(void)fakePureSetErrno(errno);
72 	}
73 	return ret;
74 }
75 /// ditto
76 void pureFree(void* ptr) @system pure @nogc nothrow {
77 	version (checkErrno) const errno = fakePureGetErrno();
78 	fakePureFree(ptr);
79 	version (checkErrno) cast(void)fakePureSetErrno(errno);
80 }