1 module mutils.container.vector; 2 3 import core.bitop; 4 import core.stdc.stdlib : malloc,free; 5 import core.stdc.string : memset,memcpy; 6 7 import std.traits:Unqual; 8 9 @nogc @safe nothrow pure size_t nextPow2(size_t num){ 10 return 1<< bsr(num)+1; 11 } 12 13 14 struct Vector(T){ 15 T[] array; 16 size_t used; 17 public: 18 19 this(T t){ 20 add(t); 21 } 22 23 this(T[] t){ 24 add(t); 25 } 26 27 this(size_t numElements){ 28 assert(numElements>0); 29 extend(numElements); 30 } 31 32 void clear(){ 33 removeAll(); 34 } 35 36 void removeAll(){ 37 if(array !is null){ 38 freeData(cast(void[])array); 39 } 40 array=T[].init; 41 used=0; 42 } 43 44 bool empty(){ 45 return (used==0); 46 } 47 48 size_t length(){ 49 return used; 50 } 51 52 void length(size_t newLength){ 53 assert(newLength>=used); 54 reserve(newLength); 55 foreach(ref el;array[used..newLength]){ 56 el=T.init; 57 } 58 used=newLength; 59 } 60 61 void reset(){ 62 used=0; 63 } 64 65 66 void reserve(size_t numElements){ 67 if(numElements>array.length){ 68 extend(numElements); 69 } 70 } 71 72 size_t capacity(){ 73 return array.length-used; 74 } 75 76 void extend(size_t newNumOfElements){ 77 auto oldArray=manualExtend(newNumOfElements); 78 if(oldArray !is null){ 79 freeData(oldArray); 80 } 81 } 82 83 @nogc void freeData(void[] data){ 84 // 0xFFFFFF probably invalid value for pointers and other types 85 memset(data.ptr,0xFFFFFFFF,data.length);// Makes bugs show up xD 86 free(data.ptr); 87 } 88 89 void[] manualExtend(size_t newNumOfElements=0){ 90 if(newNumOfElements==0)newNumOfElements=2; 91 T[] oldArray=array; 92 size_t oldSize=oldArray.length*T.sizeof; 93 size_t newSize=newNumOfElements*T.sizeof; 94 T* memory=cast(T*)malloc(newSize); 95 memcpy(cast(void*)memory,cast(void*)oldArray.ptr,oldSize); 96 array=memory[0..newNumOfElements]; 97 return cast(void[])oldArray; 98 } 99 100 Vector!T copy(){ 101 Vector!T duplicate; 102 duplicate.reserve(used); 103 duplicate~=array[0..used]; 104 return duplicate; 105 } 106 107 bool canAddWithoutRealloc(uint elemNum=1){ 108 return used+elemNum<=array.length; 109 } 110 111 void add(T t) { 112 if(used>=array.length){ 113 extend(nextPow2(used+1)); 114 } 115 array[used]=t; 116 used++; 117 } 118 119 /// Add element at given position moving others 120 void add(T t, size_t pos){ 121 assert(pos<=used); 122 if(used>=array.length){ 123 extend(array.length*2); 124 } 125 foreach_reverse(size_t i;pos..used){ 126 array[i+1]=array[i]; 127 } 128 array[pos]=t; 129 used++; 130 } 131 132 void add(T[] t){ 133 if(used+t.length>array.length){ 134 extend(nextPow2(used+t.length)); 135 } 136 foreach(i;0..t.length){ 137 array[used+i]=t[i]; 138 } 139 used+=t.length; 140 } 141 142 143 void remove(size_t elemNum){ 144 array[elemNum]=array[used-1]; 145 used--; 146 } 147 148 bool tryRemoveElement(T elem){ 149 foreach(i,ref el;array[0..used]){ 150 if(el==elem){ 151 remove(i); 152 return true; 153 } 154 } 155 return false; 156 } 157 158 void removeElement(T elem){ 159 assert(tryRemoveElement(elem)); 160 } 161 162 ref T opIndex(size_t elemNum){ 163 pragma(inline, true); 164 assert(elemNum<used); 165 return array.ptr[elemNum]; 166 } 167 168 auto opSlice(){ 169 return array.ptr[0..used]; 170 } 171 172 T[] opSlice(size_t x, size_t y){ 173 assert(y<=used); 174 return array.ptr[x..y]; 175 } 176 177 size_t opDollar(){ 178 return used; 179 } 180 181 void opOpAssign(string op)(T obj){ 182 static assert(op=="~"); 183 add(obj); 184 } 185 186 void opOpAssign(string op)(T[] obj){ 187 static assert(op=="~"); 188 add(obj); 189 } 190 191 void opIndexAssign(T obj, size_t elemNum){ 192 assert(elemNum<used, "Range viloation"); 193 array[elemNum]=obj; 194 } 195 196 void opSliceAssign(T obj, size_t a, size_t b){ 197 assert(b<used && a<=b, "Range viloation"); 198 array.ptr[a..b]=obj; 199 } 200 201 bool opEquals()(auto ref const Vector!T r) const { 202 return used==r.used && array.ptr[0..used]==r.array.ptr[0..r.used]; 203 } 204 205 size_t toHash() const nothrow @trusted 206 { 207 return hashOf(cast( Unqual!(T)[])array.ptr[0..used]); 208 } 209 210 211 import std.format:FormatSpec,formatValue; 212 /** 213 * Preety print 214 */ 215 void toString(scope void delegate(const(char)[]) sink, FormatSpec!char fmt) 216 { 217 static if(__traits(compiles,formatValue(sink, array[0..used], fmt))){ 218 formatValue(sink, array[0..used], fmt); 219 } 220 } 221 222 } 223 224 // Helper to avoid GC 225 private T[n] s(T, size_t n)(auto ref T[n] array) pure nothrow @nogc @safe{return array;} 226 227 @nogc nothrow unittest{ 228 Vector!int vec; 229 assert(vec.empty); 230 vec.add(0); 231 vec.add(1); 232 vec.add(2); 233 vec.add(3); 234 vec.add(4); 235 vec.add(5); 236 assert(vec.length==6); 237 assert(vec[3]==3); 238 assert(vec[5]==5); 239 assert(vec[]==[0,1,2,3,4,5].s); 240 assert(!vec.empty); 241 vec.remove(3); 242 assert(vec.length==5); 243 assert(vec[]==[0,1,2,5,4].s);//unstable remove 244 245 } 246 247 @nogc nothrow unittest{ 248 Vector!int vec; 249 assert(vec.empty); 250 vec~=[0,1,2,3,4,5].s; 251 assert(vec[]==[0,1,2,3,4,5].s); 252 assert(vec.length==6); 253 vec~=6; 254 assert(vec[]==[0,1,2,3,4,5,6].s); 255 256 } 257 258 259 @nogc nothrow unittest{ 260 Vector!int vec; 261 vec~=[0,1,2,3,4,5].s; 262 vec[3]=33; 263 assert(vec[3]==33); 264 265 }