1 /**
2 	Memory provider allocators to be used in templated composition 
3 	within other, designated allocators.
4 
5     Copyright: © 2012-2013 RejectedSoftware e.K.
6     		   © 2014-2015 Etienne Cimon
7     License: Subject to the terms of the MIT license.
8     Authors: Sönke Ludwig, Etienne Cimon
9 */
10 module memutils.memory;
11 
12 import memutils.allocators;
13 import memutils.helpers;
14 import std.algorithm : min;
15 import core.stdc.stdlib;
16 
17 final class GCAllocator : Allocator {
18 	import core.memory : GC;
19 	void[] alloc(size_t sz)
20 	{
21 		auto mem = GC.malloc(sz+Allocator.alignment);
22 		auto alignedmem = adjustPointerAlignment(mem);
23 		assert(alignedmem - mem <= Allocator.alignment);
24 		auto ret = alignedmem[0 .. sz];
25 		ensureValidMemory(ret);
26 		return ret;
27 	}
28 	
29 	void[] realloc(void[] mem, size_t new_size)
30 	{
31 		size_t csz = min(mem.length, new_size);
32 		
33 		auto p = extractUnalignedPointer(mem.ptr);
34 		size_t misalign = mem.ptr - p;
35 		assert(misalign <= Allocator.alignment);
36 		
37 		void[] ret;
38 		auto extended = GC.extend(p, new_size - mem.length, new_size - mem.length);
39 		if (extended) {
40 			assert(extended >= new_size+Allocator.alignment);
41 			ret = p[misalign .. new_size+misalign];
42 		} else {
43 			ret = alloc(new_size);
44 			ret[0 .. csz] = mem[0 .. csz];
45 		}
46 		ensureValidMemory(ret);
47 		return ret;
48 	}
49 
50 	/// calls to free are optional if stability is favored over speed
51 	void free(void[] mem)
52 	{
53 		GC.free(extractUnalignedPointer(mem.ptr));
54 	}
55 }
56 
57 final class MallocAllocator : Allocator {
58 	import core.exception : OutOfMemoryError;
59 
60 	void[] alloc(size_t sz)
61 	{
62 		static err = new immutable OutOfMemoryError;
63 		auto ptr = .malloc(sz + Allocator.alignment);
64 		if (ptr is null) throw err;
65 		return adjustPointerAlignment(ptr)[0 .. sz];
66 	}
67 
68 	void[] realloc(void[] mem, size_t new_size)
69 	{
70 		size_t csz = min(mem.length, new_size);
71 		auto p = extractUnalignedPointer(mem.ptr);
72 		size_t oldmisalign = mem.ptr - p;
73 		ubyte misalign;
74 		auto pn = cast(ubyte*).realloc(p, new_size+Allocator.alignment);
75 		if (p == pn) return pn[oldmisalign .. new_size+oldmisalign];
76 		
77 		auto pna = cast(ubyte*)adjustPointerAlignment(pn, &misalign);
78 		scope(exit) 
79 			*(cast(ubyte*)pna-1) = misalign;
80 		auto newmisalign = pna - pn;
81 		
82 		// account for changed alignment after realloc (move memory back to aligned position)
83 		if (oldmisalign != newmisalign) {
84 			if (newmisalign > oldmisalign) {
85 				foreach_reverse (i; 0 .. csz)
86 					pn[i + newmisalign] = pn[i + oldmisalign];
87 			} else {
88 				foreach (i; 0 .. csz)
89 					pn[i + newmisalign] = pn[i + oldmisalign];
90 			}
91 		}
92 		
93 		return pna[0 .. new_size];
94 	}
95 	
96 	void free(void[] mem)
97 	{
98 		.free(extractUnalignedPointer(mem.ptr));
99 	}
100 }