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 }