1 module yu.memory.allocator.smartgcalloctor; 2 3 import std.experimental.allocator; 4 5 struct SmartGCAllocator { 6 import core.memory : GC; 7 8 enum uint alignment = platformAlignment; 9 10 pure nothrow @trusted void[] allocate(size_t bytes) shared { 11 if (!bytes) 12 return null; 13 auto p = GC.malloc(bytes); 14 return p ? p[0 .. bytes] : null; 15 } 16 17 @system bool expand(ref void[] b, size_t delta) shared { 18 if (delta == 0) 19 return true; 20 if (b is null) 21 return false; 22 immutable curLength = GC.sizeOf(b.ptr); 23 assert(curLength != 0); // we have a valid GC pointer here 24 immutable desired = b.length + delta; 25 if (desired > curLength) // check to see if the current block can't hold the data 26 { 27 immutable sizeRequest = desired - curLength; 28 immutable newSize = GC.extend(b.ptr, sizeRequest, sizeRequest); 29 if (newSize == 0) { 30 // expansion unsuccessful 31 return false; 32 } 33 assert(newSize >= desired); 34 } 35 b = b.ptr[0 .. desired]; 36 return true; 37 } 38 39 pure nothrow @system bool reallocate(ref void[] b, size_t newSize) shared { 40 import core.exception : OutOfMemoryError; 41 42 try { 43 auto p = cast(ubyte*) GC.realloc(b.ptr, newSize); 44 b = p[0 .. newSize]; 45 } 46 catch (OutOfMemoryError) { 47 // leave the block in place, tell caller 48 return false; 49 } 50 return true; 51 } 52 53 pure nothrow void[] resolveInternalPointer(void* p) shared { 54 auto r = GC.addrOf(p); 55 if (!r) 56 return null; 57 return r[0 .. GC.sizeOf(r)]; 58 } 59 60 pure nothrow @system bool deallocate(void[] b) shared { 61 GC.free(b.ptr); 62 return true; 63 } 64 65 size_t goodAllocSize(size_t n) shared { 66 if (n == 0) 67 return 0; 68 if (n <= 16) 69 return 16; 70 71 import core.bitop : bsr; 72 73 auto largestBit = bsr(n - 1) + 1; 74 if (largestBit <= 12) // 4096 or less 75 return size_t(1) << largestBit; 76 77 // larger, we use a multiple of 4096. 78 return ((n + 4095) / 4096) * 4096; 79 } 80 81 static shared SmartGCAllocator instance; 82 83 nothrow @trusted void collect() shared { 84 GC.collect(); 85 } 86 87 auto make(T, A...)(auto ref A args) shared { 88 auto construct() { 89 static if (is(T == class) || is(T == struct)) 90 return new T(args); 91 else { 92 import std.algorithm.comparison : max; 93 import std.conv : emplace; 94 95 auto m = this.allocate(max(stateSize!T, 1)); 96 if (!m.ptr) 97 return null; 98 scope (failure) { 99 () @trusted{ this.deallocate(m); }(); 100 } 101 // Assume cast is safe as allocation succeeded for `stateSize!T` 102 auto p = () @trusted{ return cast(T*) m.ptr; }(); 103 emplace!T(p, args); 104 return p; 105 } 106 } 107 108 return construct(); 109 } 110 111 }