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