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 std.c.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 	void[] alloc(size_t sz)
59 	{
60 		static err = new immutable OutOfMemoryError;
61 		auto ptr = .malloc(sz + Allocator.alignment);
62 		if (ptr is null) throw err;
63 		return adjustPointerAlignment(ptr)[0 .. sz];
64 	}
65 
66 	void[] realloc(void[] mem, size_t new_size)
67 	{
68 		size_t csz = min(mem.length, new_size);
69 		auto p = extractUnalignedPointer(mem.ptr);
70 		size_t oldmisalign = mem.ptr - p;
71 		
72 		auto pn = cast(ubyte*).realloc(p, new_size+Allocator.alignment);
73 		if (p == pn) return pn[oldmisalign .. new_size+oldmisalign];
74 		
75 		auto pna = cast(ubyte*)adjustPointerAlignment(pn);
76 		auto newmisalign = pna - pn;
77 		
78 		// account for changed alignment after realloc (move memory back to aligned position)
79 		if (oldmisalign != newmisalign) {
80 			if (newmisalign > oldmisalign) {
81 				foreach_reverse (i; 0 .. csz)
82 					pn[i + newmisalign] = pn[i + oldmisalign];
83 			} else {
84 				foreach (i; 0 .. csz)
85 					pn[i + newmisalign] = pn[i + oldmisalign];
86 			}
87 		}
88 		
89 		return pna[0 .. new_size];
90 	}
91 	
92 	void free(void[] mem)
93 	{
94 		.free(extractUnalignedPointer(mem.ptr));
95 	}
96 }