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