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 }