1 /** 2 * Betterc: Frequently used primitives suitable for use in the BetterC D subset. 3 * 4 * Copyright: Maxim Freck, 2018. 5 * Authors: Maxim Freck <maxim@freck.pp.ru> 6 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 */ 8 module betterc.dynamicvector; 9 10 /******* 11 * Dynamic Vector without Garbage Collection 12 */ 13 struct Vector(T) 14 { 15 private import core.stdc.stdlib: malloc, realloc, free; 16 private import core.stdc.string: memcpy, memmove; 17 18 private struct Payload { 19 T* arr; 20 size_t length; 21 size_t capacity; 22 size_t initCap; 23 24 size_t count; 25 @disable this(this); // not copyable 26 } 27 28 private Payload* payload; 29 30 /******* 31 * Constructor 32 * 33 * Params: 34 * n = Initial array capacity 35 */ 36 this (size_t n) nothrow @nogc 37 { 38 payload = (cast(Payload*)malloc(Payload.sizeof)); 39 payload.length = 0; 40 payload.capacity = n; 41 payload.initCap = n; 42 payload.arr = (cast(T*)malloc(T.sizeof*n)); 43 payload.count = 1; 44 } 45 46 /******* 47 * Constructor 48 * 49 * Params: 50 * src = Initial array values 51 * n = Initial array capacity 52 */ 53 this(T[] src, size_t n = 0) nothrow @nogc 54 { 55 56 payload = (cast(Payload*)malloc(Payload.sizeof)); 57 payload.length = 0; 58 payload.initCap = n == 0 ? src.length : n; 59 payload.capacity = payload.initCap; 60 payload.arr = (cast(T*)malloc(T.sizeof*payload.capacity)); 61 payload.count = 1; 62 63 push(src); 64 } 65 66 private this(Payload* src, size_t a, size_t b) nothrow @nogc 67 { 68 69 payload = (cast(Payload*)malloc(Payload.sizeof)); 70 payload.length = b - a; 71 payload.initCap = src.initCap; 72 payload.capacity = src.capacity; 73 payload.arr = (cast(T*)malloc(T.sizeof*payload.length)); 74 payload.count = 1; 75 memcpy(payload.arr, src.arr+a, payload.length); 76 } 77 78 this(this) nothrow @nogc 79 { 80 if (payload !is null) 81 payload.count++; 82 } 83 84 ///Ref. counting during structure assignation 85 ref typeof(this) opAssign(ref typeof(this) rhs) 86 { 87 this.payload = rhs.payload; 88 if (payload !is null) 89 payload.count++; 90 91 return this; 92 } 93 94 ~this() nothrow @nogc 95 { 96 //TODO: call elements destructors if present 97 if (payload !is null && --payload.count == 0) { 98 free(payload.arr); 99 free(payload); 100 } 101 } 102 103 /******* 104 * Shrinks array 105 * 106 * Params: 107 * len = New array size 108 */ 109 public ref typeof(this) shrink(size_t len = 0) nothrow @nogc 110 { 111 if (len < payload.length) payload.length = len; 112 if (payload.length == 0 || payload.capacity/payload.length > 1) shrink_to_fit(); 113 return this; 114 } 115 116 /******* 117 * Requests the removal of unused capacity. 118 * 119 */ 120 public ref typeof(this) shrink_to_fit() nothrow @nogc 121 { 122 payload.capacity = payload.length == 0 ? payload.initCap : (payload.length * 3) / 2; 123 payload.arr = (cast(T*)realloc(payload.arr, T.sizeof*payload.capacity)); 124 return this; 125 } 126 127 /******* 128 * Clears entire array 129 * 130 */ 131 pragma(inline) 132 public ref typeof(this) clear() nothrow @nogc 133 { 134 return shrink(0); 135 } 136 137 /******* 138 * Erases nth array element 139 * 140 * Params: 141 * n = Element number 142 */ 143 public ref typeof(this) erase(in size_t n) nothrow @nogc 144 { 145 if (n >= payload.length) return this; 146 147 if (n == payload.length - 1) { 148 payload.length--; 149 return this; 150 } 151 152 payload.length--; 153 memmove(payload.arr+n, payload.arr+n+1, payload.length - n); 154 155 return this; 156 } 157 158 public ref typeof(this) trim() 159 { 160 payload.capacity = payload.length; 161 payload.arr = (cast(T*)realloc(payload.arr, T.sizeof*payload.capacity)); 162 163 return this; 164 } 165 166 public size_t length() const pure nothrow @nogc 167 { 168 return payload.length; 169 } 170 171 public size_t capacity() pure nothrow @nogc 172 { 173 return payload.capacity; 174 } 175 176 public auto ref T opIndex(in size_t id) pure nothrow @nogc 177 { 178 if (payload.length == 0) return T.init; 179 return payload.arr[id>=payload.length ? payload.length - 1 : id]; 180 } 181 182 /******* 183 * Appends a value to an array 184 * 185 * Params: 186 * rhs = The value to add 187 */ 188 public ref typeof(this) push(in T rhs) nothrow @nogc 189 { 190 payload.length++; 191 if (payload.length > payload.capacity) grow(); 192 payload.arr[payload.length - 1] = rhs; 193 194 return this; 195 } 196 197 private void grow() nothrow @nogc 198 { 199 payload.capacity = (payload.capacity * 3) / 2 + 1; 200 payload.arr = (cast(T*)realloc(payload.arr, T.sizeof*payload.capacity)); 201 } 202 203 ///ditto 204 public ref typeof(this) push(in T[] rhs) nothrow @nogc 205 { 206 foreach (v; rhs) push(v); 207 208 return this; 209 } 210 211 ///ditto 212 public ref typeof(this) push(typeof(this) rhs) nothrow @nogc 213 { 214 foreach (v; rhs) push(v); 215 216 return this; 217 } 218 219 /******* 220 * Removes the last element from an array 221 */ 222 public void pop() nothrow @nogc 223 { 224 if (payload.length > 0) payload.length--; 225 } 226 227 /******* 228 * Appends a value to an array using << operator 229 * 230 * Params: 231 * rhs = The value to add 232 */ 233 pragma(inline) 234 public ref typeof(this) opBinary(string op)(in T rhs) nothrow @nogc if (op == "<<") 235 { 236 return push(rhs); 237 } 238 239 ///ditto 240 pragma(inline) 241 public ref typeof(this) opBinary(string op)(in T[] rhs) nothrow @nogc if (op == "<<") 242 { 243 return push(rhs); 244 } 245 246 ///ditto 247 pragma(inline) 248 public ref typeof(this) opBinary(string op)(typeof(this) rhs) nothrow @nogc if (op == "<<") 249 { 250 return push(rhs); 251 } 252 253 254 /******* 255 * The $ operator returns the length of the array 256 */ 257 size_t opDollar() nothrow @nogc 258 { 259 return payload.length; 260 } 261 262 public typeof(this) opSlice(size_t a, size_t b) nothrow @nogc 263 { 264 if (a > b) { 265 immutable c = b; 266 b = a; 267 a = c; 268 } 269 if (a > payload.length) a = payload.length; 270 if (b > payload.length) b = payload.length; 271 272 return typeof(this)(payload, a, b); 273 } 274 275 276 int opApply(scope int delegate(ref T) nothrow @nogc dg) nothrow @nogc 277 { 278 int result = 0; 279 280 foreach (size_t i; 0 .. payload.length) { 281 result = dg(payload.arr[i]); 282 if (result) break; 283 } 284 285 return result; 286 } 287 288 int opApply(scope int delegate(ref size_t, ref T) nothrow @nogc dg) nothrow @nogc 289 { 290 int result; 291 292 foreach (size_t i; 0 .. payload.length) { 293 result = dg(i, payload.arr[i]); 294 if (result) break; 295 } 296 297 return result; 298 } 299 300 T* ptr() pure nothrow @nogc 301 { 302 return payload.arr; 303 } 304 }