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 @("back")
137 @safe unittest {
138     const vec = vector("foo", "bar", "baz");
139     vec.back[].shouldEqual("baz");
140 }
141 
142 @("opSliceAssign")
143 @safe unittest {
144     auto vec = vector("foo", "bar", "quux", "toto");
145 
146     vec[] = "haha";
147     vec[].shouldEqual(["haha", "haha", "haha", "haha"]);
148 
149     vec[1..3] = "oops";
150     vec[].shouldEqual(["haha", "oops", "oops", "haha"]);
151 }
152 
153 @("opSliceOpAssign")
154 @safe unittest {
155     auto vec = vector("foo", "bar", "quux", "toto");
156     vec[] ~= "oops";
157     vec[].shouldEqual(["foooops", "baroops", "quuxoops", "totooops"]);
158 }
159 
160 @("opSliceOpAssign range")
161 @safe unittest {
162     auto vec = vector("foo", "bar", "quux", "toto");
163     vec[1..3] ~= "oops";
164     vec[].shouldEqual(["foo", "baroops", "quuxoops", "toto"]);
165 }
166 
167 @("clear")
168 @safe unittest {
169     auto vec = vector(0, 1, 2, 3);
170     vec.clear;
171     int[] empty;
172     vec[].shouldEqual(empty);
173 }
174 
175 
176 @("Mallocator elements")
177 @safe @nogc unittest {
178     import std.algorithm: equal;
179     auto vec = vector!Mallocator(0, 1, 2, 3);
180     int[4] exp = [0, 1, 2, 3];
181     assert(equal(vec[], exp[]));
182 }
183 
184 @("Mallocator range")
185 @safe @nogc unittest {
186     import std.algorithm: equal;
187     import std.range: iota;
188     auto vec = vector!Mallocator(iota(5));
189     int[5] exp = [0, 1, 2, 3, 4];
190     assert(equal(vec[], exp[]));
191 }
192 
193 
194 @("theAllocator null")
195 @safe unittest {
196     Vector!int vec;
197 }
198 
199 
200 @("Mallocator null")
201 @safe @nogc unittest {
202     Vector!(int, Mallocator) vec;
203 }
204 
205 @("Cannot escape slice")
206 @safe @nogc unittest {
207     int[] ints1;
208     scope vec = vector!Mallocator(0, 1, 2, 3);
209     int[] ints2;
210 
211     static assert(!__traits(compiles, ints1 = vec[]));
212     static assert(__traits(compiles, ints2 = vec[]));
213 }
214 
215 
216 @("TestAllocator elements capacity")
217 @safe unittest {
218     static TestAllocator allocator;
219 
220     auto vec = vector(&allocator, 0, 1, 2);
221     vec[].shouldEqual([0, 1, 2]);
222 
223     vec ~= 3;
224     vec ~= 4;
225     vec ~= 5;
226     vec ~= 6;
227     vec ~= 7;
228     vec ~= 8;
229 
230     vec[].shouldEqual([0, 1, 2, 3, 4, 5, 6, 7, 8]);
231     allocator.numAllocations.shouldBeSmallerThan(4);
232 }
233 
234 @("TestAllocator reserve")
235 @safe unittest {
236     static TestAllocator allocator;
237 
238     auto vec = vector!(TestAllocator*, int)(&allocator);
239 
240     vec.reserve(5);
241     () @trusted { vec.shouldBeEmpty; }();
242 
243     vec ~= 0;
244     vec ~= 1;
245     vec ~= 2;
246     vec ~= 3;
247     vec ~= 4;
248 
249     vec[].shouldEqual([0, 1, 2, 3, 4]);
250     allocator.numAllocations.should == 1;
251 
252     vec ~= 5;
253     vec[].shouldEqual([0, 1, 2, 3, 4, 5]);
254     allocator.numAllocations.should == 2;
255 }
256 
257 @("TestAllocator shrink no length")
258 @safe unittest {
259     static TestAllocator allocator;
260 
261     auto vec = vector!(TestAllocator*, int)(&allocator);
262     vec.reserve(10);
263 
264     vec ~= 0;
265     vec ~= 1;
266     vec ~= 2;
267     vec ~= 3;
268 
269     vec.length.should == 4;
270     vec.capacity.should == 10;
271 
272     vec.shrink;
273     vec.length.should == 4;
274     vec.capacity.should == 4;
275 }
276 
277 @("TestAllocator shrink negative number")
278 @safe unittest {
279     static TestAllocator allocator;
280 
281     auto vec = vector(&allocator, 0);
282     vec ~= 1;
283     vec ~= 2;
284     vec ~= 3;
285     vec.capacity.shouldBeGreaterThan(vec.length);
286     const oldCapacity = vec.capacity;
287 
288     vec.shrink(-1).shouldBeFalse;
289     vec.capacity.should == oldCapacity;
290 }
291 
292 @("TestAllocator shrink larger than capacity")
293 @safe unittest {
294     static TestAllocator allocator;
295 
296     auto vec = vector(&allocator, 0);
297     vec ~= 1;
298     vec ~= 2;
299     vec ~= 3;
300     vec.capacity.shouldBeGreaterThan(vec.length);
301     const oldCapacity = vec.capacity;
302 
303     vec.shrink(oldCapacity * 2).shouldBeFalse;
304     vec.capacity.should == oldCapacity;
305 }
306 
307 
308 @("TestAllocator shrink with length")
309 @safe unittest {
310     static TestAllocator allocator;
311 
312     auto vec = vector(&allocator, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
313     vec.capacity.should == 10;
314 
315     vec.shrink(5);
316     vec[].shouldEqual([0, 1, 2, 3, 4]);
317     vec.capacity.should == 5;
318 
319     vec ~= 5;
320     vec[].shouldEqual([0, 1, 2, 3, 4, 5]);
321     allocator.numAllocations.should == 3;
322 
323     vec.reserve(10);
324     vec.length.should == 6;
325     vec.capacity.shouldBeGreaterThan(6);
326 }
327 
328 @("TestAllocator copy")
329 @safe unittest {
330     static TestAllocator allocator;
331 
332     auto vec1 = vector(&allocator, "foo", "bar", "baz");
333     allocator.numAllocations.should == 1;
334 
335     auto vec2 = vec1;
336     allocator.numAllocations.should == 2;
337 }
338 
339 @("TestAllocator move")
340 @safe unittest {
341     static TestAllocator allocator;
342 
343     auto vec = vector(&allocator, "foo", "bar", "baz");
344     allocator.numAllocations.should == 1;
345 
346     consumeVec(vec);
347     allocator.numAllocations.should == 1;
348 }
349 
350 
351 private void consumeVec(T)(auto ref T vec) {
352 
353 }
354 
355 
356 @("set length")
357 @safe unittest {
358     Vector!int vec;
359     vec.length = 3;
360     vec[].shouldEqual([0, 0, 0]);
361 }