1 module libd.memory.allocator.systemallocator; 2 3 import libd.memory.ptr : MaybeNullPtr, MaybeNullSlice, NotNullSlice, NotNullPtr; 4 5 @nogc nothrow 6 shared struct SystemAllocator 7 { 8 static immutable string Tag = "system"; 9 10 enum AllocIsStatic = true; 11 12 // Large amount of user trust. 13 @nogc nothrow: 14 15 @trusted 16 static MaybeNullSlice!(T, Tag) alloc(T)(size_t amount) 17 { 18 auto ptr = allocImpl!T(amount); 19 if(ptr is null) 20 return typeof(return)(null); 21 else 22 return typeof(return)(ptr[0..amount]); 23 } 24 25 @trusted 26 static void free(T)(ref NotNullSlice!(T, Tag) slice) 27 { 28 if(!freeImpl!T(slice.ptr)) 29 assert(false, "HeapFree failed. `slice` might be null or points to freed/invalid memory."); 30 slice.slice = null; 31 } 32 33 @trusted 34 static void free(T)(ref NotNullPtr!(T, Tag) ptr) 35 { 36 freeImpl!T(ptr); 37 ptr.ptr = null; 38 } 39 40 @trusted 41 static MaybeNullSlice!(T, Tag) realloc(T)(ref NotNullSlice!(T, Tag) slice, size_t toAmount) 42 { 43 auto ptr = reallocImpl!T(slice.ptr, slice.length, toAmount); 44 slice.slice = null; 45 if(ptr is null) 46 return typeof(return)(null); 47 else 48 return typeof(return)(ptr[0..toAmount]); 49 } 50 } 51 52 import libd.memory.allocator._test; 53 @("SystemAllocator - BasicAllocatorTests") 54 unittest { basicAllocatorTests!(SystemAllocator, () => true)(); } 55 56 void _d_systemAllocInit() 57 { 58 version(Posix) 59 { 60 g_posixAlloc.__ctor(32); 61 } 62 } 63 64 private: 65 66 version(Windows) 67 { 68 @nogc nothrow: 69 70 import runtime.system.windows; 71 72 T* allocImpl(T)(size_t amount) 73 { 74 return cast(T*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, T.sizeof * amount); 75 } 76 77 bool freeImpl(T)(T* ptr) 78 { 79 return !!HeapFree(GetProcessHeap(), 0, ptr); 80 } 81 82 T* reallocImpl(T)(T* ptr, size_t fromAmount, size_t toAmount) 83 { 84 return cast(T*)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ptr, T.sizeof * toAmount); 85 } 86 } 87 else version(Posix) 88 { 89 import runtime.system.posix; 90 import libd.memory; 91 92 // For now. I need to make this better of course. 93 private shared BlockBucketAllocator!64 g_posixAlloc; 94 95 T* allocImpl(T)(size_t amount) 96 { 97 auto p = g_posixAlloc.alloc!T(amount); 98 return cast(T*)p; 99 } 100 101 bool freeImpl(T)(T* ptr) 102 { 103 // Idk, somehow this is a circular reference. Will need to look into it at *some* point. 104 // if(ptr is null || !g_posixAlloc.owns(ptr)) 105 // return false; 106 // g_posixAlloc.free(ptr); 107 return true; 108 } 109 110 T* reallocImpl(T)(T* ptr, size_t fromAmount, size_t toAmount) 111 { 112 auto slice = ptr[0..T.sizeof * fromAmount].notNull!(g_posixAlloc.Tag); 113 auto result = g_posixAlloc.realloc(slice, toAmount); 114 if(result is null) 115 return null; 116 117 if(toAmount > fromAmount) 118 { 119 const difference = (toAmount - fromAmount); 120 memset(0, result.ptr + (fromAmount * T.sizeof), difference * T.sizeof); 121 } 122 123 return result.ptr; 124 } 125 }