Bug 1577282 - Part 2: Move functions outside of the Spectrum prototype. r=Maliha
[gecko.git] / mfbt / tests / TestUniquePtr.cpp
blob780607147aedee6019b94ed6d1e8a88e844a4c54
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/. */
7 #include "mozilla/Assertions.h"
8 #include "mozilla/Compiler.h"
9 #include "mozilla/Move.h"
10 #include "mozilla/TypeTraits.h"
11 #include "mozilla/UniquePtr.h"
12 #include "mozilla/UniquePtrExtensions.h"
13 #include "mozilla/Vector.h"
15 #include <stddef.h>
17 using mozilla::DefaultDelete;
18 using mozilla::IsSame;
19 using mozilla::MakeUnique;
20 using mozilla::Swap;
21 using mozilla::UniqueFreePtr;
22 using mozilla::UniquePtr;
23 using mozilla::Vector;
25 #define CHECK(c) \
26 do { \
27 bool cond = !!(c); \
28 MOZ_ASSERT(cond, "Failed assertion: " #c); \
29 if (!cond) { \
30 return false; \
31 } \
32 } while (false)
34 typedef UniquePtr<int> NewInt;
35 static_assert(sizeof(NewInt) == sizeof(int*), "stored most efficiently");
37 static size_t gADestructorCalls = 0;
39 struct A {
40 public:
41 A() : mX(0) {}
42 virtual ~A() { gADestructorCalls++; }
44 int mX;
47 static size_t gBDestructorCalls = 0;
49 struct B : public A {
50 public:
51 B() : mY(1) {}
52 ~B() { gBDestructorCalls++; }
54 int mY;
57 typedef UniquePtr<A> UniqueA;
58 typedef UniquePtr<B, UniqueA::DeleterType> UniqueB; // permit interconversion
60 static_assert(sizeof(UniqueA) == sizeof(A*), "stored most efficiently");
61 static_assert(sizeof(UniqueB) == sizeof(B*), "stored most efficiently");
63 struct DeleterSubclass : UniqueA::DeleterType {};
65 typedef UniquePtr<B, DeleterSubclass> UniqueC;
66 static_assert(sizeof(UniqueC) == sizeof(B*), "stored most efficiently");
68 static UniqueA ReturnUniqueA() { return UniqueA(new B); }
70 static UniqueA ReturnLocalA() {
71 UniqueA a(new A);
72 return a;
75 static void TestDeleterType() {
76 // Make sure UniquePtr will use its deleter's pointer type if it defines one.
77 typedef int* Ptr;
78 struct Deleter {
79 typedef Ptr pointer;
80 Deleter() {}
81 void operator()(int* p) { delete p; }
83 UniquePtr<Ptr, Deleter> u(new int, Deleter());
86 static bool TestDefaultFreeGuts() {
87 static_assert(IsSame<NewInt::DeleterType, DefaultDelete<int> >::value,
88 "weird deleter?");
90 NewInt n1(new int);
91 CHECK(n1);
92 CHECK(n1.get() != nullptr);
94 n1 = nullptr;
95 CHECK(!n1);
96 CHECK(n1.get() == nullptr);
98 int* p1 = new int;
99 n1.reset(p1);
100 CHECK(n1);
101 NewInt n2(std::move(n1));
102 CHECK(!n1);
103 CHECK(n1.get() == nullptr);
104 CHECK(n2.get() == p1);
106 Swap(n1, n2);
107 CHECK(n1.get() == p1);
108 CHECK(n2.get() == nullptr);
110 n1.swap(n2);
111 CHECK(n1.get() == nullptr);
112 CHECK(n2.get() == p1);
113 delete n2.release();
115 CHECK(n1.get() == nullptr);
116 CHECK(n2 == nullptr);
117 CHECK(nullptr == n2);
119 int* p2 = new int;
120 int* p3 = new int;
121 n1.reset(p2);
122 n2.reset(p3);
123 CHECK(n1.get() == p2);
124 CHECK(n2.get() == p3);
126 n1.swap(n2);
127 CHECK(n2 != nullptr);
128 CHECK(nullptr != n2);
129 CHECK(n2.get() == p2);
130 CHECK(n1.get() == p3);
132 UniqueA a1;
133 CHECK(a1 == nullptr);
134 a1.reset(new A);
135 CHECK(gADestructorCalls == 0);
136 CHECK(a1->mX == 0);
138 B* bp1 = new B;
139 bp1->mX = 5;
140 CHECK(gBDestructorCalls == 0);
141 a1.reset(bp1);
142 CHECK(gADestructorCalls == 1);
143 CHECK(a1->mX == 5);
144 a1.reset(nullptr);
145 CHECK(gADestructorCalls == 2);
146 CHECK(gBDestructorCalls == 1);
148 B* bp2 = new B;
149 UniqueB b1(bp2);
150 UniqueA a2(nullptr);
151 a2 = std::move(b1);
152 CHECK(gADestructorCalls == 2);
153 CHECK(gBDestructorCalls == 1);
155 UniqueA a3(std::move(a2));
156 a3 = nullptr;
157 CHECK(gADestructorCalls == 3);
158 CHECK(gBDestructorCalls == 2);
160 B* bp3 = new B;
161 bp3->mX = 42;
162 UniqueB b2(bp3);
163 UniqueA a4(std::move(b2));
164 CHECK(b2.get() == nullptr);
165 CHECK((*a4).mX == 42);
166 CHECK(gADestructorCalls == 3);
167 CHECK(gBDestructorCalls == 2);
169 UniqueA a5(new A);
170 UniqueB b3(new B);
171 a5 = std::move(b3);
172 CHECK(gADestructorCalls == 4);
173 CHECK(gBDestructorCalls == 2);
175 ReturnUniqueA();
176 CHECK(gADestructorCalls == 5);
177 CHECK(gBDestructorCalls == 3);
179 ReturnLocalA();
180 CHECK(gADestructorCalls == 6);
181 CHECK(gBDestructorCalls == 3);
183 UniqueA a6(ReturnLocalA());
184 a6 = nullptr;
185 CHECK(gADestructorCalls == 7);
186 CHECK(gBDestructorCalls == 3);
188 UniqueC c1(new B);
189 UniqueA a7(new B);
190 a7 = std::move(c1);
191 CHECK(gADestructorCalls == 8);
192 CHECK(gBDestructorCalls == 4);
194 c1.reset(new B);
196 UniqueA a8(std::move(c1));
197 CHECK(gADestructorCalls == 8);
198 CHECK(gBDestructorCalls == 4);
200 // These smart pointers still own B resources.
201 CHECK(a4);
202 CHECK(a5);
203 CHECK(a7);
204 CHECK(a8);
205 return true;
208 static bool TestDefaultFree() {
209 CHECK(TestDefaultFreeGuts());
210 CHECK(gADestructorCalls == 12);
211 CHECK(gBDestructorCalls == 8);
212 return true;
215 static size_t FreeClassCounter = 0;
217 struct FreeClass {
218 public:
219 FreeClass() {}
221 void operator()(int* aPtr) {
222 FreeClassCounter++;
223 delete aPtr;
227 typedef UniquePtr<int, FreeClass> NewIntCustom;
228 static_assert(sizeof(NewIntCustom) == sizeof(int*), "stored most efficiently");
230 static bool TestFreeClass() {
231 CHECK(FreeClassCounter == 0);
233 NewIntCustom n1(new int);
234 CHECK(FreeClassCounter == 0);
236 CHECK(FreeClassCounter == 1);
238 NewIntCustom n2;
240 NewIntCustom n3(new int);
241 CHECK(FreeClassCounter == 1);
242 n2 = std::move(n3);
244 CHECK(FreeClassCounter == 1);
245 n2 = nullptr;
246 CHECK(FreeClassCounter == 2);
248 n2.reset(nullptr);
249 CHECK(FreeClassCounter == 2);
250 n2.reset(new int);
251 n2.reset();
252 CHECK(FreeClassCounter == 3);
254 NewIntCustom n4(new int, FreeClass());
255 CHECK(FreeClassCounter == 3);
256 n4.reset(new int);
257 CHECK(FreeClassCounter == 4);
258 n4.reset();
259 CHECK(FreeClassCounter == 5);
261 FreeClass f;
262 NewIntCustom n5(new int, f);
263 CHECK(FreeClassCounter == 5);
264 int* p = n5.release();
265 CHECK(FreeClassCounter == 5);
266 delete p;
268 return true;
271 typedef UniquePtr<int, DefaultDelete<int>&> IntDeleterRef;
272 typedef UniquePtr<A, DefaultDelete<A>&> ADeleterRef;
273 typedef UniquePtr<B, DefaultDelete<A>&> BDeleterRef;
275 static_assert(sizeof(IntDeleterRef) > sizeof(int*),
276 "has to be heavier than an int* to store the reference");
277 static_assert(sizeof(ADeleterRef) > sizeof(A*),
278 "has to be heavier than an A* to store the reference");
279 static_assert(sizeof(BDeleterRef) > sizeof(int*),
280 "has to be heavier than a B* to store the reference");
282 static bool TestReferenceDeleterGuts() {
283 DefaultDelete<int> delInt;
284 IntDeleterRef id1(new int, delInt);
286 IntDeleterRef id2(std::move(id1));
287 CHECK(id1 == nullptr);
288 CHECK(nullptr != id2);
289 CHECK(&id1.get_deleter() == &id2.get_deleter());
291 IntDeleterRef id3(std::move(id2));
293 DefaultDelete<A> delA;
294 ADeleterRef a1(new A, delA);
295 a1.reset(nullptr);
296 a1.reset(new B);
297 a1 = nullptr;
299 BDeleterRef b1(new B, delA);
300 a1 = std::move(b1);
302 BDeleterRef b2(new B, delA);
304 ADeleterRef a2(std::move(b2));
306 return true;
309 static bool TestReferenceDeleter() {
310 gADestructorCalls = 0;
311 gBDestructorCalls = 0;
313 CHECK(TestReferenceDeleterGuts());
315 CHECK(gADestructorCalls == 4);
316 CHECK(gBDestructorCalls == 3);
318 gADestructorCalls = 0;
319 gBDestructorCalls = 0;
320 return true;
323 typedef void (&FreeSignature)(void*);
325 static size_t DeleteIntFunctionCallCount = 0;
327 static void DeleteIntFunction(void* aPtr) {
328 DeleteIntFunctionCallCount++;
329 delete static_cast<int*>(aPtr);
332 static void SetMallocedInt(UniquePtr<int, FreeSignature>& aPtr, int aI) {
333 int* newPtr = static_cast<int*>(malloc(sizeof(int)));
334 *newPtr = aI;
335 aPtr.reset(newPtr);
338 static UniquePtr<int, FreeSignature> MallocedInt(int aI) {
339 UniquePtr<int, FreeSignature> ptr(static_cast<int*>(malloc(sizeof(int))),
340 free);
341 *ptr = aI;
342 return ptr;
344 static bool TestFunctionReferenceDeleter() {
345 // Look for allocator mismatches and leaks to verify these bits
346 UniquePtr<int, FreeSignature> i1(MallocedInt(17));
347 CHECK(*i1 == 17);
349 SetMallocedInt(i1, 42);
350 CHECK(*i1 == 42);
352 // These bits use a custom deleter so we can instrument deletion.
354 UniquePtr<int, FreeSignature> i2 =
355 UniquePtr<int, FreeSignature>(new int(42), DeleteIntFunction);
356 CHECK(DeleteIntFunctionCallCount == 0);
358 i2.reset(new int(76));
359 CHECK(DeleteIntFunctionCallCount == 1);
362 CHECK(DeleteIntFunctionCallCount == 2);
364 return true;
367 template <typename T>
368 struct AppendNullptrTwice {
369 AppendNullptrTwice() {}
371 bool operator()(Vector<T>& vec) {
372 CHECK(vec.append(nullptr));
373 CHECK(vec.append(nullptr));
374 return true;
378 static size_t AAfter;
379 static size_t BAfter;
381 static bool TestVectorGuts() {
382 Vector<UniqueA> vec;
383 CHECK(vec.append(new B));
384 CHECK(vec.append(new A));
385 CHECK(AppendNullptrTwice<UniqueA>()(vec));
386 CHECK(vec.append(new B));
388 size_t initialLength = vec.length();
390 UniqueA* begin = vec.begin();
391 bool appendA = true;
392 do {
393 CHECK(appendA ? vec.append(new A) : vec.append(new B));
394 appendA = !appendA;
395 } while (begin == vec.begin());
397 size_t numAppended = vec.length() - initialLength;
399 BAfter = numAppended / 2;
400 AAfter = numAppended - numAppended / 2;
402 CHECK(gADestructorCalls == 0);
403 CHECK(gBDestructorCalls == 0);
404 return true;
407 static bool TestVector() {
408 gADestructorCalls = 0;
409 gBDestructorCalls = 0;
411 CHECK(TestVectorGuts());
413 CHECK(gADestructorCalls == 3 + AAfter + BAfter);
414 CHECK(gBDestructorCalls == 2 + BAfter);
415 return true;
418 typedef UniquePtr<int[]> IntArray;
419 static_assert(sizeof(IntArray) == sizeof(int*), "stored most efficiently");
421 static bool TestArray() {
422 static_assert(IsSame<IntArray::DeleterType, DefaultDelete<int[]> >::value,
423 "weird deleter?");
425 IntArray n1(new int[5]);
426 CHECK(n1);
427 CHECK(n1.get() != nullptr);
429 n1 = nullptr;
430 CHECK(!n1);
431 CHECK(n1.get() == nullptr);
433 int* p1 = new int[42];
434 n1.reset(p1);
435 CHECK(n1);
436 IntArray n2(std::move(n1));
437 CHECK(!n1);
438 CHECK(n1.get() == nullptr);
439 CHECK(n2.get() == p1);
441 Swap(n1, n2);
442 CHECK(n1.get() == p1);
443 CHECK(n2.get() == nullptr);
445 n1.swap(n2);
446 CHECK(n1.get() == nullptr);
447 CHECK(n2.get() == p1);
448 delete[] n2.release();
450 CHECK(n1.get() == nullptr);
451 CHECK(n2.get() == nullptr);
453 int* p2 = new int[7];
454 int* p3 = new int[42];
455 n1.reset(p2);
456 n2.reset(p3);
457 CHECK(n1.get() == p2);
458 CHECK(n2.get() == p3);
460 n1.swap(n2);
461 CHECK(n2.get() == p2);
462 CHECK(n1.get() == p3);
464 n1 = std::move(n2);
465 CHECK(n1.get() == p2);
466 n1 = std::move(n2);
467 CHECK(n1.get() == nullptr);
469 UniquePtr<A[]> a1(new A[17]);
470 static_assert(sizeof(a1) == sizeof(A*), "stored most efficiently");
472 UniquePtr<A[]> a2(new A[5], DefaultDelete<A[]>());
473 a2.reset(nullptr);
474 a2.reset(new A[17]);
475 a2 = nullptr;
477 UniquePtr<A[]> a3(nullptr);
478 a3.reset(new A[7]);
480 return true;
483 struct Q {
484 Q() {}
485 Q(const Q&) {}
487 Q(Q&, char) {}
489 template <typename T>
490 Q(Q, T&&, int) {}
492 Q(int, long, double, void*) {}
495 static int randomInt() { return 4; }
497 static bool TestMakeUnique() {
498 UniquePtr<int> a1(MakeUnique<int>());
499 UniquePtr<long> a2(MakeUnique<long>(4));
501 // no args, easy
502 UniquePtr<Q> q0(MakeUnique<Q>());
504 // temporary bound to const lval ref
505 UniquePtr<Q> q1(MakeUnique<Q>(Q()));
507 // passing through a non-const lval ref
508 UniquePtr<Q> q2(MakeUnique<Q>(*q1, 'c'));
510 // pass by copying, forward a temporary, pass by value
511 UniquePtr<Q> q3(MakeUnique<Q>(Q(), UniquePtr<int>(), randomInt()));
513 // various type mismatching to test "fuzzy" forwarding
514 UniquePtr<Q> q4(MakeUnique<Q>('s', 66LL, 3.141592654, &q3));
516 UniquePtr<char[]> c1(MakeUnique<char[]>(5));
518 return true;
521 static bool TestVoid() {
522 // UniquePtr<void> supports all operations except operator*() and
523 // operator->().
524 UniqueFreePtr<void> p1(malloc(1));
525 UniqueFreePtr<void> p2;
527 auto x = p1.get();
528 CHECK(x != nullptr);
529 CHECK((IsSame<decltype(x), void*>::value));
531 p2.reset(p1.release());
532 CHECK(p1.get() == nullptr);
533 CHECK(p2.get() != nullptr);
535 p1 = std::move(p2);
536 CHECK(p1);
537 CHECK(!p2);
539 p1.swap(p2);
540 CHECK(!p1);
541 CHECK(p2);
543 p2 = nullptr;
544 CHECK(!p2);
546 return true;
549 int main() {
550 TestDeleterType();
552 if (!TestDefaultFree()) {
553 return 1;
555 if (!TestFreeClass()) {
556 return 1;
558 if (!TestReferenceDeleter()) {
559 return 1;
561 if (!TestFunctionReferenceDeleter()) {
562 return 1;
564 if (!TestVector()) {
565 return 1;
567 if (!TestArray()) {
568 return 1;
570 if (!TestMakeUnique()) {
571 return 1;
573 if (!TestVoid()) {
574 return 1;
576 return 0;