Bug 1732219 - Add API for fetching the preview image. r=geckoview-reviewers,agi,mconley
[gecko.git] / mfbt / tests / TestUniquePtr.cpp
blob1000b1caf3c165ca643e6298b4ba318cbec9175d
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 <stddef.h>
9 #include <type_traits>
10 #include <utility>
12 #include "mozilla/Assertions.h"
13 #include "mozilla/Compiler.h"
14 #include "mozilla/UniquePtr.h"
15 #include "mozilla/UniquePtrExtensions.h"
16 #include "mozilla/Vector.h"
18 using mozilla::DefaultDelete;
19 using mozilla::MakeUnique;
20 using mozilla::UniqueFreePtr;
21 using mozilla::UniquePtr;
22 using mozilla::Vector;
24 #define CHECK(c) \
25 do { \
26 bool cond = !!(c); \
27 MOZ_ASSERT(cond, "Failed assertion: " #c); \
28 if (!cond) { \
29 return false; \
30 } \
31 } while (false)
33 typedef UniquePtr<int> NewInt;
34 static_assert(sizeof(NewInt) == sizeof(int*), "stored most efficiently");
36 static size_t gADestructorCalls = 0;
38 struct A {
39 public:
40 A() : mX(0) {}
41 virtual ~A() { gADestructorCalls++; }
43 int mX;
46 static size_t gBDestructorCalls = 0;
48 struct B : public A {
49 public:
50 B() : mY(1) {}
51 ~B() { gBDestructorCalls++; }
53 int mY;
56 typedef UniquePtr<A> UniqueA;
57 typedef UniquePtr<B, UniqueA::DeleterType> UniqueB; // permit interconversion
59 static_assert(sizeof(UniqueA) == sizeof(A*), "stored most efficiently");
60 static_assert(sizeof(UniqueB) == sizeof(B*), "stored most efficiently");
62 struct DeleterSubclass : UniqueA::DeleterType {};
64 typedef UniquePtr<B, DeleterSubclass> UniqueC;
65 static_assert(sizeof(UniqueC) == sizeof(B*), "stored most efficiently");
67 static UniqueA ReturnUniqueA() { return UniqueA(new B); }
69 static UniqueA ReturnLocalA() {
70 UniqueA a(new A);
71 return a;
74 static void TestDeleterType() {
75 // Make sure UniquePtr will use its deleter's pointer type if it defines one.
76 typedef int* Ptr;
77 struct Deleter {
78 typedef Ptr pointer;
79 Deleter() = default;
80 void operator()(int* p) { delete p; }
82 UniquePtr<Ptr, Deleter> u(new int, Deleter());
85 static bool TestDefaultFreeGuts() {
86 static_assert(std::is_same_v<NewInt::DeleterType, DefaultDelete<int> >,
87 "weird deleter?");
89 NewInt n1(new int);
90 CHECK(n1);
91 CHECK(n1.get() != nullptr);
93 n1 = nullptr;
94 CHECK(!n1);
95 CHECK(n1.get() == nullptr);
97 int* p1 = new int;
98 n1.reset(p1);
99 CHECK(n1);
100 NewInt n2(std::move(n1));
101 CHECK(!n1);
102 CHECK(n1.get() == nullptr);
103 CHECK(n2.get() == p1);
105 std::swap(n1, n2);
106 CHECK(n1.get() == p1);
107 CHECK(n2.get() == nullptr);
109 n1.swap(n2);
110 CHECK(n1.get() == nullptr);
111 CHECK(n2.get() == p1);
112 delete n2.release();
114 CHECK(n1.get() == nullptr);
115 CHECK(n2 == nullptr);
116 CHECK(nullptr == n2);
118 int* p2 = new int;
119 int* p3 = new int;
120 n1.reset(p2);
121 n2.reset(p3);
122 CHECK(n1.get() == p2);
123 CHECK(n2.get() == p3);
125 n1.swap(n2);
126 CHECK(n2 != nullptr);
127 CHECK(nullptr != n2);
128 CHECK(n2.get() == p2);
129 CHECK(n1.get() == p3);
131 UniqueA a1;
132 CHECK(a1 == nullptr);
133 a1.reset(new A);
134 CHECK(gADestructorCalls == 0);
135 CHECK(a1->mX == 0);
137 B* bp1 = new B;
138 bp1->mX = 5;
139 CHECK(gBDestructorCalls == 0);
140 a1.reset(bp1);
141 CHECK(gADestructorCalls == 1);
142 CHECK(a1->mX == 5);
143 a1.reset(nullptr);
144 CHECK(gADestructorCalls == 2);
145 CHECK(gBDestructorCalls == 1);
147 B* bp2 = new B;
148 UniqueB b1(bp2);
149 UniqueA a2(nullptr);
150 a2 = std::move(b1);
151 CHECK(gADestructorCalls == 2);
152 CHECK(gBDestructorCalls == 1);
154 UniqueA a3(std::move(a2));
155 a3 = nullptr;
156 CHECK(gADestructorCalls == 3);
157 CHECK(gBDestructorCalls == 2);
159 B* bp3 = new B;
160 bp3->mX = 42;
161 UniqueB b2(bp3);
162 UniqueA a4(std::move(b2));
163 CHECK(b2.get() == nullptr);
164 CHECK((*a4).mX == 42);
165 CHECK(gADestructorCalls == 3);
166 CHECK(gBDestructorCalls == 2);
168 UniqueA a5(new A);
169 UniqueB b3(new B);
170 a5 = std::move(b3);
171 CHECK(gADestructorCalls == 4);
172 CHECK(gBDestructorCalls == 2);
174 ReturnUniqueA();
175 CHECK(gADestructorCalls == 5);
176 CHECK(gBDestructorCalls == 3);
178 ReturnLocalA();
179 CHECK(gADestructorCalls == 6);
180 CHECK(gBDestructorCalls == 3);
182 UniqueA a6(ReturnLocalA());
183 a6 = nullptr;
184 CHECK(gADestructorCalls == 7);
185 CHECK(gBDestructorCalls == 3);
187 UniqueC c1(new B);
188 UniqueA a7(new B);
189 a7 = std::move(c1);
190 CHECK(gADestructorCalls == 8);
191 CHECK(gBDestructorCalls == 4);
193 c1.reset(new B);
195 UniqueA a8(std::move(c1));
196 CHECK(gADestructorCalls == 8);
197 CHECK(gBDestructorCalls == 4);
199 // These smart pointers still own B resources.
200 CHECK(a4);
201 CHECK(a5);
202 CHECK(a7);
203 CHECK(a8);
204 return true;
207 static bool TestDefaultFree() {
208 CHECK(TestDefaultFreeGuts());
209 CHECK(gADestructorCalls == 12);
210 CHECK(gBDestructorCalls == 8);
211 return true;
214 static size_t FreeClassCounter = 0;
216 struct FreeClass {
217 public:
218 FreeClass() = default;
220 void operator()(int* aPtr) {
221 FreeClassCounter++;
222 delete aPtr;
226 typedef UniquePtr<int, FreeClass> NewIntCustom;
227 static_assert(sizeof(NewIntCustom) == sizeof(int*), "stored most efficiently");
229 static bool TestFreeClass() {
230 CHECK(FreeClassCounter == 0);
232 NewIntCustom n1(new int);
233 CHECK(FreeClassCounter == 0);
235 CHECK(FreeClassCounter == 1);
237 NewIntCustom n2;
239 NewIntCustom n3(new int);
240 CHECK(FreeClassCounter == 1);
241 n2 = std::move(n3);
243 CHECK(FreeClassCounter == 1);
244 n2 = nullptr;
245 CHECK(FreeClassCounter == 2);
247 n2.reset(nullptr);
248 CHECK(FreeClassCounter == 2);
249 n2.reset(new int);
250 n2.reset();
251 CHECK(FreeClassCounter == 3);
253 NewIntCustom n4(new int, FreeClass());
254 CHECK(FreeClassCounter == 3);
255 n4.reset(new int);
256 CHECK(FreeClassCounter == 4);
257 n4.reset();
258 CHECK(FreeClassCounter == 5);
260 FreeClass f;
261 NewIntCustom n5(new int, f);
262 CHECK(FreeClassCounter == 5);
263 int* p = n5.release();
264 CHECK(FreeClassCounter == 5);
265 delete p;
267 return true;
270 typedef UniquePtr<int, DefaultDelete<int>&> IntDeleterRef;
271 typedef UniquePtr<A, DefaultDelete<A>&> ADeleterRef;
272 typedef UniquePtr<B, DefaultDelete<A>&> BDeleterRef;
274 static_assert(sizeof(IntDeleterRef) > sizeof(int*),
275 "has to be heavier than an int* to store the reference");
276 static_assert(sizeof(ADeleterRef) > sizeof(A*),
277 "has to be heavier than an A* to store the reference");
278 static_assert(sizeof(BDeleterRef) > sizeof(int*),
279 "has to be heavier than a B* to store the reference");
281 static bool TestReferenceDeleterGuts() {
282 DefaultDelete<int> delInt;
283 IntDeleterRef id1(new int, delInt);
285 IntDeleterRef id2(std::move(id1));
286 CHECK(id1 == nullptr);
287 CHECK(nullptr != id2);
288 CHECK(&id1.get_deleter() == &id2.get_deleter());
290 IntDeleterRef id3(std::move(id2));
292 DefaultDelete<A> delA;
293 ADeleterRef a1(new A, delA);
294 a1.reset(nullptr);
295 a1.reset(new B);
296 a1 = nullptr;
298 BDeleterRef b1(new B, delA);
299 a1 = std::move(b1);
301 BDeleterRef b2(new B, delA);
303 ADeleterRef a2(std::move(b2));
305 return true;
308 static bool TestReferenceDeleter() {
309 gADestructorCalls = 0;
310 gBDestructorCalls = 0;
312 CHECK(TestReferenceDeleterGuts());
314 CHECK(gADestructorCalls == 4);
315 CHECK(gBDestructorCalls == 3);
317 gADestructorCalls = 0;
318 gBDestructorCalls = 0;
319 return true;
322 typedef void (&FreeSignature)(void*);
324 static size_t DeleteIntFunctionCallCount = 0;
326 static void DeleteIntFunction(void* aPtr) {
327 DeleteIntFunctionCallCount++;
328 delete static_cast<int*>(aPtr);
331 static void SetMallocedInt(UniquePtr<int, FreeSignature>& aPtr, int aI) {
332 int* newPtr = static_cast<int*>(malloc(sizeof(int)));
333 *newPtr = aI;
334 aPtr.reset(newPtr);
337 static UniquePtr<int, FreeSignature> MallocedInt(int aI) {
338 UniquePtr<int, FreeSignature> ptr(static_cast<int*>(malloc(sizeof(int))),
339 free);
340 *ptr = aI;
341 return ptr;
343 static bool TestFunctionReferenceDeleter() {
344 // Look for allocator mismatches and leaks to verify these bits
345 UniquePtr<int, FreeSignature> i1(MallocedInt(17));
346 CHECK(*i1 == 17);
348 SetMallocedInt(i1, 42);
349 CHECK(*i1 == 42);
351 // These bits use a custom deleter so we can instrument deletion.
353 UniquePtr<int, FreeSignature> i2 =
354 UniquePtr<int, FreeSignature>(new int(42), DeleteIntFunction);
355 CHECK(DeleteIntFunctionCallCount == 0);
357 i2.reset(new int(76));
358 CHECK(DeleteIntFunctionCallCount == 1);
361 CHECK(DeleteIntFunctionCallCount == 2);
363 return true;
366 template <typename T>
367 struct AppendNullptrTwice {
368 AppendNullptrTwice() = default;
370 bool operator()(Vector<T>& vec) {
371 CHECK(vec.append(nullptr));
372 CHECK(vec.append(nullptr));
373 return true;
377 static size_t AAfter;
378 static size_t BAfter;
380 static bool TestVectorGuts() {
381 Vector<UniqueA> vec;
382 CHECK(vec.append(new B));
383 CHECK(vec.append(new A));
384 CHECK(AppendNullptrTwice<UniqueA>()(vec));
385 CHECK(vec.append(new B));
387 size_t initialLength = vec.length();
389 UniqueA* begin = vec.begin();
390 bool appendA = true;
391 do {
392 CHECK(appendA ? vec.append(new A) : vec.append(new B));
393 appendA = !appendA;
394 } while (begin == vec.begin());
396 size_t numAppended = vec.length() - initialLength;
398 BAfter = numAppended / 2;
399 AAfter = numAppended - numAppended / 2;
401 CHECK(gADestructorCalls == 0);
402 CHECK(gBDestructorCalls == 0);
403 return true;
406 static bool TestVector() {
407 gADestructorCalls = 0;
408 gBDestructorCalls = 0;
410 CHECK(TestVectorGuts());
412 CHECK(gADestructorCalls == 3 + AAfter + BAfter);
413 CHECK(gBDestructorCalls == 2 + BAfter);
414 return true;
417 typedef UniquePtr<int[]> IntArray;
418 static_assert(sizeof(IntArray) == sizeof(int*), "stored most efficiently");
420 static bool TestArray() {
421 static_assert(std::is_same_v<IntArray::DeleterType, DefaultDelete<int[]> >,
422 "weird deleter?");
424 IntArray n1(new int[5]);
425 CHECK(n1);
426 CHECK(n1.get() != nullptr);
428 n1 = nullptr;
429 CHECK(!n1);
430 CHECK(n1.get() == nullptr);
432 int* p1 = new int[42];
433 n1.reset(p1);
434 CHECK(n1);
435 IntArray n2(std::move(n1));
436 CHECK(!n1);
437 CHECK(n1.get() == nullptr);
438 CHECK(n2.get() == p1);
440 std::swap(n1, n2);
441 CHECK(n1.get() == p1);
442 CHECK(n2.get() == nullptr);
444 n1.swap(n2);
445 CHECK(n1.get() == nullptr);
446 CHECK(n2.get() == p1);
447 delete[] n2.release();
449 CHECK(n1.get() == nullptr);
450 CHECK(n2.get() == nullptr);
452 int* p2 = new int[7];
453 int* p3 = new int[42];
454 n1.reset(p2);
455 n2.reset(p3);
456 CHECK(n1.get() == p2);
457 CHECK(n2.get() == p3);
459 n1.swap(n2);
460 CHECK(n2.get() == p2);
461 CHECK(n1.get() == p3);
463 n1 = std::move(n2);
464 CHECK(n1.get() == p2);
465 n1 = std::move(n2);
466 CHECK(n1.get() == nullptr);
468 UniquePtr<A[]> a1(new A[17]);
469 static_assert(sizeof(a1) == sizeof(A*), "stored most efficiently");
471 UniquePtr<A[]> a2(new A[5], DefaultDelete<A[]>());
472 a2.reset(nullptr);
473 a2.reset(new A[17]);
474 a2 = nullptr;
476 UniquePtr<A[]> a3(nullptr);
477 a3.reset(new A[7]);
479 return true;
482 struct Q {
483 Q() = default;
484 Q(const Q&) = default;
486 Q(Q&, char) {}
488 template <typename T>
489 Q(Q, T&&, int) {}
491 Q(int, long, double, void*) {}
494 static int randomInt() { return 4; }
496 static bool TestMakeUnique() {
497 UniquePtr<int> a1(MakeUnique<int>());
498 UniquePtr<long> a2(MakeUnique<long>(4));
500 // no args, easy
501 UniquePtr<Q> q0(MakeUnique<Q>());
503 // temporary bound to const lval ref
504 UniquePtr<Q> q1(MakeUnique<Q>(Q()));
506 // passing through a non-const lval ref
507 UniquePtr<Q> q2(MakeUnique<Q>(*q1, 'c'));
509 // pass by copying, forward a temporary, pass by value
510 UniquePtr<Q> q3(MakeUnique<Q>(Q(), UniquePtr<int>(), randomInt()));
512 // various type mismatching to test "fuzzy" forwarding
513 UniquePtr<Q> q4(MakeUnique<Q>('s', 66LL, 3.141592654, &q3));
515 UniquePtr<char[]> c1(MakeUnique<char[]>(5));
517 return true;
520 static bool TestVoid() {
521 // UniquePtr<void> supports all operations except operator*() and
522 // operator->().
523 UniqueFreePtr<void> p1(malloc(1));
524 UniqueFreePtr<void> p2;
526 auto x = p1.get();
527 CHECK(x != nullptr);
528 CHECK((std::is_same_v<decltype(x), void*>));
530 p2.reset(p1.release());
531 CHECK(p1.get() == nullptr);
532 CHECK(p2.get() != nullptr);
534 p1 = std::move(p2);
535 CHECK(p1);
536 CHECK(!p2);
538 p1.swap(p2);
539 CHECK(!p1);
540 CHECK(p2);
542 p2 = nullptr;
543 CHECK(!p2);
545 return true;
548 int main() {
549 TestDeleterType();
551 if (!TestDefaultFree()) {
552 return 1;
554 if (!TestFreeClass()) {
555 return 1;
557 if (!TestReferenceDeleter()) {
558 return 1;
560 if (!TestFunctionReferenceDeleter()) {
561 return 1;
563 if (!TestVector()) {
564 return 1;
566 if (!TestArray()) {
567 return 1;
569 if (!TestMakeUnique()) {
570 return 1;
572 if (!TestVoid()) {
573 return 1;
575 return 0;