1 /**
2 Copyright: Copyright (c) 2016-2018 Andrey Penechko.
3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
4 Authors: Andrey Penechko.
5 */
6 module voxelman.container.buffer;
7 
8 import std.experimental.allocator.gc_allocator;
9 alias allocator = GCAllocator.instance;
10 import voxelman.math : nextPOT;
11 
12 
13 struct Buffer(T)
14 {
15 	T[] buf;
16 	// Must be kept private since it can be used to check for avaliable space
17 	// when used as output range
18 	private size_t length;
19 
20 	bool empty() { return length == 0; }
21 
22 	void put(T[] items ...)
23 	{
24 		reserve(items.length);
25 		buf[length..length+items.length] = items;
26 		length += items.length;
27 	}
28 
29 	void put(R)(R itemRange)
30 	{
31 		foreach(item; itemRange)
32 			put(item);
33 	}
34 
35 	void stealthPut(T item)
36 	{
37 		reserve(1);
38 		buf[length] = item;
39 	}
40 
41 	/// Increases length and returns void-initialized slice to be filled by user
42 	T[] voidPut(size_t howMany)
43 	{
44 		reserve(howMany);
45 		length += howMany;
46 		return buf[length-howMany..length];
47 	}
48 
49 	ref T opIndex(size_t at)
50 	{
51 		return buf[at];
52 	}
53 
54 	ref T back() { return buf[length-1]; }
55 
56 	inout(T[]) data() inout {
57 		return buf[0..length];
58 	}
59 
60 	void clear() nothrow {
61 		length = 0;
62 	}
63 
64 	size_t capacity() const @property {
65 		return buf.length;
66 	}
67 
68 	void reserve(size_t items)
69 	{
70 		if (buf.length - length < items)
71 		{
72 			import core.memory;
73 			GC.removeRange(buf.ptr);
74 			size_t newCapacity = nextPOT(buf.length + items);
75 			void[] tmp = buf;
76 			allocator.reallocate(tmp, newCapacity*T.sizeof);
77 			buf = cast(T[])tmp;
78 			GC.addRange(buf.ptr, buf.length * T.sizeof, typeid(T));
79 		}
80 	}
81 
82 	void unput(size_t numItems)
83 	{
84 		length -= numItems;
85 	}
86 }