1 module xbuffer.memory;
2 
3 import core.exception : onOutOfMemoryError;
4 import core.memory : pureMalloc, pureCalloc, pureRealloc, pureFree;
5 
6 import std.conv : emplace;
7 
8 /**
9  * Uses `pureMalloc` to allocate a block of memory of the given
10  * size and throws an `outOfMemoryError` if the memory cannot be
11  * allocated.
12  */
13 void[] xmalloc(size_t size) pure nothrow @trusted @nogc {
14 	void* ptr = pureMalloc(size);
15 	if(ptr is null) onOutOfMemoryError();
16 	return ptr[0..size];
17 }
18 
19 ///
20 pure nothrow @trusted @nogc unittest {
21 
22 	ubyte[] bytes = cast(ubyte[])xmalloc(12);
23 	assert(bytes.length == 12);
24 
25 	int[] ints = cast(int[])xmalloc(12);
26 	assert(ints.length == 3);
27 
28 }
29 
30 /**
31  * Uses `pureCalloc` to allocate a block of memory of the given
32  * size and trows an `outOfMemoryError` if the memory cannot be
33  * allocated.
34  */
35 void[] xcalloc(size_t nitems, size_t size) pure nothrow @trusted @nogc {
36 	void* ptr = pureCalloc(nitems, size);
37 	if(ptr is null) onOutOfMemoryError();
38 	return ptr[0..nitems*size];
39 }
40 
41 ///
42 pure nothrow @trusted @nogc unittest {
43 
44 	ubyte[] bytes = cast(ubyte[])xcalloc(12, 1);
45 	assert(bytes.length == 12);
46 
47 	int[] ints = cast(int[])xcalloc(3, 4);
48 	assert(ints.length == 3);
49 
50 }
51 
52 /**
53  * Uses `pureRealloc` to realloc a block of memory and throws an
54  * `outOfMemoryError` if the memory cannot be allocated.
55  */
56 void[] xrealloc(void* ptr, size_t size) pure nothrow @trusted @nogc {
57 	void* new_ptr = pureRealloc(ptr, size);
58 	if(new_ptr is null) onOutOfMemoryError();
59 	return new_ptr[0..size];
60 }
61 
62 ///
63 pure nothrow @trusted @nogc unittest {
64 
65 	void[] buffer = xmalloc(12);
66 	assert(buffer.length == 12);
67 
68 	// allocate
69 	buffer = xrealloc(buffer.ptr, 100);
70 	assert(buffer.length == 100);
71 
72 	// deallocate
73 	buffer = xrealloc(buffer, 10);
74 	assert(buffer.length == 10);
75 
76 }
77 
78 /**
79  * Reallocates the given array using a new size.
80  */
81 void[] xrealloc(T)(ref T[] buffer, size_t size) pure nothrow @trusted @nogc {
82 	return (buffer = cast(T[])xrealloc(buffer.ptr, size * T.sizeof));
83 }
84 
85 ///
86 pure nothrow @trusted @nogc unittest {
87 
88 	ubyte[] bytes = cast(ubyte[])xmalloc(12);
89 	xrealloc(bytes, 44); // same as `xrealloc(bytes.ptr, 44)`
90 	assert(bytes.length == 44);
91 
92 	int[] ints = cast(int[])xcalloc(3, 4);
93 	assert(ints.length == 3);
94 	xrealloc(ints, 4); // same as `xrealloc(ints.ptr, 4 * 4)`
95 	assert(ints.length == 4);
96 
97 }
98 
99 /**
100  * Uses `pureFree` to release allocated memory.
101  */
102 void xfree(void* ptr) pure nothrow @system @nogc {
103 	pureFree(ptr);
104 }
105 
106 /// ditto
107 void xfree(T)(ref T[] array) pure nothrow @nogc {
108 	xfree(array.ptr);
109 }
110 
111 /**
112  * Allocates memory for a class and emplaces it.
113  */
114 T xalloc(T, E...)(auto ref E args) pure nothrow @system @nogc if(is(T == class)) {
115 	return emplace!(T, E)(xmalloc(__traits(classInstanceSize, T)), args);
116 }
117 
118 ///
119 pure nothrow @trusted @nogc unittest {
120 
121 	class Test {
122 
123 		int a, b, c;
124 
125 	}
126 
127 	Test test;
128 	assert(test is null);
129 
130 	test = xalloc!Test();
131 	assert(test !is null);
132 
133 }
134 
135 /**
136  * Deallocates a class allocated with xalloc and calls its custom
137  * destructor (`__xdtor` pure, nothrow and @nogc method).
138  */
139 void xfree(T)(T obj) pure nothrow @system @nogc if(is(T == class)) {
140 	static if(__traits(hasMember, T, "__xdtor")) obj.__xdtor();
141 	else obj.__dtor();
142 	xfree(cast(void*)obj);
143 }