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 }