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 copy")
370 @safe unittest {
371     static TestAllocator allocator;
372 
373     auto vec1 = vector(&allocator, "foo", "bar", "baz");
374     allocator.numAllocations.should == 1;
375 
376     auto vec2 = vec1;
377     allocator.numAllocations.should == 2;
378 }
379 
380 @("TestAllocator move")
381 @safe unittest {
382     static TestAllocator allocator;
383 
384     auto vec = vector(&allocator, "foo", "bar", "baz");
385     allocator.numAllocations.should == 1;
386 
387     consumeVec(vec);
388     allocator.numAllocations.should == 1;
389 }
390 
391 
392 private void consumeVec(T)(auto ref T vec) {
393 
394 }
395 
396 
397 @("set length")
398 @system unittest {
399     Vector!int vec;
400     vec.length = 3;
401     vec.range.should == [0, 0, 0];
402 }
403 
404 
405 @("foreach")
406 @safe unittest {
407     foreach(e; vector(7, 7, 7).range) {
408         e.should == 7;
409     }
410 }
411 
412 
413 @("equal")
414 @safe unittest {
415     import std.range: iota;
416     import std.algorithm: equal;
417 
418     auto v = vector(0, 1, 2, 3);
419     assert(equal(v.range, 4.iota));
420 }
421 
422 
423 @("bool")
424 @safe unittest {
425     vector(0, 1, 2).shouldBeTrue;
426     Vector!int v;
427     if(v) {
428         assert(0);
429     }
430 }
431 
432 @("char")
433 @system unittest {
434     {
435         auto vec = vector('f', 'o', 'o');
436         vec.range.should ==("foo");
437         vec ~= 'b';
438         vec ~= ['a', 'r'];
439         vec.range.should ==("foobar");
440         vec ~= "quux";
441         vec.range.should ==("foobarquux");
442     }
443 
444     {
445         auto vec = vector("foo");
446         vec.range.should ==("foo");
447         vec.popBack;
448         vec.range.should ==("fo");
449     }
450 
451     {
452         auto vec = vector("foo");
453         vec ~= "bar";
454         vec.range.should ==("foobar");
455     }
456 }
457 
458 
459 @("immutable.append")
460 @system unittest {
461     Vector!(immutable int) vec;
462     vec ~= 42;
463     vec.range.should == [42];
464 }
465 
466 
467 @("String")
468 @safe unittest {
469     foreach(c; String("oooooo").range)
470         c.should == 'o';
471 }
472 
473 @("stringz")
474 @safe unittest {
475     import std.string: fromStringz;
476     auto str = vector("foobar");
477     const strz = () @trusted { return str.stringz; }();
478     const back = () @trusted { return fromStringz(strz); }();
479     back.should == "foobar";
480     str.range.should ==("foobar");
481 }
482 
483 
484 @("ptr")
485 @safe unittest {
486     const vec = vector(0, 1, 2, 3);
487     takesScopePtr(vec.ptr);
488     () @trusted { vec.ptr[1].should == 1; }();
489 }
490 
491 private void takesScopePtr(T)(scope const(T)* ptr) {
492 
493 }
494 
495 
496 @("StackFront")
497 @safe @nogc unittest {
498     import std.algorithm: equal;
499     import std.experimental.allocator.showcase: StackFront;
500     import std.experimental.allocator.mallocator: Mallocator;
501 
502     alias Allocator = StackFront!(1024, Mallocator);
503 
504     {
505         Vector!(int, Allocator) v;
506         () @trusted { v ~= 1; }();
507         {
508             int[1] expected = [1];
509             assert(equal(v.range, expected[]));
510         }
511     }
512 
513     {
514         static void fun(Allocator)(ref Allocator allocator) {
515             Vector!(int, Allocator) v;
516         }
517     }
518 }
519 
520 
521 version(Windows) {}
522 else {
523     @("mmapRegionList")
524         @system unittest {
525         import std.experimental.allocator.showcase: mmapRegionList;
526         import std.experimental.allocator.mallocator: Mallocator;
527         import automem.vector: isAllocator;
528 
529         auto v = vector(mmapRegionList(1024), 0, 1, 2);
530         v ~= 3;
531     }
532 }
533 
534 
535 
536 @("2d")
537 @safe unittest {
538     auto v = vector(vector(0, 0, 0), vector(1, 1, 1, 1));
539     v[0].range.should == [0, 0, 0];
540     v[1].range.should == [1, 1, 1, 1];
541 }
542 
543 
544 @("toString")
545 @safe unittest {
546     import std.conv: text;
547     auto v = vector(1, 2, 3);
548     v.range.text.should == `[1, 2, 3]`;
549 }
550 
551 
552 @("return")
553 @system unittest {
554 
555     static auto fun() {
556         auto v = vector(1, 2, 3);
557         v ~= 4;
558         return v;
559     }
560 
561     auto v = fun;
562     v ~= 5;
563     v.range.should == [1, 2, 3, 4, 5];
564 }
565 
566 
567 @("noconsume.range")
568 @safe unittest {
569     import std.algorithm: equal;
570 
571     scope v = vector(1, 2, 3);
572 
573     static void fun(R)(R range) {
574         import std.array: array;
575         assert(equal(range, [1, 2, 3]));
576     }
577 
578     fun(v.range);
579     assert(equal(v.range, [1, 2, 3]));
580 }
581 
582 
583 @("noconsume.foreach")
584 @safe unittest {
585     scope v = vector(1, 2, 3);
586     foreach(e; v.range) {}
587     v.range.should == [1, 2, 3];
588 }
589 
590 
591 @("noconsume.map")
592 @safe unittest {
593     import std.algorithm: map;
594 
595     scope v = vector(1, 2, 3);
596     v.range.map!(a => a * 2).should == [2, 4, 6];
597     v.range.should == [1, 2, 3];
598 }
599 
600 
601 @("reserve")
602 @safe unittest {
603     scope vec = vector(1, 2, 3);
604     vec.range.should == [1, 2, 3];
605     () @trusted { vec.reserve(10); }();
606     vec.range.should == [1, 2, 3];
607 }
608 
609 
610 @("range.reserve")
611 @safe unittest {
612     scope vec = vector(1, 2, 3);
613     scope range = vec.range;
614 
615     range.save.should == [1, 2, 3];
616     () @trusted { vec.reserve(10); }();
617 
618     range.should == [1, 2, 3];
619 }
620 
621 
622 @("range.const")
623 @safe unittest {
624     const vec = vector(1, 2, 3);
625     vec.range.should == [1, 2, 3];
626 }
627 
628 
629 @("range.bounds")
630 @safe unittest {
631     const vec = vector(1, 2, 3, 4, 5);
632     vec.range(1, 4).should == [2, 3, 4];
633     vec.range(2, vec.length).should == [3, 4, 5];
634     vec.range(2, -1).should == [3, 4, 5];
635     vec.range(2, -2).should == [3, 4];
636 }
637 
638 
639 @("equals")
640 @safe unittest {
641     import std.range: iota, only;
642 
643     const vec = vector(0, 1, 2);
644 
645     (vec == 3.iota).should == true;
646     (vec == 2.iota).should == false;
647     (vec == 4.iota).should == false;
648     (vec == only(0)).should == false;
649 }