1 module ut.unique_array;
2 
3 import ut;
4 import automem.unique_array;
5 
6 mixin TestUtils;
7 
8 @("default TestAllocator")
9 @system unittest {
10     defaultTest!TestAllocator;
11 }
12 
13 
14 @("default Mallocator")
15 @system unittest {
16     import stdx.allocator.mallocator: Mallocator;
17     defaultTest!Mallocator;
18 }
19 
20 private void defaultTest(T)() {
21     import std.algorithm: move;
22     import std.traits: hasMember;
23 
24     enum isGlobal = hasMember!(T, "instance");
25 
26     static if(isGlobal) {
27         alias allocator = T.instance;
28         alias Allocator = T;
29     } else {
30         auto allocator = T();
31         alias Allocator = T*;
32     }
33 
34     auto makeUniqueArray(T, A1, A2, Args...)(ref A2 allocator, Args args) {
35 
36         import std.traits: isPointer, hasMember;
37 
38         enum isGlobal = hasMember!(A1, "instance");
39 
40         static if(isGlobal)
41             return UniqueArray!(T, A1)(args);
42         else static if(isPointer!A1)
43             return UniqueArray!(T, A1)(&allocator, args);
44         else
45             return UniqueArray!(T, A1)(allocator, args);
46     }
47 
48     auto ptr = makeUniqueArray!(Struct, Allocator)(allocator, 3);
49     ptr.length.shouldEqual(3);
50 
51     ptr[2].twice.shouldEqual(0);  // Struct.init
52     ptr[2] = Struct(5);
53     ptr[2].twice.shouldEqual(10);
54 
55     ptr[1..$].shouldEqual([Struct(), Struct(5)]);
56 
57     typeof(ptr) ptr2 = ptr.move;
58 
59     ptr.length.shouldEqual(0);  // moved from
60     (cast(bool)ptr).shouldBeFalse;
61     ptr2.length.shouldEqual(3);
62     (cast(bool)ptr2).shouldBeTrue;
63 
64     // not copyable
65     static assert(!__traits(compiles, ptr2 = ptr1));
66 
67     auto ptr3 = ptr2.unique;  // same as move
68     ptr3.length.shouldEqual(3);
69     ptr3.shouldEqual([Struct(), Struct(), Struct(5)]);
70     (*ptr3).shouldEqual([Struct(), Struct(), Struct(5)]);
71 
72     ptr3 ~= Struct(10);
73     ptr3.shouldEqual([Struct(), Struct(), Struct(5), Struct(10)]);
74 
75     ptr3 ~= [Struct(11), Struct(12)];
76     ptr3.shouldEqual([Struct(), Struct(), Struct(5), Struct(10), Struct(11), Struct(12)]);
77 
78     ptr3.length = 3;
79     ptr3.shouldEqual([Struct(), Struct(), Struct(5)]);
80 
81     ptr3.length = 4;
82     ptr3.shouldEqual([Struct(), Struct(), Struct(5), Struct()]);
83 
84     ptr3.length = 1;
85 
86     ptr3 ~= makeUniqueArray!(Struct, Allocator)(allocator, 1);
87 
88     ptr3.shouldEqual([Struct(), Struct()]);
89 
90     auto ptr4 = makeUniqueArray!(Struct, Allocator)(allocator, 1);
91 
92     ptr3 ~= ptr4.unique;
93     ptr3.shouldEqual([Struct(), Struct(), Struct()]);
94 
95     ptr3 = [Struct(7), Struct(9)];
96     ptr3.shouldEqual([Struct(7), Struct(9)]);
97 }
98 
99 ///
100 @("@nogc")
101 @system @nogc unittest {
102 
103     import stdx.allocator.mallocator: Mallocator;
104 
105     auto arr = UniqueArray!(NoGcStruct, Mallocator)(2);
106     assert(arr.length == 2);
107 
108     arr[0] = NoGcStruct(1);
109     arr[1] = NoGcStruct(3);
110 
111     {
112         NoGcStruct[2] expected = [NoGcStruct(1), NoGcStruct(3)];
113         assert(arr == expected);
114     }
115 
116     auto arr2 = UniqueArray!(NoGcStruct, Mallocator)(1);
117     arr ~= arr2.unique;
118 
119     {
120         NoGcStruct[3] expected = [NoGcStruct(1), NoGcStruct(3), NoGcStruct()];
121         assert(arr == expected);
122     }
123 }
124 
125 @("@nogc @safe")
126 @safe @nogc unittest {
127     auto allocator = SafeAllocator();
128     auto arr = UniqueArray!(NoGcStruct, SafeAllocator)(SafeAllocator(), 6);
129     assert(arr.length == 6);
130     arr ~= NoGcStruct();
131     assert(arr.length == 7);
132 }
133 
134 
135 @("init TestAllocator")
136 @system unittest {
137     auto allocator = TestAllocator();
138     auto arr = UniqueArray!(Struct, TestAllocator*)(&allocator, 2, Struct(7));
139     arr.shouldEqual([Struct(7), Struct(7)]);
140 }
141 
142 @("init Mallocator")
143 @system unittest {
144     import stdx.allocator.mallocator: Mallocator;
145     alias allocator = Mallocator.instance;
146     auto arr = UniqueArray!(Struct, Mallocator)(2, Struct(7));
147     arr.shouldEqual([Struct(7), Struct(7)]);
148 }
149 
150 
151 @("range TestAllocator")
152 @system unittest {
153     auto allocator = TestAllocator();
154     auto arr = UniqueArray!(Struct, TestAllocator*)(&allocator, [Struct(1), Struct(2)]);
155     arr.shouldEqual([Struct(1), Struct(2)]);
156 }
157 
158 @("range Mallocator")
159 @system unittest {
160     import stdx.allocator.mallocator: Mallocator;
161     auto arr = UniqueArray!(Struct, Mallocator)([Struct(1), Struct(2)]);
162     arr.shouldEqual([Struct(1), Struct(2)]);
163 }
164 
165 
166 @("theAllocator")
167 @system unittest {
168     with(theTestAllocator) {
169         auto arr = UniqueArray!Struct(2);
170         arr.shouldEqual([Struct(), Struct()]);
171     }
172 }
173 
174 @("issue 1 array")
175 @system unittest {
176     import stdx.allocator.mallocator;
177     UniqueArray!(int, Mallocator) a;
178     a ~= [0, 1];
179 }
180 
181 @("issue 1 value")
182 @system unittest {
183     import stdx.allocator.mallocator;
184     UniqueArray!(int, Mallocator) a;
185     a ~= 7;
186 }
187 
188 @("issue 1 UniqueArray")
189 @system unittest {
190     import stdx.allocator.mallocator;
191     UniqueArray!(int, Mallocator) a;
192     a ~= UniqueArray!(int, Mallocator)([1, 2, 3]);
193 }
194 
195 @("dereference")
196 unittest {
197     import stdx.allocator.mallocator;
198     UniqueArray!(int, Mallocator) a;
199     a ~= [0, 1];
200     (*a).shouldEqual([0, 1]);
201 }
202 
203 @("reserve from nothing")
204 @system unittest {
205     auto allocator = TestAllocator();
206     auto a = UniqueArray!(int, TestAllocator*)(&allocator);
207     a.reserve(10); //allocates here
208     a ~= [1, 2, 3]; // should not allocate
209     a ~= [4, 5, 6, 7, 8, 9]; //should not allocate
210     a.shouldEqual([1, 2, 3, 4, 5, 6, 7, 8, 9]);
211     allocator.numAllocations.shouldEqual(1);
212 }
213 
214 @("reserve from existing expand")
215 @system unittest {
216     auto allocator = TestAllocator();
217     auto a = UniqueArray!(int, TestAllocator*)(&allocator, [1, 2]); //allocates here
218     a.reserve(10); //allocates here
219     a ~= [3, 4]; // should not allocate
220     a ~= [5, 6, 7, 8, 9]; //should not allocate
221     a.shouldEqual([1, 2, 3, 4, 5, 6, 7, 8, 9]);
222     allocator.numAllocations.shouldEqual(2);
223 }
224 
225 @("reserve from existing reduce")
226 @system unittest {
227     auto allocator = TestAllocator();
228     auto a = UniqueArray!(int, TestAllocator*)(&allocator, [1, 2, 3, 4, 5]); //allocates here
229     a.reserve(2); // should not allocate, changes length to 2
230     a ~= [5, 6];  // should not allocate
231     a.shouldEqual([1, 2, 5, 6]);
232     allocator.numAllocations.shouldEqual(1);
233 }
234 
235 @("Append 2 arrays")
236 @system unittest {
237     auto allocator = TestAllocator();
238     auto a = UniqueArray!(int, TestAllocator*)(&allocator, [1, 2, 3]) ~
239              UniqueArray!(int, TestAllocator*)(&allocator, [4, 5]);
240     a.shouldEqual([1, 2, 3, 4, 5]);
241 }
242 
243 @("ptr")
244 @system unittest {
245     auto allocator = TestAllocator();
246     auto a = UniqueArray!(int, TestAllocator*)(&allocator, [1, 2, 3, 4, 5]);
247     auto ptr = a.ptr;
248     ++ptr;
249     (*ptr).shouldEqual(2);
250 }
251 
252 @("dup TestAllocator")
253 @system unittest {
254     auto allocator = TestAllocator();
255     auto a = UniqueArray!(int, TestAllocator*)(&allocator, [1, 2, 3, 4, 5]);
256     auto b = a.dup;
257     allocator.numAllocations.shouldEqual(2);
258     b.shouldEqual([1, 2, 3, 4, 5]);
259 }
260 
261 @("dup Mallocator")
262 @system unittest {
263     import stdx.allocator.mallocator: Mallocator;
264     auto a = UniqueArray!(int, Mallocator)([1, 2, 3, 4, 5]);
265     auto b = a.dup;
266     b.shouldEqual([1, 2, 3, 4, 5]);
267 }
268 
269 @("dup TestAllocator indirections")
270 @system unittest {
271     auto allocator = TestAllocator();
272     static struct String { string s; }
273     auto a = UniqueArray!(String, TestAllocator*)(&allocator, [String("foo"), String("bar")]);
274     auto b = a.dup;
275     a[0] = String("quux");
276     a[1] = String("toto");
277     allocator.numAllocations.shouldEqual(2);
278     a.shouldEqual([String("quux"), String("toto")]);
279     b.shouldEqual([String("foo"), String("bar")]);
280 }
281 
282 @("Set length to the same length")
283 unittest {
284     auto allocator = TestAllocator();
285     auto a = UniqueArray!(Struct, TestAllocator*)(&allocator, [Struct(2), Struct(3)]);
286     a.length = 2;
287 }
288 
289 @("UniqueString TestAllocator append")
290 @safe unittest {
291     auto allocator = TestAllocator();
292     auto allocatorPtr = () @trusted { return &allocator; }();
293     auto str = UniqueString!(TestAllocator*)(allocatorPtr);
294     str ~= 'f';
295     str ~= 'o';
296     str ~= 'o';
297     str.shouldEqual("foo");
298 }
299 
300 @("UniqueString TestAllocator init with string")
301 @safe unittest {
302     auto allocator = TestAllocator();
303     auto allocatorPtr = () @trusted { return &allocator; }();
304     auto str = UniqueString!(TestAllocator*)(allocatorPtr, "foobar");
305     str.shouldEqual("foobar");
306 }