1 module mutils.container.vector_allocator; 2 3 import std.experimental.allocator; 4 import std.traits; 5 6 /** 7 * Vector backed by given allocator, it is not releaseing data after destruction, used in lua_json_token to treat dynamic arrays as a custom vector 8 **/ 9 struct VectorAllocator(T, Allocator) { 10 static if (hasStaticMember!(Allocator, "instance")) { 11 alias allocator = Allocator.instance; 12 } else { 13 Allocator allocator; 14 } 15 16 T[] array; 17 18 this(size_t numElements) { 19 assert(numElements > 0); 20 setLenght(numElements); 21 } 22 23 void clear() { 24 removeAll(); 25 } 26 27 void removeAll() { 28 if (array !is null) { 29 freeData(cast(void[]) array); 30 } 31 array = T[].init; 32 } 33 34 bool empty() { 35 return (array.length == 0); 36 } 37 38 size_t length() { 39 return array.length; 40 } 41 42 void reset() { 43 clear(); 44 } 45 46 void setLenght(size_t newNumOfElements) { 47 if (array is null) { 48 array = allocator.makeArray!(T)(newNumOfElements); 49 } else { 50 if (array.length < newNumOfElements) { 51 allocator.expandArray(array, newNumOfElements - array.length); 52 } else if (array.length > newNumOfElements) { 53 allocator.shrinkArray(array, array.length - newNumOfElements); 54 } 55 } 56 } 57 58 void freeData(void[] data) { 59 allocator.dispose(array); 60 } 61 62 void add(T t) { 63 setLenght(array.length + 1); 64 array[$ - 1] = t; 65 } 66 67 void add(X)(X[] t) if (is(Unqual!X == Unqual!T)) { 68 size_t sizeBefore = array.length; 69 setLenght(array.length + t.length); 70 foreach (i; 0 .. t.length) { 71 array[sizeBefore + i] = t[i]; 72 } 73 } 74 75 void remove(size_t elemNum) { 76 array[elemNum] = array[$ - 1]; 77 setLenght(array.length - 1); 78 } 79 80 void removeElement(T elem) { 81 foreach (i, ref el; array) { 82 if (el == elem) { 83 remove(i); 84 return; 85 } 86 } 87 } 88 89 T opIndex(size_t elemNum) { 90 return array[elemNum]; 91 } 92 93 auto opSlice() { 94 return array; 95 } 96 97 T[] opSlice(size_t x, size_t y) { 98 return array[x .. y]; 99 } 100 101 size_t opDollar() { 102 return array.length; 103 } 104 105 void opOpAssign(string op)(T obj) { 106 static assert(op == "~"); 107 add(obj); 108 } 109 110 /*void opOpAssign(string op)(T[] obj){ 111 static assert(op=="~"); 112 add(obj); 113 }*/ 114 void opOpAssign(string op, X)(X[] obj) { 115 static assert(op == "~"); 116 add(obj); 117 } 118 119 void opIndexAssign(T obj, size_t elemNum) { 120 array[elemNum] = obj; 121 122 } 123 124 void opAssign(X)(X[] slice) { 125 reset(); 126 this ~= slice; 127 } 128 129 } 130 131 // Helper to avoid GC 132 private T[n] s(T, size_t n)(auto ref T[n] array) pure nothrow @nogc @safe { 133 return array; 134 } 135 136 unittest { 137 import std.experimental.allocator.mallocator; 138 139 VectorAllocator!(int, Mallocator) vec; 140 assert(vec.empty); 141 vec.add(0); 142 vec.add(1); 143 vec.add(2); 144 vec.add(3); 145 vec.add(4); 146 vec.add(5); 147 assert(vec.length == 6); 148 assert(vec[3] == 3); 149 assert(vec[5] == 5); 150 assert(vec[] == [0, 1, 2, 3, 4, 5].s); 151 assert(!vec.empty); 152 vec.remove(3); 153 assert(vec.length == 5); 154 assert(vec[] == [0, 1, 2, 5, 4].s); //unstable remove 155 156 Mallocator.instance.dispose(vec.array); 157 }