1 module ut.vector;
2 
3 
4 import ut;
5 import automem.vector;
6 import std.experimental.allocator.mallocator: Mallocator;
7 import test_allocator;
8 
9 
10 @("length")
11 @safe unittest {
12     vector("foo", "bar", "baz").length.should == 3;
13     vector("quux", "toto").length.should == 2;
14 }
15 
16 @("vector.int")
17 @safe unittest {
18     vector(1, 2, 3, 4, 5).range.should == [1, 2, 3, 4, 5];
19     vector(2, 3, 4).range.should == [2, 3, 4];
20     vector(2, 3, 4).range.should == [2, 3, 4];
21 }
22 
23 @("vector.double")
24 @safe unittest {
25     vector(33.3).range.should == [33.3];
26     vector(22.2, 77.7).range.should == [22.2, 77.7];
27 }
28 
29 @("copying")
30 @safe unittest {
31     auto vec1 = vector(1, 2, 3);
32     () @trusted { vec1.reserve(10); }();
33     auto vec2 = vec1;
34     vec1[1] = 7;
35 
36     vec1.range.should == [1, 7, 3];
37     vec2.range.should == [1, 2, 3];
38 }
39 
40 @("bounds check")
41 @safe unittest {
42 
43     auto vec = vector(1, 2, 3);
44     () @trusted { vec.reserve(10); }();
45     vec[3].shouldThrow!BoundsException;
46     vec[-1].shouldThrow!BoundsException;
47     () @trusted { vec[0 .. 4].shouldThrow!BoundsException; }();
48     () @trusted { vec[0.. 3]; }(); // shouldn't throw (see #45)
49 }
50 
51 @("extend")
52 @system unittest {
53     import std.algorithm: map;
54 
55     auto vec = vector(0, 1, 2, 3);
56 
57     vec ~= 4;
58     vec.range.should == [0, 1, 2, 3, 4];
59 
60     vec ~= [5, 6];
61     vec.range.should == [0, 1, 2, 3, 4, 5, 6];
62 
63     vec ~= [1, 2].map!(a => a + 10);
64     vec.range.should == [0, 1, 2, 3, 4, 5, 6, 11, 12];
65 }
66 
67 
68 @("put")
69 @system unittest {
70     import std.range: iota;
71 
72     auto vec = vector(0, 1, 2, 3);
73     vec.put(4);
74     vec.range.should == [0, 1, 2, 3, 4];
75     vec.put(2.iota);
76     vec.range.should == [0, 1, 2, 3, 4, 0, 1];
77 }
78 
79 @("append")
80 @system unittest {
81     auto vec1 = vector(0, 1, 2);
82     auto vec2 = vector(3, 4);
83 
84     auto vec3 =  vec1 ~ vec2;
85     vec3.range.should == [0, 1, 2, 3, 4];
86 
87     vec1[0] = 7;
88     vec2[0] = 9;
89     vec3.range.should == [0, 1, 2, 3, 4];
90 
91 
92     // make sure capacity is larger
93     vec1 ~= 100;
94     vec1.capacity.shouldBeGreaterThan(vec1.length);
95     vec1.range.should == [7, 1, 2, 100];
96 
97     vec2 ~= 200;
98     vec2.capacity.shouldBeGreaterThan(vec2.length);
99     vec2.range.should == [9, 4, 200];
100 
101     (vec1 ~ vec2).range.should == [7, 1, 2, 100, 9, 4, 200];
102     (vec1 ~ vector(11, 12, 13, 14, 15)).range.should == [7, 1, 2, 100, 11, 12, 13, 14, 15];
103 }
104 
105 @("slice")
106 @system unittest {
107     const vec = vector(0, 1, 2, 3, 4, 5);
108     vec[].should == [0, 1, 2, 3, 4, 5];
109     vec[1 .. 3].should == [1, 2];
110     vec[1 .. 4].should == [1, 2, 3];
111     vec[2 .. 5].should == [2, 3, 4];
112     vec[1 .. $ - 1].should == [1, 2, 3, 4];
113     vec[0 .. 6].should == [0, 1, 2, 3, 4, 5];
114 }
115 
116 @("opDollar")
117 @system unittest {
118     auto vec = vector(0, 1, 2, 3, 4);
119     vec ~= 5;
120     vec ~= 6;
121     vec.capacity.shouldBeGreaterThan(vec.length);
122 
123     vec[1 .. $ - 1].should == [1, 2, 3, 4, 5];
124 }
125 
126 @("assign")
127 @system unittest {
128     import std.range: iota;
129     auto vec = vector(10, 11, 12);
130     vec = 5.iota;
131     vec.range.should == [0, 1, 2, 3, 4];
132 }
133 
134 @("construct from range")
135 @safe unittest {
136     import std.range: iota;
137     vector(5.iota).range.should == [0, 1, 2, 3, 4];
138 }
139 
140 
141 @("popBack")
142 @safe unittest {
143     auto vec = vector(0, 1, 2);
144     vec.popBack;
145     vec.range.should == [0, 1];
146 }
147 
148 @("popFront")
149 @safe unittest {
150     auto vec = vector(0, 1, 2, 3, 4);
151     vec.popFront;
152     vec.range.should == [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 @("opSliceAssign")
161 @system unittest {
162     auto vec = vector("foo", "bar", "quux", "toto");
163 
164     vec[] = "haha";
165     vec.range.should == ["haha", "haha", "haha", "haha"];
166 
167     vec[1..3] = "oops";
168     vec.range.should == ["haha", "oops", "oops", "haha"];
169 }
170 
171 @("opSliceOpAssign")
172 @system unittest {
173     auto vec = vector("foo", "bar", "quux", "toto");
174     vec[] ~= "oops";
175     vec.range.should == ["foooops", "baroops", "quuxoops", "totooops"];
176 }
177 
178 @("opSliceOpAssign range")
179 @system unittest {
180     auto vec = vector("foo", "bar", "quux", "toto");
181     vec[1..3] ~= "oops";
182     vec.range.should == ["foo", "baroops", "quuxoops", "toto"];
183 }
184 
185 @("clear")
186 @safe unittest {
187     auto vec = vector(0, 1, 2, 3);
188     vec.clear;
189     int[] empty;
190     vec.range.should ==(empty);
191 }
192 
193 
194 @("Mallocator elements")
195 @safe @nogc unittest {
196     import std.algorithm: equal;
197     auto vec = vector!Mallocator(0, 1, 2, 3);
198     int[4] exp = [0, 1, 2, 3];
199     assert(equal(vec.range, exp[]));
200 }
201 
202 @("Mallocator range")
203 @safe @nogc unittest {
204     import std.algorithm: equal;
205     import std.range: iota;
206     auto vec = vector!Mallocator(iota(5));
207     int[5] exp = [0, 1, 2, 3, 4];
208     assert(equal(vec.range, exp[]));
209 }
210 
211 
212 @("theAllocator null")
213 @safe unittest {
214     Vector!int vec;
215 }
216 
217 
218 @("Mallocator null")
219 @safe @nogc unittest {
220     Vector!(int, Mallocator) vec;
221 }
222 
223 
224 @("escape.range")
225 @safe @nogc unittest {
226 
227     alias Ints = typeof(Vector!(int, Mallocator).init.range());
228 
229     Ints ints1;
230     scope vec = vector!Mallocator(0, 1, 2, 3);
231     Ints ints2;
232 
233     static assert(!__traits(compiles, ints1 = vec.range));
234     ints2 = vec.range;  // should compile
235 }
236 
237 
238 @("escape.element")
239 @safe unittest {
240 
241     int i = 1;
242     int j = 2;
243 
244     int** oops;
245     scope vec = vector(&i, &j);
246     int** ok;
247 
248     // Taking address of `ref` return not allowed in older dmd versions
249     static if (__VERSION__ >= 2101)
250     {
251         static assert(!__traits(compiles, oops = &vec[0]));
252         ok = &vec[0];
253     }
254 }
255 
256 
257 @("TestAllocator elements capacity")
258 @system unittest {
259     static TestAllocator allocator;
260 
261     auto vec = vector(&allocator, 0, 1, 2);
262     vec.range.should == [0, 1, 2];
263 
264     vec ~= 3;
265     vec ~= 4;
266     vec ~= 5;
267     vec ~= 6;
268     vec ~= 7;
269     vec ~= 8;
270 
271     vec.range.should == [0, 1, 2, 3, 4, 5, 6, 7, 8];
272     allocator.numAllocations.shouldBeSmallerThan(4);
273 }
274 
275 @("TestAllocator reserve")
276 @system unittest {
277     static TestAllocator allocator;
278 
279     auto vec = vector!(TestAllocator*, int)(&allocator);
280 
281     vec.reserve(5);
282     () @trusted { vec.empty.should == true; }();
283 
284     vec ~= 0;
285     vec ~= 1;
286     vec ~= 2;
287     vec ~= 3;
288     vec ~= 4;
289 
290     vec.range.should == [0, 1, 2, 3, 4];
291     allocator.numAllocations.should == 1;
292 
293     vec ~= 5;
294     vec.range.should == [0, 1, 2, 3, 4, 5];
295     allocator.numAllocations.should == 2;
296 }
297 
298 @("TestAllocator shrink no length")
299 @system unittest {
300     static TestAllocator allocator;
301 
302     auto vec = vector!(TestAllocator*, int)(&allocator);
303     vec.reserve(10);
304 
305     vec ~= 0;
306     vec ~= 1;
307     vec ~= 2;
308     vec ~= 3;
309 
310     vec.length.should == 4;
311     vec.capacity.should == 10;
312 
313     vec.shrink;
314     vec.length.should == 4;
315     vec.capacity.should == 4;
316 }
317 
318 @("TestAllocator shrink negative number")
319 @system unittest {
320     static TestAllocator allocator;
321 
322     auto vec = vector(&allocator, 0);
323     vec ~= 1;
324     vec ~= 2;
325     vec ~= 3;
326     vec.capacity.shouldBeGreaterThan(vec.length);
327     const oldCapacity = vec.capacity;
328 
329     vec.shrink(-1).shouldBeFalse;
330     vec.capacity.should == oldCapacity;
331 }
332 
333 @("TestAllocator shrink larger than capacity")
334 @system unittest {
335     static TestAllocator allocator;
336 
337     auto vec = vector(&allocator, 0);
338     vec ~= 1;
339     vec ~= 2;
340     vec ~= 3;
341     vec.capacity.shouldBeGreaterThan(vec.length);
342     const oldCapacity = vec.capacity;
343 
344     vec.shrink(oldCapacity * 2).shouldBeFalse;
345     vec.capacity.should == oldCapacity;
346 }
347 
348 
349 @("TestAllocator shrink with length")
350 @system unittest {
351     static TestAllocator allocator;
352 
353     auto vec = vector(&allocator, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
354     vec.capacity.should == 10;
355 
356     vec.shrink(5);
357     vec.range.should == [0, 1, 2, 3, 4];
358     vec.capacity.should == 5;
359 
360     vec ~= 5;
361     vec.range.should == [0, 1, 2, 3, 4, 5];
362     allocator.numAllocations.should == 3;
363 
364     vec.reserve(10);
365     vec.length.should == 6;
366     vec.capacity.shouldBeGreaterThan(6);
367 }
368 
369 @("TestAllocator shrink with length range invalidation")
370 @safe unittest {
371     static TestAllocator allocator;
372 
373     scope vec = vector(&allocator, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
374     vec.capacity.should == 10;
375     scope rng = vec.range;
376 
377     foreach(i; 0 .. 5)
378         rng.popFront;
379     rng.empty.should == false;
380 
381     () @trusted { vec.shrink(5); }();
382     rng.empty.should == true;
383 }
384 
385 @("TestAllocator copy")
386 @safe unittest {
387     static TestAllocator allocator;
388 
389     auto vec1 = vector(&allocator, "foo", "bar", "baz");
390     allocator.numAllocations.should == 1;
391 
392     auto vec2 = vec1;
393     allocator.numAllocations.should == 2;
394 }
395 
396 @("TestAllocator move")
397 @safe unittest {
398     static TestAllocator allocator;
399 
400     auto vec = vector(&allocator, "foo", "bar", "baz");
401     allocator.numAllocations.should == 1;
402 
403     consumeVec(vec);
404     allocator.numAllocations.should == 1;
405 }
406 
407 
408 private void consumeVec(T)(auto ref T vec) {
409 
410 }
411 
412 
413 @("set length")
414 @system unittest {
415     Vector!int vec;
416     vec.length = 3;
417     vec.range.should == [0, 0, 0];
418 }
419 
420 
421 @("foreach")
422 @safe unittest {
423     // can't be inline in the foreach otherwise disappears before anything happens
424     scope v = vector(7, 7, 7);
425     foreach(e; v.range) {
426         e.should == 7;
427     }
428 }
429 
430 
431 @("equal")
432 @safe unittest {
433     import std.range: iota;
434     import std.algorithm: equal;
435 
436     auto v = vector(0, 1, 2, 3);
437     assert(equal(v.range, 4.iota));
438 }
439 
440 
441 @("bool")
442 @safe unittest {
443     vector(0, 1, 2).shouldBeTrue;
444     Vector!int v;
445     if(v) {
446         assert(0);
447     }
448 }
449 
450 @("char")
451 @system unittest {
452     {
453         auto vec = vector('f', 'o', 'o');
454         vec.range.should ==("foo");
455         vec ~= 'b';
456         vec ~= ['a', 'r'];
457         vec.range.should ==("foobar");
458         vec ~= "quux";
459         vec.range.should ==("foobarquux");
460     }
461 
462     {
463         auto vec = vector("foo");
464         vec.range.should ==("foo");
465         vec.popBack;
466         vec.range.should ==("fo");
467     }
468 
469     {
470         auto vec = vector("foo");
471         vec ~= "bar";
472         vec.range.should ==("foobar");
473     }
474 }
475 
476 
477 @("immutable.append")
478 @system unittest {
479     Vector!(immutable int) vec;
480     vec ~= 42;
481     vec.range.should == [42];
482 }
483 
484 
485 @("String")
486 @safe unittest {
487     // can't be inline in the foreach otherwise disappears
488     auto s = String("oooooo");
489     foreach(c; s.range)
490         c.should == 'o';
491 }
492 
493 @("stringz")
494 @safe unittest {
495     import std.string: fromStringz;
496     auto str = vector("foobar");
497     const strz = () @trusted { return str.stringz; }();
498     const back = () @trusted { return fromStringz(strz); }();
499     back.should == "foobar";
500     str.range.should ==("foobar");
501 }
502 
503 
504 @("ptr")
505 @safe unittest {
506     const vec = vector(0, 1, 2, 3);
507     takesScopePtr(vec.ptr);
508     () @trusted { vec.ptr[1].should == 1; }();
509 }
510 
511 private void takesScopePtr(T)(scope const(T)* ptr) {
512 
513 }
514 
515 
516 @("StackFront")
517 @safe @nogc unittest {
518     import std.algorithm: equal;
519     import std.experimental.allocator.showcase: StackFront;
520     import std.experimental.allocator.mallocator: Mallocator;
521 
522     alias Allocator = StackFront!(1024, Mallocator);
523 
524     {
525         Vector!(int, Allocator) v;
526         () @trusted { v ~= 1; }();
527         {
528             int[1] expected = [1];
529             assert(equal(v.range, expected[]));
530         }
531     }
532 
533     {
534         static void fun(Allocator)(ref Allocator allocator) {
535             Vector!(int, Allocator) v;
536         }
537     }
538 }
539 
540 
541 version(Windows) {}
542 else {
543     @("mmapRegionList")
544         @system unittest {
545         import std.experimental.allocator.showcase: mmapRegionList;
546         import std.experimental.allocator.mallocator: Mallocator;
547         import automem.vector: isAllocator;
548 
549         auto v = vector(mmapRegionList(1024), 0, 1, 2);
550         v ~= 3;
551     }
552 }
553 
554 
555 
556 @("2d")
557 @safe unittest {
558     auto v = vector(vector(0, 0, 0), vector(1, 1, 1, 1));
559     v[0].range.should == [0, 0, 0];
560     v[1].range.should == [1, 1, 1, 1];
561 }
562 
563 
564 @("toString")
565 @safe unittest {
566     import std.conv: text;
567     auto v = vector(1, 2, 3);
568     v.range.text.should == `[1, 2, 3]`;
569 }
570 
571 
572 @("return")
573 @system unittest {
574 
575     static auto fun() {
576         auto v = vector(1, 2, 3);
577         v ~= 4;
578         return v;
579     }
580 
581     auto v = fun;
582     v ~= 5;
583     v.range.should == [1, 2, 3, 4, 5];
584 }
585 
586 
587 @("noconsume.range")
588 @safe unittest {
589     import std.algorithm: equal;
590 
591     scope v = vector(1, 2, 3);
592 
593     static void fun(R)(R range) {
594         import std.array: array;
595         assert(equal(range, [1, 2, 3]));
596     }
597 
598     fun(v.range);
599     assert(equal(v.range, [1, 2, 3]));
600 }
601 
602 
603 @("noconsume.foreach")
604 @safe unittest {
605     scope v = vector(1, 2, 3);
606     foreach(e; v.range) {}
607     v.range.should == [1, 2, 3];
608 }
609 
610 
611 @("noconsume.map")
612 @safe unittest {
613     import std.algorithm: map;
614 
615     scope v = vector(1, 2, 3);
616     v.range.map!(a => a * 2).should == [2, 4, 6];
617     v.range.should == [1, 2, 3];
618 }
619 
620 
621 @("reserve")
622 @safe unittest {
623     scope vec = vector(1, 2, 3);
624     vec.range.should == [1, 2, 3];
625     () @trusted { vec.reserve(10); }();
626     vec.range.should == [1, 2, 3];
627 }
628 
629 
630 @("range.reserve")
631 @safe unittest {
632     scope vec = vector(1, 2, 3);
633     scope range = vec.range;
634 
635     range.save.should == [1, 2, 3];
636     () @trusted { vec.reserve(10); }();
637 
638     range.should == [1, 2, 3];
639 }
640 
641 
642 @("range.const")
643 @safe unittest {
644     const vec = vector(1, 2, 3);
645     vec.range.should == [1, 2, 3];
646 }
647 
648 
649 @("range.bounds")
650 @safe unittest {
651     const vec = vector(1, 2, 3, 4, 5);
652     vec.range(1, 4).should == [2, 3, 4];
653     vec.range(2, vec.length).should == [3, 4, 5];
654     vec.range(2, -1).should == [3, 4, 5];
655     vec.range(2, -2).should == [3, 4];
656 }
657 
658 
659 @("equals")
660 @safe unittest {
661     import std.range: iota, only;
662 
663     const vec = vector(0, 1, 2);
664 
665     (vec == 3.iota).should == true;
666     (vec == 2.iota).should == false;
667     (vec == 4.iota).should == false;
668     (vec == only(0)).should == false;
669 }