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/. */
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
;
27 MOZ_ASSERT(cond, "Failed assertion: " #c); \
33 typedef UniquePtr
<int> NewInt
;
34 static_assert(sizeof(NewInt
) == sizeof(int*), "stored most efficiently");
36 static size_t gADestructorCalls
= 0;
41 virtual ~A() { gADestructorCalls
++; }
46 static size_t gBDestructorCalls
= 0;
51 ~B() { gBDestructorCalls
++; }
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() {
74 static void TestDeleterType() {
75 // Make sure UniquePtr will use its deleter's pointer type if it defines one.
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> >,
91 CHECK(n1
.get() != nullptr);
95 CHECK(n1
.get() == nullptr);
100 NewInt
n2(std::move(n1
));
102 CHECK(n1
.get() == nullptr);
103 CHECK(n2
.get() == p1
);
106 CHECK(n1
.get() == p1
);
107 CHECK(n2
.get() == nullptr);
110 CHECK(n1
.get() == nullptr);
111 CHECK(n2
.get() == p1
);
114 CHECK(n1
.get() == nullptr);
115 CHECK(n2
== nullptr);
116 CHECK(nullptr == n2
);
122 CHECK(n1
.get() == p2
);
123 CHECK(n2
.get() == p3
);
126 CHECK(n2
!= nullptr);
127 CHECK(nullptr != n2
);
128 CHECK(n2
.get() == p2
);
129 CHECK(n1
.get() == p3
);
132 CHECK(a1
== nullptr);
134 CHECK(gADestructorCalls
== 0);
139 CHECK(gBDestructorCalls
== 0);
141 CHECK(gADestructorCalls
== 1);
144 CHECK(gADestructorCalls
== 2);
145 CHECK(gBDestructorCalls
== 1);
151 CHECK(gADestructorCalls
== 2);
152 CHECK(gBDestructorCalls
== 1);
154 UniqueA
a3(std::move(a2
));
156 CHECK(gADestructorCalls
== 3);
157 CHECK(gBDestructorCalls
== 2);
162 UniqueA
a4(std::move(b2
));
163 CHECK(b2
.get() == nullptr);
164 CHECK((*a4
).mX
== 42);
165 CHECK(gADestructorCalls
== 3);
166 CHECK(gBDestructorCalls
== 2);
171 CHECK(gADestructorCalls
== 4);
172 CHECK(gBDestructorCalls
== 2);
175 CHECK(gADestructorCalls
== 5);
176 CHECK(gBDestructorCalls
== 3);
179 CHECK(gADestructorCalls
== 6);
180 CHECK(gBDestructorCalls
== 3);
182 UniqueA
a6(ReturnLocalA());
184 CHECK(gADestructorCalls
== 7);
185 CHECK(gBDestructorCalls
== 3);
190 CHECK(gADestructorCalls
== 8);
191 CHECK(gBDestructorCalls
== 4);
195 UniqueA
a8(std::move(c1
));
196 CHECK(gADestructorCalls
== 8);
197 CHECK(gBDestructorCalls
== 4);
199 // These smart pointers still own B resources.
207 static bool TestDefaultFree() {
208 CHECK(TestDefaultFreeGuts());
209 CHECK(gADestructorCalls
== 12);
210 CHECK(gBDestructorCalls
== 8);
214 static size_t FreeClassCounter
= 0;
218 FreeClass() = default;
220 void operator()(int* 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);
239 NewIntCustom
n3(new int);
240 CHECK(FreeClassCounter
== 1);
243 CHECK(FreeClassCounter
== 1);
245 CHECK(FreeClassCounter
== 2);
248 CHECK(FreeClassCounter
== 2);
251 CHECK(FreeClassCounter
== 3);
253 NewIntCustom
n4(new int, FreeClass());
254 CHECK(FreeClassCounter
== 3);
256 CHECK(FreeClassCounter
== 4);
258 CHECK(FreeClassCounter
== 5);
261 NewIntCustom
n5(new int, f
);
262 CHECK(FreeClassCounter
== 5);
263 int* p
= n5
.release();
264 CHECK(FreeClassCounter
== 5);
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
);
298 BDeleterRef
b1(new B
, delA
);
301 BDeleterRef
b2(new B
, delA
);
303 ADeleterRef
a2(std::move(b2
));
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;
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)));
337 static UniquePtr
<int, FreeSignature
> MallocedInt(int aI
) {
338 UniquePtr
<int, FreeSignature
> ptr(static_cast<int*>(malloc(sizeof(int))),
343 static bool TestFunctionReferenceDeleter() {
344 // Look for allocator mismatches and leaks to verify these bits
345 UniquePtr
<int, FreeSignature
> i1(MallocedInt(17));
348 SetMallocedInt(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);
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));
377 static size_t AAfter
;
378 static size_t BAfter
;
380 static bool TestVectorGuts() {
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();
392 CHECK(appendA
? vec
.append(new A
) : vec
.append(new B
));
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);
406 static bool TestVector() {
407 gADestructorCalls
= 0;
408 gBDestructorCalls
= 0;
410 CHECK(TestVectorGuts());
412 CHECK(gADestructorCalls
== 3 + AAfter
+ BAfter
);
413 CHECK(gBDestructorCalls
== 2 + BAfter
);
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[]> >,
424 IntArray
n1(new int[5]);
426 CHECK(n1
.get() != nullptr);
430 CHECK(n1
.get() == nullptr);
432 int* p1
= new int[42];
435 IntArray
n2(std::move(n1
));
437 CHECK(n1
.get() == nullptr);
438 CHECK(n2
.get() == p1
);
441 CHECK(n1
.get() == p1
);
442 CHECK(n2
.get() == nullptr);
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];
456 CHECK(n1
.get() == p2
);
457 CHECK(n2
.get() == p3
);
460 CHECK(n2
.get() == p2
);
461 CHECK(n1
.get() == p3
);
464 CHECK(n1
.get() == p2
);
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
[]>());
476 UniquePtr
<A
[]> a3(nullptr);
484 Q(const Q
&) = default;
488 template <typename T
>
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));
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));
520 static bool TestVoid() {
521 // UniquePtr<void> supports all operations except operator*() and
523 UniqueFreePtr
<void> p1(malloc(1));
524 UniqueFreePtr
<void> p2
;
528 CHECK((std::is_same_v
<decltype(x
), void*>));
530 p2
.reset(p1
.release());
531 CHECK(p1
.get() == nullptr);
532 CHECK(p2
.get() != nullptr);
551 if (!TestDefaultFree()) {
554 if (!TestFreeClass()) {
557 if (!TestReferenceDeleter()) {
560 if (!TestFunctionReferenceDeleter()) {
569 if (!TestMakeUnique()) {