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 }