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 @safe 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 @safe 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 @safe 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     static assert(!__traits(compiles, oops = vec[0]));
249     ok = vec[0];
250 }
251 
252 
253 @("TestAllocator elements capacity")
254 @system unittest {
255     static TestAllocator allocator;
256 
257     auto vec = vector(&allocator, 0, 1, 2);
258     vec.range.should == [0, 1, 2];
259 
260     vec ~= 3;
261     vec ~= 4;
262     vec ~= 5;
263     vec ~= 6;
264     vec ~= 7;
265     vec ~= 8;
266 
267     vec.range.should == [0, 1, 2, 3, 4, 5, 6, 7, 8];
268     allocator.numAllocations.shouldBeSmallerThan(4);
269 }
270 
271 @("TestAllocator reserve")
272 @system unittest {
273     static TestAllocator allocator;
274 
275     auto vec = vector!(TestAllocator*, int)(&allocator);
276 
277     vec.reserve(5);
278     () @trusted { vec.empty.should == true; }();
279 
280     vec ~= 0;
281     vec ~= 1;
282     vec ~= 2;
283     vec ~= 3;
284     vec ~= 4;
285 
286     vec.range.should == [0, 1, 2, 3, 4];
287     allocator.numAllocations.should == 1;
288 
289     vec ~= 5;
290     vec.range.should == [0, 1, 2, 3, 4, 5];
291     allocator.numAllocations.should == 2;
292 }
293 
294 @("TestAllocator shrink no length")
295 @system unittest {
296     static TestAllocator allocator;
297 
298     auto vec = vector!(TestAllocator*, int)(&allocator);
299     vec.reserve(10);
300 
301     vec ~= 0;
302     vec ~= 1;
303     vec ~= 2;
304     vec ~= 3;
305 
306     vec.length.should == 4;
307     vec.capacity.should == 10;
308 
309     vec.shrink;
310     vec.length.should == 4;
311     vec.capacity.should == 4;
312 }
313 
314 @("TestAllocator shrink negative number")
315 @system unittest {
316     static TestAllocator allocator;
317 
318     auto vec = vector(&allocator, 0);
319     vec ~= 1;
320     vec ~= 2;
321     vec ~= 3;
322     vec.capacity.shouldBeGreaterThan(vec.length);
323     const oldCapacity = vec.capacity;
324 
325     vec.shrink(-1).shouldBeFalse;
326     vec.capacity.should == oldCapacity;
327 }
328 
329 @("TestAllocator shrink larger than capacity")
330 @system unittest {
331     static TestAllocator allocator;
332 
333     auto vec = vector(&allocator, 0);
334     vec ~= 1;
335     vec ~= 2;
336     vec ~= 3;
337     vec.capacity.shouldBeGreaterThan(vec.length);
338     const oldCapacity = vec.capacity;
339 
340     vec.shrink(oldCapacity * 2).shouldBeFalse;
341     vec.capacity.should == oldCapacity;
342 }
343 
344 
345 @("TestAllocator shrink with length")
346 @system unittest {
347     static TestAllocator allocator;
348 
349     auto vec = vector(&allocator, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
350     vec.capacity.should == 10;
351 
352     vec.shrink(5);
353     vec.range.should == [0, 1, 2, 3, 4];
354     vec.capacity.should == 5;
355 
356     vec ~= 5;
357     vec.range.should == [0, 1, 2, 3, 4, 5];
358     allocator.numAllocations.should == 3;
359 
360     vec.reserve(10);
361     vec.length.should == 6;
362     vec.capacity.shouldBeGreaterThan(6);
363 }
364 
365 @("TestAllocator copy")
366 @safe unittest {
367     static TestAllocator allocator;
368 
369     auto vec1 = vector(&allocator, "foo", "bar", "baz");
370     allocator.numAllocations.should == 1;
371 
372     auto vec2 = vec1;
373     allocator.numAllocations.should == 2;
374 }
375 
376 @("TestAllocator move")
377 @safe unittest {
378     static TestAllocator allocator;
379 
380     auto vec = vector(&allocator, "foo", "bar", "baz");
381     allocator.numAllocations.should == 1;
382 
383     consumeVec(vec);
384     allocator.numAllocations.should == 1;
385 }
386 
387 
388 private void consumeVec(T)(auto ref T vec) {
389 
390 }
391 
392 
393 @("set length")
394 @system unittest {
395     Vector!int vec;
396     vec.length = 3;
397     vec.range.should == [0, 0, 0];
398 }
399 
400 
401 @("foreach")
402 @safe unittest {
403     foreach(e; vector(7, 7, 7).range) {
404         e.should == 7;
405     }
406 }
407 
408 
409 @("equal")
410 @safe unittest {
411     import std.range: iota;
412     import std.algorithm: equal;
413 
414     auto v = vector(0, 1, 2, 3);
415     assert(equal(v.range, 4.iota));
416 }
417 
418 
419 @("bool")
420 @safe unittest {
421     vector(0, 1, 2).shouldBeTrue;
422     Vector!int v;
423     if(v) {
424         assert(0);
425     }
426 }
427 
428 @("char")
429 @system unittest {
430     {
431         auto vec = vector('f', 'o', 'o');
432         vec.range.should ==("foo");
433         vec ~= 'b';
434         vec ~= ['a', 'r'];
435         vec.range.should ==("foobar");
436         vec ~= "quux";
437         vec.range.should ==("foobarquux");
438     }
439 
440     {
441         auto vec = vector("foo");
442         vec.range.should ==("foo");
443         vec.popBack;
444         vec.range.should ==("fo");
445     }
446 
447     {
448         auto vec = vector("foo");
449         vec ~= "bar";
450         vec.range.should ==("foobar");
451     }
452 }
453 
454 
455 @("immutable.append")
456 @system unittest {
457     Vector!(immutable int) vec;
458     vec ~= 42;
459     vec.range.should == [42];
460 }
461 
462 
463 @("String")
464 @safe unittest {
465     foreach(c; String("oooooo").range)
466         c.should == 'o';
467 }
468 
469 @("stringz")
470 @safe unittest {
471     import std.string: fromStringz;
472     auto str = vector("foobar");
473     const strz = () @trusted { return str.stringz; }();
474     const back = () @trusted { return fromStringz(strz); }();
475     back.should == "foobar";
476     str.range.should ==("foobar");
477 }
478 
479 
480 @("ptr")
481 @safe unittest {
482     const vec = vector(0, 1, 2, 3);
483     takesScopePtr(vec.ptr);
484     () @trusted { vec.ptr[1].should == 1; }();
485 }
486 
487 private void takesScopePtr(T)(scope const(T)* ptr) {
488 
489 }
490 
491 
492 @("StackFront")
493 @safe @nogc unittest {
494     import std.algorithm: equal;
495     import std.experimental.allocator.showcase: StackFront;
496     import std.experimental.allocator.mallocator: Mallocator;
497 
498     alias Allocator = StackFront!(1024, Mallocator);
499 
500     {
501         Vector!(int, Allocator) v;
502         () @trusted { v ~= 1; }();
503         {
504             int[1] expected = [1];
505             assert(equal(v.range, expected[]));
506         }
507     }
508 
509     {
510         static void fun(Allocator)(ref Allocator allocator) {
511             Vector!(int, Allocator) v;
512         }
513     }
514 }
515 
516 
517 version(Windows) {}
518 else {
519     @("mmapRegionList")
520         @system unittest {
521         import std.experimental.allocator.showcase: mmapRegionList;
522         import std.experimental.allocator.mallocator: Mallocator;
523         import automem.vector: isAllocator;
524 
525         auto v = vector(mmapRegionList(1024), 0, 1, 2);
526         v ~= 3;
527     }
528 }
529 
530 
531 
532 @("2d")
533 @safe unittest {
534     auto v = vector(vector(0, 0, 0), vector(1, 1, 1, 1));
535     v[0].range.should == [0, 0, 0];
536     v[1].range.should == [1, 1, 1, 1];
537 }
538 
539 
540 @("toString")
541 @safe unittest {
542     import std.conv: text;
543     auto v = vector(1, 2, 3);
544     v.range.text.should == `[1, 2, 3]`;
545 }
546 
547 
548 @("return")
549 @system unittest {
550 
551     static auto fun() {
552         auto v = vector(1, 2, 3);
553         v ~= 4;
554         return v;
555     }
556 
557     auto v = fun;
558     v ~= 5;
559     v.range.should == [1, 2, 3, 4, 5];
560 }
561 
562 
563 @("noconsume.range")
564 @safe unittest {
565     import std.algorithm: equal;
566 
567     scope v = vector(1, 2, 3);
568 
569     static void fun(R)(R range) {
570         import std.array: array;
571         assert(equal(range, [1, 2, 3]));
572     }
573 
574     fun(v.range);
575     assert(equal(v.range, [1, 2, 3]));
576 }
577 
578 
579 @("noconsume.foreach")
580 @safe unittest {
581     scope v = vector(1, 2, 3);
582     foreach(e; v.range) {}
583     v.range.should == [1, 2, 3];
584 }
585 
586 
587 @("noconsume.map")
588 @safe unittest {
589     import std.algorithm: map;
590 
591     scope v = vector(1, 2, 3);
592     v.range.map!(a => a * 2).should == [2, 4, 6];
593     v.range.should == [1, 2, 3];
594 }
595 
596 
597 @("reserve")
598 @safe unittest {
599     scope vec = vector(1, 2, 3);
600     vec.range.should == [1, 2, 3];
601     () @trusted { vec.reserve(10); }();
602     vec.range.should == [1, 2, 3];
603 }
604 
605 
606 @("range.reserve")
607 @safe unittest {
608     scope vec = vector(1, 2, 3);
609     scope range = vec.range;
610 
611     range.save.should == [1, 2, 3];
612     () @trusted { vec.reserve(10); }();
613 
614     range.should == [1, 2, 3];
615 }
616 
617 
618 @("range.const")
619 @safe unittest {
620     const vec = vector(1, 2, 3);
621     vec.range.should == [1, 2, 3];
622 }
623 
624 
625 @("range.bounds")
626 @safe unittest {
627     const vec = vector(1, 2, 3, 4, 5);
628     vec.range(1, 4).should == [2, 3, 4];
629     vec.range(2, vec.length).should == [3, 4, 5];
630     vec.range(2, -1).should == [3, 4, 5];
631     vec.range(2, -2).should == [3, 4];
632 }
633 
634 
635 @("equals")
636 @safe unittest {
637     import std.range: iota, only;
638 
639     const vec = vector(0, 1, 2);
640 
641     (vec == 3.iota).should == true;
642     (vec == 2.iota).should == false;
643     (vec == 4.iota).should == false;
644     (vec == only(0)).should == false;
645 }