1 module decs.memory;
2 
3 import core.stdc.stdio;
4 import core.stdc.stdlib;
5 import core.stdc..string;
6 import core.lifetime;
7 
8 import decs.dbg;
9 
10 __gshared MallocAllocator MALLOCATOR = MallocAllocator();
11 
12 // TODO: handle failures
13 struct Allocator
14 {
15 	void* function(Allocator*, size_t) vt_allocate;
16 	void* function(Allocator*, void*, size_t) vt_reallocate;
17 	void function(Allocator*, void*) vt_free;
18 
19 
20 	Allocator* ptr()
21 	{
22 		return &this;
23 	}
24 
25 	// INTERFACE
26 
27 	void* allocate(size_t size)
28 	{
29 		assert(size > 0);
30 		return vt_allocate(&this, size);
31 	}
32 	
33 	void* reallocate(void* ptr, size_t size)
34 	{
35 		assert(size > 0);
36 		return vt_reallocate(&this, ptr, size);
37 	}
38 
39 	// prefer safe_delete(T)(ref T* ptr)
40 	void free(void* ptr)
41 	{
42 		assert(ptr != null);
43 		vt_free(&this, ptr);
44 	}
45 
46 	// END INTERFACE
47 
48 	void safe_delete(T)(ref T* ptr)
49 	{
50 		if(ptr)
51 		{
52 			free(ptr);
53 			ptr = null;
54 		}
55 	}
56 
57 
58 
59 	void[] alloc(size_t size)
60 	{
61 		assert(size > 0);
62 
63 		void* ptr = malloc(size);
64 		if (!ptr)
65 			assert(0, "Out of memory!");
66 		return ptr[0 .. size];
67 	}
68 
69 	T[] alloc_array(T)(size_t count)
70 	{
71 		assert(count > 0, "can't allocate empty array");
72 		return cast(T[]) alloc(T.sizeof * count);
73 	}
74 
75 	T[] reallocate_array(T)(T* ptr, size_t count)
76 	{
77 		assert(count > 0, "can't reallocate empty array");
78 
79 		auto size = T.sizeof * count;
80 		auto ret = reallocate(ptr, size);
81 		return cast(T[]) ret[0 .. size];
82 	}
83 
84 	T* create(T, Args...)(Args args = Args.init)
85 	{
86 		static assert(is(T == struct), "it's not a struct");
87 
88 		void* ptr = allocate(T.sizeof);
89 		if (!ptr)
90 			assert(0, "Out of memory!");
91 
92 		auto ret = cast(T*) ptr;
93 		return emplace(ret, args);
94 	}
95 }
96 
97 struct MallocAllocator
98 {
99 	Allocator base = Allocator( 
100 		&MallocAllocator.allocate,
101 		&MallocAllocator.reallocate,
102 		&MallocAllocator.free,
103 	);
104 	alias base this;
105 
106 	static void* allocate(Allocator* self, size_t size)
107 	{
108 		assert(size > 0);
109 		return core.stdc.stdlib.malloc(size);
110 	}
111 	
112 	static void* reallocate(Allocator* self, void* ptr, size_t size)
113 	{
114 		assert(size > 0);
115 		return core.stdc.stdlib.realloc(ptr, size);
116 	}
117 
118 	static void free(Allocator* self, void* ptr)
119 	{
120 		assert(ptr != null);
121 		core.stdc.stdlib.free(ptr);
122 	}
123 }
124 
125 T[] dupe(T)(Allocator* a, T[] orig)
126 {
127 	assert(orig.length != 0);
128 
129 	T[] ret = a.alloc_array!T(orig.length);
130 
131 	memcpy(ret.ptr, orig.ptr, orig.length * T.sizeof);
132 
133 	return ret;
134 }