1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5  * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "mozilla/Move.h"
8 #include "mozilla/UniquePtr.h"
9 #include "mozilla/Vector.h"
10 
11 using mozilla::detail::VectorTesting;
12 using mozilla::MakeUnique;
13 using mozilla::Move;
14 using mozilla::UniquePtr;
15 using mozilla::Vector;
16 
17 struct mozilla::detail::VectorTesting
18 {
19   static void testReserved();
20   static void testConstRange();
21   static void testEmplaceBack();
22   static void testReverse();
23   static void testExtractRawBuffer();
24   static void testExtractOrCopyRawBuffer();
25 };
26 
27 void
testReserved()28 mozilla::detail::VectorTesting::testReserved()
29 {
30 #ifdef DEBUG
31   Vector<bool> bv;
32   MOZ_RELEASE_ASSERT(bv.reserved() == 0);
33 
34   MOZ_RELEASE_ASSERT(bv.append(true));
35   MOZ_RELEASE_ASSERT(bv.reserved() == 1);
36 
37   Vector<bool> otherbv;
38   MOZ_RELEASE_ASSERT(otherbv.append(false));
39   MOZ_RELEASE_ASSERT(otherbv.append(true));
40   MOZ_RELEASE_ASSERT(bv.appendAll(otherbv));
41   MOZ_RELEASE_ASSERT(bv.reserved() == 3);
42 
43   MOZ_RELEASE_ASSERT(bv.reserve(5));
44   MOZ_RELEASE_ASSERT(bv.reserved() == 5);
45 
46   MOZ_RELEASE_ASSERT(bv.reserve(1));
47   MOZ_RELEASE_ASSERT(bv.reserved() == 5);
48 
49   Vector<bool> bv2(Move(bv));
50   MOZ_RELEASE_ASSERT(bv.reserved() == 0);
51   MOZ_RELEASE_ASSERT(bv2.reserved() == 5);
52 
53   bv2.clearAndFree();
54   MOZ_RELEASE_ASSERT(bv2.reserved() == 0);
55 
56   Vector<int, 42> iv;
57   MOZ_RELEASE_ASSERT(iv.reserved() == 0);
58 
59   MOZ_RELEASE_ASSERT(iv.append(17));
60   MOZ_RELEASE_ASSERT(iv.reserved() == 1);
61 
62   Vector<int, 42> otheriv;
63   MOZ_RELEASE_ASSERT(otheriv.append(42));
64   MOZ_RELEASE_ASSERT(otheriv.append(37));
65   MOZ_RELEASE_ASSERT(iv.appendAll(otheriv));
66   MOZ_RELEASE_ASSERT(iv.reserved() == 3);
67 
68   MOZ_RELEASE_ASSERT(iv.reserve(5));
69   MOZ_RELEASE_ASSERT(iv.reserved() == 5);
70 
71   MOZ_RELEASE_ASSERT(iv.reserve(1));
72   MOZ_RELEASE_ASSERT(iv.reserved() == 5);
73 
74   MOZ_RELEASE_ASSERT(iv.reserve(55));
75   MOZ_RELEASE_ASSERT(iv.reserved() == 55);
76 
77   Vector<int, 42> iv2(Move(iv));
78   MOZ_RELEASE_ASSERT(iv.reserved() == 0);
79   MOZ_RELEASE_ASSERT(iv2.reserved() == 55);
80 
81   iv2.clearAndFree();
82   MOZ_RELEASE_ASSERT(iv2.reserved() == 0);
83 #endif
84 }
85 
86 void
testConstRange()87 mozilla::detail::VectorTesting::testConstRange()
88 {
89 #ifdef DEBUG
90   Vector<int> vec;
91 
92   for (int i = 0; i < 10; i++) {
93     MOZ_RELEASE_ASSERT(vec.append(i));
94   }
95 
96   const auto &vecRef = vec;
97 
98   Vector<int>::ConstRange range = vecRef.all();
99   for (int i = 0; i < 10; i++) {
100     MOZ_RELEASE_ASSERT(!range.empty());
101     MOZ_RELEASE_ASSERT(range.front() == i);
102     range.popFront();
103   }
104 #endif
105 }
106 
107 namespace {
108 
109 struct S
110 {
111   size_t            j;
112   UniquePtr<size_t> k;
113 
114   static size_t constructCount;
115   static size_t moveCount;
116   static size_t destructCount;
117 
resetCounts__anon9d01b3e40111::S118   static void resetCounts() {
119     constructCount = 0;
120     moveCount = 0;
121     destructCount = 0;
122   }
123 
S__anon9d01b3e40111::S124   S(size_t j, size_t k)
125     : j(j)
126     , k(MakeUnique<size_t>(k))
127   {
128     constructCount++;
129   }
130 
S__anon9d01b3e40111::S131   S(S&& rhs)
132     : j(rhs.j)
133     , k(Move(rhs.k))
134   {
135     rhs.j = 0;
136     rhs.k.reset(0);
137     moveCount++;
138   }
139 
~S__anon9d01b3e40111::S140   ~S() {
141     destructCount++;
142   }
143 
144   S(const S&) = delete;
145   S& operator=(const S&) = delete;
146 };
147 
148 size_t S::constructCount = 0;
149 size_t S::moveCount = 0;
150 size_t S::destructCount = 0;
151 
152 }
153 
154 void
testEmplaceBack()155 mozilla::detail::VectorTesting::testEmplaceBack()
156 {
157   S::resetCounts();
158 
159   Vector<S> vec;
160   MOZ_RELEASE_ASSERT(vec.reserve(20));
161 
162   for (size_t i = 0; i < 10; i++) {
163     S s(i, i * i);
164     MOZ_RELEASE_ASSERT(vec.append(Move(s)));
165   }
166 
167   MOZ_RELEASE_ASSERT(vec.length() == 10);
168   MOZ_RELEASE_ASSERT(S::constructCount == 10);
169   MOZ_RELEASE_ASSERT(S::moveCount == 10);
170 
171   for (size_t i = 10; i < 20; i++) {
172     MOZ_RELEASE_ASSERT(vec.emplaceBack(i, i * i));
173   }
174 
175   MOZ_RELEASE_ASSERT(vec.length() == 20);
176   MOZ_RELEASE_ASSERT(S::constructCount == 20);
177   MOZ_RELEASE_ASSERT(S::moveCount == 10);
178 
179   for (size_t i = 0; i < 20; i++) {
180     MOZ_RELEASE_ASSERT(vec[i].j == i);
181     MOZ_RELEASE_ASSERT(*vec[i].k == i * i);
182   }
183 }
184 
185 void
testReverse()186 mozilla::detail::VectorTesting::testReverse()
187 {
188   // Use UniquePtr to make sure that reverse() can handler move-only types.
189   Vector<UniquePtr<uint8_t>, 0> vec;
190 
191   // Reverse an odd number of elements.
192 
193   for (uint8_t i = 0; i < 5; i++) {
194     auto p = MakeUnique<uint8_t>(i);
195     MOZ_RELEASE_ASSERT(p);
196     MOZ_RELEASE_ASSERT(vec.append(mozilla::Move(p)));
197   }
198 
199   vec.reverse();
200 
201   MOZ_RELEASE_ASSERT(*vec[0] == 4);
202   MOZ_RELEASE_ASSERT(*vec[1] == 3);
203   MOZ_RELEASE_ASSERT(*vec[2] == 2);
204   MOZ_RELEASE_ASSERT(*vec[3] == 1);
205   MOZ_RELEASE_ASSERT(*vec[4] == 0);
206 
207   // Reverse an even number of elements.
208 
209   vec.popBack();
210   vec.reverse();
211 
212   MOZ_RELEASE_ASSERT(*vec[0] == 1);
213   MOZ_RELEASE_ASSERT(*vec[1] == 2);
214   MOZ_RELEASE_ASSERT(*vec[2] == 3);
215   MOZ_RELEASE_ASSERT(*vec[3] == 4);
216 
217   // Reverse an empty vector.
218 
219   vec.clear();
220   MOZ_RELEASE_ASSERT(vec.length() == 0);
221   vec.reverse();
222   MOZ_RELEASE_ASSERT(vec.length() == 0);
223 
224   // Reverse a vector using only inline storage.
225 
226   Vector<UniquePtr<uint8_t>, 5> vec2;
227   for (uint8_t i = 0; i < 5; i++) {
228     auto p = MakeUnique<uint8_t>(i);
229     MOZ_RELEASE_ASSERT(p);
230     MOZ_RELEASE_ASSERT(vec2.append(mozilla::Move(p)));
231   }
232 
233   vec2.reverse();
234 
235   MOZ_RELEASE_ASSERT(*vec2[0] == 4);
236   MOZ_RELEASE_ASSERT(*vec2[1] == 3);
237   MOZ_RELEASE_ASSERT(*vec2[2] == 2);
238   MOZ_RELEASE_ASSERT(*vec2[3] == 1);
239   MOZ_RELEASE_ASSERT(*vec2[4] == 0);
240 }
241 
242 void
testExtractRawBuffer()243 mozilla::detail::VectorTesting::testExtractRawBuffer()
244 {
245   S::resetCounts();
246 
247   Vector<S, 5> vec;
248   MOZ_RELEASE_ASSERT(vec.reserve(5));
249   for (size_t i = 0; i < 5; i++) {
250     vec.infallibleEmplaceBack(i, i * i);
251   }
252   MOZ_RELEASE_ASSERT(vec.length() == 5);
253   MOZ_ASSERT(vec.reserved() == 5);
254   MOZ_RELEASE_ASSERT(S::constructCount == 5);
255   MOZ_RELEASE_ASSERT(S::moveCount == 0);
256   MOZ_RELEASE_ASSERT(S::destructCount == 0);
257 
258   S* buf = vec.extractRawBuffer();
259   MOZ_RELEASE_ASSERT(!buf);
260   MOZ_RELEASE_ASSERT(vec.length() == 5);
261   MOZ_ASSERT(vec.reserved() == 5);
262   MOZ_RELEASE_ASSERT(S::constructCount == 5);
263   MOZ_RELEASE_ASSERT(S::moveCount == 0);
264   MOZ_RELEASE_ASSERT(S::destructCount == 0);
265 
266   MOZ_RELEASE_ASSERT(vec.reserve(10));
267   for (size_t i = 5; i < 10; i++) {
268     vec.infallibleEmplaceBack(i, i * i);
269   }
270   MOZ_RELEASE_ASSERT(vec.length() == 10);
271   MOZ_ASSERT(vec.reserved() == 10);
272   MOZ_RELEASE_ASSERT(S::constructCount == 10);
273   MOZ_RELEASE_ASSERT(S::moveCount == 5);
274   MOZ_RELEASE_ASSERT(S::destructCount == 5);
275 
276   buf = vec.extractRawBuffer();
277   MOZ_RELEASE_ASSERT(buf);
278   MOZ_RELEASE_ASSERT(vec.length() == 0);
279   MOZ_ASSERT(vec.reserved() == 0);
280   MOZ_RELEASE_ASSERT(S::constructCount == 10);
281   MOZ_RELEASE_ASSERT(S::moveCount == 5);
282   MOZ_RELEASE_ASSERT(S::destructCount == 5);
283 
284   for (size_t i = 0; i < 10; i++) {
285     MOZ_RELEASE_ASSERT(buf[i].j == i);
286     MOZ_RELEASE_ASSERT(*buf[i].k == i * i);
287   }
288 
289   free(buf);
290 }
291 
292 void
testExtractOrCopyRawBuffer()293 mozilla::detail::VectorTesting::testExtractOrCopyRawBuffer()
294 {
295   S::resetCounts();
296 
297   Vector<S, 5> vec;
298   MOZ_RELEASE_ASSERT(vec.reserve(5));
299   for (size_t i = 0; i < 5; i++) {
300     vec.infallibleEmplaceBack(i, i * i);
301   }
302   MOZ_RELEASE_ASSERT(vec.length() == 5);
303   MOZ_ASSERT(vec.reserved() == 5);
304   MOZ_RELEASE_ASSERT(S::constructCount == 5);
305   MOZ_RELEASE_ASSERT(S::moveCount == 0);
306   MOZ_RELEASE_ASSERT(S::destructCount == 0);
307 
308   S* buf = vec.extractOrCopyRawBuffer();
309   MOZ_RELEASE_ASSERT(buf);
310   MOZ_RELEASE_ASSERT(vec.length() == 0);
311   MOZ_ASSERT(vec.reserved() == 0);
312   MOZ_RELEASE_ASSERT(S::constructCount == 5);
313   MOZ_RELEASE_ASSERT(S::moveCount == 5);
314   MOZ_RELEASE_ASSERT(S::destructCount == 5);
315 
316   for (size_t i = 0; i < 5; i++) {
317     MOZ_RELEASE_ASSERT(buf[i].j == i);
318     MOZ_RELEASE_ASSERT(*buf[i].k == i * i);
319   }
320 
321   S::resetCounts();
322 
323   MOZ_RELEASE_ASSERT(vec.reserve(10));
324   for (size_t i = 0; i < 10; i++) {
325     vec.infallibleEmplaceBack(i, i * i);
326   }
327   MOZ_RELEASE_ASSERT(vec.length() == 10);
328   MOZ_ASSERT(vec.reserved() == 10);
329   MOZ_RELEASE_ASSERT(S::constructCount == 10);
330   MOZ_RELEASE_ASSERT(S::moveCount == 0);
331   MOZ_RELEASE_ASSERT(S::destructCount == 0);
332 
333   buf = vec.extractOrCopyRawBuffer();
334   MOZ_RELEASE_ASSERT(buf);
335   MOZ_RELEASE_ASSERT(vec.length() == 0);
336   MOZ_ASSERT(vec.reserved() == 0);
337   MOZ_RELEASE_ASSERT(S::constructCount == 10);
338   MOZ_RELEASE_ASSERT(S::moveCount == 0);
339   MOZ_RELEASE_ASSERT(S::destructCount == 0);
340 
341   for (size_t i = 0; i < 10; i++) {
342     MOZ_RELEASE_ASSERT(buf[i].j == i);
343     MOZ_RELEASE_ASSERT(*buf[i].k == i * i);
344   }
345 
346   free(buf);
347 }
348 
349 int
main()350 main()
351 {
352   VectorTesting::testReserved();
353   VectorTesting::testConstRange();
354   VectorTesting::testEmplaceBack();
355   VectorTesting::testReverse();
356   VectorTesting::testExtractRawBuffer();
357   VectorTesting::testExtractOrCopyRawBuffer();
358 }
359