1 module ut.vector;
2 
3 import ut;
4 import automem.vector;
5 import stdx.allocator.mallocator: Mallocator;
6 import test_allocator;
7 
8 
9 @("length")
10 @safe unittest {
11     vector("foo", "bar", "baz").length.should == 3;
12     vector("quux", "toto").length.should == 2;
13 }
14 
15 @("vector.int")
16 @safe unittest {
17     vector(1, 2, 3, 4, 5)[].shouldEqual([1, 2, 3, 4, 5]);
18     vector(2, 3, 4)[].shouldEqual([2, 3, 4]);
19 }
20 
21 @("vector.double")
22 @safe unittest {
23     vector(33.3)[].shouldEqual([33.3]);
24     vector(22.2, 77.7)[].shouldEqual([22.2, 77.7]);
25 }
26 
27 @("copying")
28 @safe unittest {
29     auto vec1 = vector(1, 2, 3);
30     vec1.reserve(10);
31     auto vec2 = vec1;
32     vec1[1] = 7;
33 
34     vec1[].shouldEqual([1, 7, 3]);
35     vec2[].shouldEqual([1, 2, 3]);
36 }
37 
38 @("bounds check")
39 @safe unittest {
40 
41     auto vec = vector(1, 2, 3);
42     vec.reserve(10);
43     vec[3].shouldThrow!BoundsException;
44     vec[-1].shouldThrow!BoundsException;
45 }
46 
47 @("extend")
48 @safe unittest {
49     import std.algorithm: map;
50 
51     auto vec = vector(0, 1, 2, 3);
52 
53     vec ~= 4;
54     vec[].shouldEqual([0, 1, 2, 3, 4]);
55 
56     vec ~= [5, 6];
57     vec[].shouldEqual([0, 1, 2, 3, 4, 5, 6]);
58 
59     vec ~= [1, 2].map!(a => a + 10);
60     vec[].shouldEqual([0, 1, 2, 3, 4, 5, 6, 11, 12]);
61 }
62 
63 
64 @("put")
65 @safe unittest {
66     import std.range: iota;
67 
68     auto vec = vector(0, 1, 2, 3);
69     vec.put(4);
70     vec[].shouldEqual([0, 1, 2, 3, 4]);
71     vec.put(2.iota);
72     vec[].shouldEqual([0, 1, 2, 3, 4, 0, 1]);
73 }
74 
75 @("append")
76 @safe unittest {
77     auto vec1 = vector(0, 1, 2);
78     auto vec2 = vector(3, 4);
79 
80     auto vec3 =  vec1 ~ vec2;
81     vec3[].shouldEqual([0, 1, 2, 3, 4]);
82 
83     vec1[0] = 7;
84     vec2[0] = 9;
85     vec3[].shouldEqual([0, 1, 2, 3, 4]);
86 
87 
88     // make sure capacity is larger
89     vec1 ~= 100;
90     vec1.capacity.shouldBeGreaterThan(vec1.length);
91     vec1[].shouldEqual([7, 1, 2, 100]);
92 
93     vec2 ~= 200;
94     vec2.capacity.shouldBeGreaterThan(vec2.length);
95     vec2[].shouldEqual([9, 4, 200]);
96 
97     (vec1 ~ vec2)[].shouldEqual([7, 1, 2, 100, 9, 4, 200]);
98     (vec1 ~ vector(11, 12, 13, 14, 15))[].shouldEqual([7, 1, 2, 100, 11, 12, 13, 14, 15]);
99 }
100 
101 @("slice")
102 @safe unittest {
103     const vec = vector(0, 1, 2, 3, 4, 5);
104     vec[][].shouldEqual([0, 1, 2, 3, 4, 5]);
105     vec[1 .. 3][].shouldEqual([1, 2]);
106     vec[1 .. 4][].shouldEqual([1, 2, 3]);
107     vec[2 .. 5][].shouldEqual([2, 3, 4]);
108     vec[1 .. $ - 1][].shouldEqual([1, 2, 3, 4]);
109 }
110 
111 @("opDollar")
112 @safe unittest {
113     auto vec = vector(0, 1, 2, 3, 4);
114     vec ~= 5;
115     vec ~= 6;
116     vec.capacity.shouldBeGreaterThan(vec.length);
117 
118     vec[1 .. $ - 1][].shouldEqual([1, 2, 3, 4, 5]);
119 }
120 
121 @("assign")
122 @safe unittest {
123     import std.range: iota;
124     auto vec = vector(10, 11, 12);
125     vec = 5.iota;
126     vec[].shouldEqual([0, 1, 2, 3, 4]);
127 }
128 
129 @("construct from range")
130 @safe unittest {
131     import std.range: iota;
132     vector(5.iota)[].shouldEqual([0, 1, 2, 3, 4]);
133 }
134 
135 @("front")
136 @safe unittest {
137     vector(1, 2, 3).front.should == 1;
138     vector(2, 3).front.should == 2;
139 }
140 
141 @("popBack")
142 @safe unittest {
143     auto vec = vector(0, 1, 2);
144     vec.popBack;
145     vec[].shouldEqual([0, 1]);
146 }
147 
148 @("popFront")
149 @safe unittest {
150     auto vec = vector(0, 1, 2, 3, 4);
151     vec.popFront;
152     vec[].shouldEqual([1, 2, 3, 4]);
153     vec.empty.shouldBeFalse;
154 
155     foreach(i; 0 ..  vec.length) vec.popFront;
156     vec.empty.shouldBeTrue;
157 }
158 
159 
160 @("back")
161 @safe unittest {
162     const vec = vector("foo", "bar", "baz");
163     vec.back[].shouldEqual("baz");
164 }
165 
166 @("opSliceAssign")
167 @safe unittest {
168     auto vec = vector("foo", "bar", "quux", "toto");
169 
170     vec[] = "haha";
171     vec[].shouldEqual(["haha", "haha", "haha", "haha"]);
172 
173     vec[1..3] = "oops";
174     vec[].shouldEqual(["haha", "oops", "oops", "haha"]);
175 }
176 
177 @("opSliceOpAssign")
178 @safe unittest {
179     auto vec = vector("foo", "bar", "quux", "toto");
180     vec[] ~= "oops";
181     vec[].shouldEqual(["foooops", "baroops", "quuxoops", "totooops"]);
182 }
183 
184 @("opSliceOpAssign range")
185 @safe unittest {
186     auto vec = vector("foo", "bar", "quux", "toto");
187     vec[1..3] ~= "oops";
188     vec[].shouldEqual(["foo", "baroops", "quuxoops", "toto"]);
189 }
190 
191 @("clear")
192 @safe unittest {
193     auto vec = vector(0, 1, 2, 3);
194     vec.clear;
195     int[] empty;
196     vec[].shouldEqual(empty);
197 }
198 
199 
200 @("Mallocator elements")
201 @safe @nogc unittest {
202     import std.algorithm: equal;
203     auto vec = vector!Mallocator(0, 1, 2, 3);
204     int[4] exp = [0, 1, 2, 3];
205     assert(equal(vec[], exp[]));
206 }
207 
208 @("Mallocator range")
209 @safe @nogc unittest {
210     import std.algorithm: equal;
211     import std.range: iota;
212     auto vec = vector!Mallocator(iota(5));
213     int[5] exp = [0, 1, 2, 3, 4];
214     assert(equal(vec[], exp[]));
215 }
216 
217 
218 @("theAllocator null")
219 @safe unittest {
220     Vector!int vec;
221 }
222 
223 
224 @("Mallocator null")
225 @safe @nogc unittest {
226     Vector!(int, Mallocator) vec;
227 }
228 
229 @("Cannot escape slice")
230 @safe @nogc unittest {
231     int[] ints1;
232     scope vec = vector!Mallocator(0, 1, 2, 3);
233     int[] ints2;
234 
235     static assert(!__traits(compiles, ints1 = vec[]));
236     static assert(__traits(compiles, ints2 = vec[]));
237 }
238 
239 
240 @("TestAllocator elements capacity")
241 @safe unittest {
242     static TestAllocator allocator;
243 
244     auto vec = vector(&allocator, 0, 1, 2);
245     vec[].shouldEqual([0, 1, 2]);
246 
247     vec ~= 3;
248     vec ~= 4;
249     vec ~= 5;
250     vec ~= 6;
251     vec ~= 7;
252     vec ~= 8;
253 
254     vec[].shouldEqual([0, 1, 2, 3, 4, 5, 6, 7, 8]);
255     allocator.numAllocations.shouldBeSmallerThan(4);
256 }
257 
258 @("TestAllocator reserve")
259 @safe unittest {
260     static TestAllocator allocator;
261 
262     auto vec = vector!(TestAllocator*, int)(&allocator);
263 
264     vec.reserve(5);
265     () @trusted { vec.shouldBeEmpty; }();
266 
267     vec ~= 0;
268     vec ~= 1;
269     vec ~= 2;
270     vec ~= 3;
271     vec ~= 4;
272 
273     vec[].shouldEqual([0, 1, 2, 3, 4]);
274     allocator.numAllocations.should == 1;
275 
276     vec ~= 5;
277     vec[].shouldEqual([0, 1, 2, 3, 4, 5]);
278     allocator.numAllocations.should == 2;
279 }
280 
281 @("TestAllocator shrink no length")
282 @safe unittest {
283     static TestAllocator allocator;
284 
285     auto vec = vector!(TestAllocator*, int)(&allocator);
286     vec.reserve(10);
287 
288     vec ~= 0;
289     vec ~= 1;
290     vec ~= 2;
291     vec ~= 3;
292 
293     vec.length.should == 4;
294     vec.capacity.should == 10;
295 
296     vec.shrink;
297     vec.length.should == 4;
298     vec.capacity.should == 4;
299 }
300 
301 @("TestAllocator shrink negative number")
302 @safe unittest {
303     static TestAllocator allocator;
304 
305     auto vec = vector(&allocator, 0);
306     vec ~= 1;
307     vec ~= 2;
308     vec ~= 3;
309     vec.capacity.shouldBeGreaterThan(vec.length);
310     const oldCapacity = vec.capacity;
311 
312     vec.shrink(-1).shouldBeFalse;
313     vec.capacity.should == oldCapacity;
314 }
315 
316 @("TestAllocator shrink larger than capacity")
317 @safe unittest {
318     static TestAllocator allocator;
319 
320     auto vec = vector(&allocator, 0);
321     vec ~= 1;
322     vec ~= 2;
323     vec ~= 3;
324     vec.capacity.shouldBeGreaterThan(vec.length);
325     const oldCapacity = vec.capacity;
326 
327     vec.shrink(oldCapacity * 2).shouldBeFalse;
328     vec.capacity.should == oldCapacity;
329 }
330 
331 
332 @("TestAllocator shrink with length")
333 @safe unittest {
334     static TestAllocator allocator;
335 
336     auto vec = vector(&allocator, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
337     vec.capacity.should == 10;
338 
339     vec.shrink(5);
340     vec[].shouldEqual([0, 1, 2, 3, 4]);
341     vec.capacity.should == 5;
342 
343     vec ~= 5;
344     vec[].shouldEqual([0, 1, 2, 3, 4, 5]);
345     allocator.numAllocations.should == 3;
346 
347     vec.reserve(10);
348     vec.length.should == 6;
349     vec.capacity.shouldBeGreaterThan(6);
350 }
351 
352 @("TestAllocator copy")
353 @safe unittest {
354     static TestAllocator allocator;
355 
356     auto vec1 = vector(&allocator, "foo", "bar", "baz");
357     allocator.numAllocations.should == 1;
358 
359     auto vec2 = vec1;
360     allocator.numAllocations.should == 2;
361 }
362 
363 @("TestAllocator move")
364 @safe unittest {
365     static TestAllocator allocator;
366 
367     auto vec = vector(&allocator, "foo", "bar", "baz");
368     allocator.numAllocations.should == 1;
369 
370     consumeVec(vec);
371     allocator.numAllocations.should == 1;
372 }
373 
374 
375 private void consumeVec(T)(auto ref T vec) {
376 
377 }
378 
379 
380 @("set length")
381 @safe unittest {
382     Vector!int vec;
383     vec.length = 3;
384     vec[].shouldEqual([0, 0, 0]);
385 }
386 
387 
388 @("foreach")
389 @safe unittest {
390     foreach(e; vector(7, 7, 7)) {
391         e.should == 7;
392     }
393 }
394 
395 
396 @("equal")
397 @safe unittest {
398     import std.range: iota;
399     import std.algorithm: equal;
400 
401     auto v = vector(0, 1, 2, 3);
402     assert(equal(v, 4.iota));
403 }
404 
405 
406 @("bool")
407 @safe unittest {
408     vector(0, 1, 2).shouldBeTrue;
409     Vector!int v;
410     if(v) {
411         assert(0);
412     }
413 }
414 
415 @("char")
416 @safe unittest {
417     {
418         auto vec = vector('f', 'o', 'o');
419         vec[].shouldEqual("foo");
420         vec ~= 'b';
421         vec ~= ['a', 'r'];
422         vec[].shouldEqual("foobar");
423         vec ~= "quux";
424         vec[].shouldEqual("foobarquux");
425     }
426 
427     {
428         auto vec = vector("foo");
429         vec[].shouldEqual("foo");
430         vec.popBack;
431         vec[].shouldEqual("fo");
432     }
433 
434     {
435         auto vec = vector("foo");
436         vec ~= "bar";
437         vec[].shouldEqual("foobar");
438     }
439 }
440 
441 
442 @("immutable")
443 @safe unittest {
444     Vector!(immutable int) vec;
445     vec ~= 42;
446     vec[].shouldEqual([42]);
447 }
448 
449 
450 @("String")
451 @safe unittest {
452     foreach(c; String("oooooo"))
453         c.should == 'o';
454 }
455 
456 @("stringz")
457 @safe unittest {
458     import std.string: fromStringz;
459     auto str = vector("foobar");
460     const strz = str.stringz;
461     const back = () @trusted { return fromStringz(strz); }();
462     back.should == "foobar";
463     str[].shouldEqual("foobar");
464 }
465 
466 
467 @("ptr")
468 @safe unittest {
469     const vec = vector(0, 1, 2, 3);
470     takesScopePtr(vec.ptr);
471     () @trusted { vec.ptr[1].shouldEqual(1); }();
472 }
473 
474 private void takesScopePtr(T)(scope const(T)* ptr) {
475 
476 }
477 
478 
479 @safe @nogc unittest {
480     import stdx.allocator.showcase: StackFront;
481     import stdx.allocator.mallocator: Mallocator;
482 
483     Vector!(int, StackFront!(1024, Mallocator)) v;
484     v ~= 1;
485 }