1 /** 2 Utility functions for memory management 3 4 Copyright: © 2012-2013 RejectedSoftware e.K. 5 © 2014-2015 Etienne Cimon 6 License: Subject to the terms of the MIT license. 7 Authors: Sönke Ludwig, Etienne Cimon 8 */ 9 module memutils.allocators; 10 11 public import memutils.constants; 12 import memutils.hashmap : HashMap; 13 import memutils.pool; 14 import memutils.memory; 15 import memutils.freelist; 16 import memutils.utils : Malloc; 17 18 19 alias LocklessAllocator = AutoFreeListAllocator!MallocAllocator; 20 21 22 struct Allocator { 23 static enum size_t alignment = 0x10; 24 25 static enum size_t alignmentMask = alignment-1; 26 } 27 28 package: 29 @trusted: 30 31 32 pragma(inline, true) nothrow 33 public auto getAllocator(int ALLOC)(bool is_freeing = false) { 34 static if (ALLOC == LocklessFreeList) alias R = LocklessAllocator; 35 else static if (ALLOC == Mallocator) alias R = MallocAllocator; 36 else static assert(false, "Invalid allocator specified"); 37 return getAllocator!R(is_freeing); 38 } 39 40 nothrow R* getAllocator(R)(bool is_freeing = false, bool kill_it = false) { 41 __gshared static R* alloc; 42 __gshared static R alloc_; 43 static bool deinit; 44 if (kill_it) { 45 import memutils.helpers : destructRecurse; 46 destructRecurse(*alloc); 47 deinit = true; 48 alloc = null; 49 return null; 50 } 51 if (!alloc && !is_freeing) { 52 alloc_ = R(); 53 alloc = &alloc_; 54 } 55 return alloc; 56 } 57 58 nothrow: 59 60 //static ~this() { 61 // getAllocator!LocklessAllocator(false, true); 62 //} 63 64 size_t alignedSize(size_t sz) 65 { 66 return ((sz + Allocator.alignment - 1) / Allocator.alignment) * Allocator.alignment; 67 } 68 69 void* extractUnalignedPointer(void* base) 70 { 71 ubyte misalign = *(cast(const(ubyte)*)base-1); 72 assert(misalign <= Allocator.alignment); 73 return base - misalign; 74 } 75 76 void* adjustPointerAlignment(void* base, ubyte* misalign_ = null) 77 { 78 ubyte misalign = Allocator.alignment - (cast(size_t)base & Allocator.alignmentMask); 79 base += misalign; 80 if (misalign_) *misalign_ = misalign; 81 else *(cast(ubyte*)base-1) = misalign; 82 return base; 83 } 84 85 template AllocSize(T) 86 { 87 static if (is(T == class)) { 88 // workaround for a strange bug where AllocSize!SSLStream == 0: TODO: dustmite! 89 //enum dummy = T.stringof ~ __traits(classInstanceSize, T).stringof; 90 static enum AllocSize = __traits(classInstanceSize, T); 91 } else { 92 static enum AllocSize = T.sizeof; 93 } 94 } 95 96 template RefTypeOf(T) { 97 static if( is(T == class) || __traits(isAbstractClass, T) || is(T == interface) ){ 98 alias RefTypeOf = T; 99 } else { 100 alias RefTypeOf = T*; 101 } 102 } 103 104 version(none): 105 unittest { 106 void testAlign(void* p, size_t adjustment) { 107 void* pa = adjustPointerAlignment(p); 108 assert((cast(size_t)pa & Allocator.alignmentMask) == 0, "Non-aligned pointer."); 109 //assert(*(cast(const(ubyte)*)pa-1) == adjustment, "Invalid adjustment "~to!string(p)~": "~to!string(*(cast(const(ubyte)*)pa-1))); 110 void* pr = extractUnalignedPointer(pa); 111 assert(pr == p, "Recovered base != original"); 112 } 113 void* ptr = .malloc(0x40); 114 ptr += Allocator.alignment - (cast(size_t)ptr & Allocator.alignmentMask); 115 testAlign(ptr++, 0x10); 116 testAlign(ptr++, 0x0F); 117 testAlign(ptr++, 0x0E); 118 testAlign(ptr++, 0x0D); 119 testAlign(ptr++, 0x0C); 120 testAlign(ptr++, 0x0B); 121 testAlign(ptr++, 0x0A); 122 testAlign(ptr++, 0x09); 123 testAlign(ptr++, 0x08); 124 testAlign(ptr++, 0x07); 125 testAlign(ptr++, 0x06); 126 testAlign(ptr++, 0x05); 127 testAlign(ptr++, 0x04); 128 testAlign(ptr++, 0x03); 129 testAlign(ptr++, 0x02); 130 testAlign(ptr++, 0x01); 131 testAlign(ptr++, 0x10); 132 } 133 134 unittest { 135 foreach( i; 0 .. 20 ){ 136 auto ia = alignedSize(i); 137 assert(ia >= i); 138 assert((ia & Allocator.alignmentMask) == 0); 139 assert(ia < i+Allocator.alignment); 140 } 141 }