1 module mage.util.mem; 2 import std.algorithm : max; 3 4 auto KiB(size_t i) { return i * 1024; } 5 auto MiB(size_t i) { return KiB(i) * 1024; } 6 auto GiB(size_t i) { return MiB(i) * 1024; } 7 auto TiB(size_t i) { return GiB(i) * 1024; } 8 9 struct Mallocator 10 { 11 @disable this(this); 12 } 13 14 static shared Mallocator mallocator; 15 16 @trusted void[] allocate(shared ref Mallocator a, size_t size) 17 { 18 import core.stdc.stdlib : malloc; 19 if(!size) { 20 return null; 21 } 22 auto ptr = malloc(size); 23 return ptr ? ptr[0..size] : null; 24 } 25 26 @system void deallocate(shared ref Mallocator a, void[] mem) 27 { 28 import core.stdc.stdlib : free; 29 free(mem.ptr); 30 } 31 32 unittest { 33 auto p = mallocator.allocate(32); 34 scope(exit) mallocator.deallocate(p); 35 assert(p !is null); 36 assert(mallocator.allocate(0) is null); 37 } 38 39 auto allocate(T, A, Args...)(ref A allocator, Args args) 40 { 41 import std.conv : emplace; 42 return emplace!(T, Args)(allocator.allocate(T.sizeof), args); 43 } 44 45 void deallocate(A, T)(ref A allocator, T instance) 46 { 47 allocator.deallocate(cast(void[])(&instance)[0..T.sizeof]); 48 } 49 50 unittest { 51 struct X { int a = 42; int b = 1337; } 52 auto px = mallocator.allocate!X; 53 scope(exit) mallocator.deallocate(px); 54 assert(px.a == 42); 55 assert(px.b == 1337); 56 } 57 58 struct Block(size_t N = 4.KiB) 59 { 60 void[N] mem; 61 size_t ap = 0; // Allocation pointer. 62 } 63 64 void[] allocate(size_t N)(ref Block!N b, size_t size) 65 { 66 if(!size || b.ap + size > N) { 67 return null; 68 } 69 auto mem = b.mem[b.ap .. b.ap + size]; 70 b.ap += size; 71 return mem; 72 } 73 74 void deallocate(size_t N)(ref Block!N b) 75 { 76 b.ap = 0; 77 } 78 79 unittest { 80 auto block = Block!(16)(); 81 auto m1 = block.allocate(8); 82 assert(m1 !is null); 83 auto m2 = block.allocate(4); 84 assert(m1 !is null); 85 auto m3 = block.allocate(8); 86 assert(m1 !is null); 87 } 88 89 unittest { 90 auto block = Block!(16)(); 91 struct S { int a = 42; int b = 1337; } 92 import mage; 93 auto ps = block.allocate!S(); 94 assert(ps.a == 42); 95 assert(ps.b == 1337); 96 ps = block.allocate!S(1, 2); 97 assert(ps.a == 1); 98 assert(ps.b == 2); 99 } 100 101 /// Uses a dynamic array of fixed sized blocks to allocate memory. 102 struct BlockArray(size_t N) 103 { 104 Block!N[] blocks; 105 } 106 107 void[] allocate(size_t N)(ref BlockArray!N dyn, size_t size) 108 { 109 import std.range; 110 111 if(dyn.blocks.empty) { 112 ++dyn.blocks.length; 113 } 114 auto ptr = dyn.blocks[$-1].allocate(size); 115 if(ptr is null) 116 { 117 ++dyn.blocks.length; 118 ptr = dyn.blocks[$-1].allocate(size); 119 } 120 return ptr; 121 }