1 /**
2  * Tools for building up arrays without using the GC.
3  * Copyright: © 2014 Economic Modeling Specialists, Intl.
4  * Authors: Brian Schott
5  * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt Boost, License 1.0)
6  */
7 
8 module memory.appender;
9 
10 /**
11  * Allocator-backed array appender.
12  */
13 struct Appender(T, A, size_t initialSize = 10)
14 {
15 public:
16 
17 	@disable this();
18 
19 	/**
20 	 * Params:
21 	 *     allocator = the allocator to use
22 	 */
23 	this()(auto ref A allocator)
24 	{
25 		this.allocator = allocator;
26 		mem = cast(T[]) allocator.allocate(initialSize * T.sizeof);
27 		assert (mem.length == initialSize);
28 	}
29 
30 	/**
31 	 * Returns: all of the items
32 	 */
33 	T[] opSlice()
34 	{
35 		return mem[0 .. next];
36 	}
37 
38 	alias put = append;
39 
40 	/**
41 	 * Appends an item.
42 	 */
43 	void append(T item) @trusted
44 	{
45 		if (next >= mem.length)
46 		{
47 			next = mem.length;
48 			immutable newSize = T.sizeof * (mem.length << 1);
49 			void[] original = cast(void[]) mem;
50 			assert (original.ptr is mem.ptr);
51 			assert (mem);
52 			assert (original);
53 			assert (original.length == mem.length * T.sizeof);
54 			bool success = allocator.reallocate(original, newSize);
55 			assert (success);
56 			mem = cast(T[]) original;
57 			assert (mem.ptr == original.ptr);
58 		}
59 		assert (next < mem.length);
60 		mem[next++] = item;
61 	}
62 
63 	void append(inout(T)[] items) @trusted
64 	{
65 		foreach (ref i; items)
66 			append(i);
67 	}
68 
69 	void reset()
70 	{
71 		next = 0;
72 	}
73 
74 	T[] mem;
75 
76 private:
77 	import memory.allocators;
78 	size_t next;
79 
80 	A allocator;
81 }
82 
83 unittest
84 {
85 	import std.allocator;
86 	auto a = Appender!(int, shared Mallocator, 64)(Mallocator.it);
87 	foreach (i; 0 .. 20)
88 		a.append(i);
89 	assert (a[].length == 20);
90 	Mallocator.it.deallocate(a.mem);
91 }