1 module m3.Array; 2 3 private: 4 5 static import m3.m3; 6 7 debug(m3) { 8 static import core.stdc.stdio; 9 alias printf = core.stdc.stdio.printf; 10 } 11 12 static import std.traits; 13 alias isArray = std.traits.isArray; 14 15 public: 16 17 /* Static Array */ 18 19 @safe 20 @nogc 21 T[n] s(T, size_t n)(auto ref T[n] values) pure nothrow if (!isArray!(T)) { 22 return values; 23 } 24 25 @safe 26 @nogc 27 unittest { 28 auto arr1 = [1, 2, 3].s; 29 assert(typeof(arr1).stringof == "int[3]"); 30 assert(arr1.length == 3); 31 } 32 33 /* Dynamic Array */ 34 35 struct DynamicArray(T, size_t OFFSET = 3) { 36 static assert(!isArray!(T), "DynamicArray cannot be used with an array"); 37 static assert(OFFSET > 0); 38 39 private: 40 alias ArrayPtrType = m3.m3.ArrayPtrTypeOf!(T); 41 42 ArrayPtrType _data; 43 44 size_t _length; 45 size_t _capacity; 46 47 public: 48 @nogc 49 this(size_t size) nothrow { 50 this.reserve(size); 51 } 52 53 @nogc 54 this(T[] items) nothrow { 55 _length = items.length; 56 this.reserve(_length); 57 58 for (size_t i = 0; i < _length; i++) { 59 static if (is(T == class)) 60 _data[i] = cast(void*) items[i]; 61 else 62 _data[i] = items[i]; 63 } 64 } 65 66 @nogc 67 ~this() { 68 m3.m3.destruct(_data); 69 } 70 71 @safe 72 @nogc 73 void clear() pure nothrow { 74 _length = 0; 75 } 76 77 @nogc 78 T[] release() pure nothrow { 79 scope(exit) { 80 _data = null; 81 this.clear(); 82 } 83 84 static if (is(T == class)) 85 return cast(T[]) _data[0 .. _length]; 86 else 87 return _data[0 .. _length]; 88 } 89 90 @nogc 91 DynamicArray!(T) copy() nothrow { 92 static if (is(T == class)) 93 return DynamicArray!(T)(cast(T[]) _data[0 .. _length]); 94 else 95 return DynamicArray!(T)(_data[0 .. _length]); 96 } 97 98 @safe 99 @nogc 100 @property 101 size_t length() const pure nothrow { 102 return _length; 103 } 104 105 @safe 106 @nogc 107 @property 108 size_t capacity() const pure nothrow { 109 return _capacity; 110 } 111 112 @nogc 113 @property 114 auto front() inout pure nothrow { 115 return _data; 116 } 117 118 @nogc 119 @property 120 auto back() inout pure nothrow { 121 return _data + _length - 1; 122 } 123 124 @nogc 125 @property 126 auto begin() const pure nothrow { 127 return _data - 1; 128 } 129 130 @nogc 131 @property 132 auto end() const pure nothrow { 133 return _data + _length; 134 } 135 136 @nogc 137 void reserve(size_t size) nothrow { 138 if (size > 0) { 139 _capacity += size; 140 _data = m3.m3.reserve(_data, _capacity); 141 } 142 } 143 144 @nogc 145 void append(U : T)(auto ref U item) nothrow { 146 if (_length == _capacity) 147 this.reserve(_capacity + OFFSET); 148 149 static if (is(T == class)) 150 _data[_length] = cast(void*) item; 151 else 152 _data[_length] = item; 153 154 _length++; 155 } 156 157 @nogc 158 void append(U : T)(U[] items) nothrow { 159 if ((_length + items.length) > _capacity) 160 this.reserve(_capacity + items.length + OFFSET); 161 162 foreach (ref U item; items) { 163 this.append(item); 164 } 165 } 166 167 @nogc 168 auto ref inout(T) opIndex(size_t index) inout pure nothrow in { 169 assert(index < _length); 170 } body { 171 static if (is(T == class)) 172 return cast(T) _data[index]; 173 else 174 return _data[index]; 175 } 176 177 @nogc 178 void opIndexAssign(U : T)(auto ref U item, size_t index) pure nothrow in { 179 assert(index < _length); 180 } body { 181 _data[index] = item; 182 } 183 184 @nogc 185 inout(T[]) opSlice(size_t from, size_t too) inout pure nothrow in { 186 assert(from < _length); 187 assert(too < _length); 188 assert(too > from); 189 } body { 190 static if (is(T == class)) 191 return cast(inout T[]) _data[from .. too]; 192 else 193 return _data[from .. too]; 194 } 195 196 @nogc 197 inout(T[]) opSlice() inout pure nothrow { 198 static if (is(T == class)) 199 return cast(inout T[]) _data[0 .. _length]; 200 else 201 return _data[0 .. _length]; 202 } 203 204 @nogc 205 void opSliceAssign(U : T)(auto ref U item, size_t from, size_t too) pure nothrow in { 206 assert(from < _length); 207 assert(too < _length); 208 assert(too > from); 209 } body { 210 _data[from .. too] = item; 211 } 212 213 @nogc 214 void opSliceAssign(U : T)(auto ref U item) pure nothrow { 215 _data[0 .. _length] = item; 216 } 217 218 @nogc 219 void opSliceAssign(U : T)(auto ref U[] items, size_t from, size_t too) pure nothrow in { 220 assert(from < _length); 221 assert(too < _length); 222 assert(too > from); 223 } body { 224 for (int i = from, j = 0; i < too; i++, j++) { 225 _data[i] = items[j]; 226 } 227 } 228 } 229 230 version (unittest) { 231 class A { 232 @nogc: 233 234 int id; 235 236 this(int i) { 237 this.id = i; 238 } 239 240 ~this() { 241 debug(m3) printf("DTor A\n"); 242 } 243 244 int getId() const { 245 return this.id; 246 } 247 } 248 } 249 250 @nogc 251 unittest { 252 DynamicArray!(char) myStr; 253 254 assert(myStr.length == 0); 255 assert(myStr.capacity == 0); 256 257 myStr.append('H'); 258 259 assert(myStr.length == 1); 260 assert(myStr.capacity == 3); 261 262 myStr.append('a'); 263 264 assert(myStr.length == 2); 265 assert(myStr.capacity == 3); 266 267 myStr.append('l'); 268 269 assert(myStr.length == 3); 270 assert(myStr.capacity == 3); 271 272 myStr.append('l'); 273 274 assert(myStr.length == 4); 275 assert(myStr.capacity == 9); 276 277 myStr.append('o'); 278 279 assert(myStr.length == 5); 280 assert(myStr.capacity == 9); 281 282 const char[5] hello = "Hallo"; 283 const char[5] meep = "-----"; 284 const char[2] moep = "++"; 285 286 for (int i = 0; i < 5; i++) { 287 assert(myStr[i] == hello[i]); 288 } 289 290 assert(myStr[] == hello); 291 assert(myStr[1 .. 4] == hello[1 .. 4]); 292 293 myStr[] = '-'; 294 assert(myStr[] == meep); 295 296 myStr[1 .. 3] = '+'; 297 assert(myStr[1 .. 3] == moep); 298 299 myStr.append(hello[]); 300 assert(myStr.length == 10); 301 assert(myStr.capacity == 26); 302 303 myStr[0 .. 5] = hello[]; 304 305 int i = 0; 306 for (; i < 5; i++) { 307 assert(myStr[i] == hello[i]); 308 } 309 310 for (int j = 0; i < 10; j++, i++) { 311 assert(myStr[i] == hello[j]); 312 } 313 314 myStr[0] = 'h'; 315 assert(myStr[0] == 'h'); 316 317 assert(!__traits(compiles, { DynamicArray!(int[]) _; })); 318 319 // Class test 320 321 void[m3.m3.SizeOf!(A)] buf = void; 322 A a1 = m3.m3.emplace!(A)(buf[], 42); 323 assert(a1.id == 42 && a1.getId() == 42); 324 325 // as void* 326 327 DynamicArray!(void*) as; 328 as.append(buf.ptr); 329 330 assert(as.length == 1); 331 assert(as.capacity == 3); 332 333 A a2 = cast(A) as[0]; 334 assert(a2 is a1); 335 assert(a2.id == 42 && a2.getId() == 42); 336 337 // as class reference 338 339 assert(__traits(compiles, { DynamicArray!(A) _; })); 340 341 DynamicArray!(A) as2; 342 343 as2.append(a1); 344 as2.append(null); 345 as2.append(a2); 346 347 assert(as2.length == 3); 348 assert(as2.capacity == 3); 349 350 A a3 = as2[0]; 351 assert(a3 is a1); 352 assert(a3.id == 42 && a3.getId() == 42); 353 354 A a4 = as2[1]; 355 assert(a4 is null); 356 357 A a5 = as2[2]; 358 assert(a5 is a3); 359 assert(a5.id == 42 && a5.getId() == 42); 360 }