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"
17 using mozilla::DefaultDelete
;
18 using mozilla::IsSame
;
19 using mozilla::MakeUnique
;
21 using mozilla::UniqueFreePtr
;
22 using mozilla::UniquePtr
;
23 using mozilla::Vector
;
28 MOZ_ASSERT(cond, "Failed assertion: " #c); \
34 typedef UniquePtr
<int> NewInt
;
35 static_assert(sizeof(NewInt
) == sizeof(int*), "stored most efficiently");
37 static size_t gADestructorCalls
= 0;
42 virtual ~A() { gADestructorCalls
++; }
47 static size_t gBDestructorCalls
= 0;
52 ~B() { gBDestructorCalls
++; }
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() {
75 static void TestDeleterType() {
76 // Make sure UniquePtr will use its deleter's pointer type if it defines one.
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
,
92 CHECK(n1
.get() != nullptr);
96 CHECK(n1
.get() == nullptr);
101 NewInt
n2(std::move(n1
));
103 CHECK(n1
.get() == nullptr);
104 CHECK(n2
.get() == p1
);
107 CHECK(n1
.get() == p1
);
108 CHECK(n2
.get() == nullptr);
111 CHECK(n1
.get() == nullptr);
112 CHECK(n2
.get() == p1
);
115 CHECK(n1
.get() == nullptr);
116 CHECK(n2
== nullptr);
117 CHECK(nullptr == n2
);
123 CHECK(n1
.get() == p2
);
124 CHECK(n2
.get() == p3
);
127 CHECK(n2
!= nullptr);
128 CHECK(nullptr != n2
);
129 CHECK(n2
.get() == p2
);
130 CHECK(n1
.get() == p3
);
133 CHECK(a1
== nullptr);
135 CHECK(gADestructorCalls
== 0);
140 CHECK(gBDestructorCalls
== 0);
142 CHECK(gADestructorCalls
== 1);
145 CHECK(gADestructorCalls
== 2);
146 CHECK(gBDestructorCalls
== 1);
152 CHECK(gADestructorCalls
== 2);
153 CHECK(gBDestructorCalls
== 1);
155 UniqueA
a3(std::move(a2
));
157 CHECK(gADestructorCalls
== 3);
158 CHECK(gBDestructorCalls
== 2);
163 UniqueA
a4(std::move(b2
));
164 CHECK(b2
.get() == nullptr);
165 CHECK((*a4
).mX
== 42);
166 CHECK(gADestructorCalls
== 3);
167 CHECK(gBDestructorCalls
== 2);
172 CHECK(gADestructorCalls
== 4);
173 CHECK(gBDestructorCalls
== 2);
176 CHECK(gADestructorCalls
== 5);
177 CHECK(gBDestructorCalls
== 3);
180 CHECK(gADestructorCalls
== 6);
181 CHECK(gBDestructorCalls
== 3);
183 UniqueA
a6(ReturnLocalA());
185 CHECK(gADestructorCalls
== 7);
186 CHECK(gBDestructorCalls
== 3);
191 CHECK(gADestructorCalls
== 8);
192 CHECK(gBDestructorCalls
== 4);
196 UniqueA
a8(std::move(c1
));
197 CHECK(gADestructorCalls
== 8);
198 CHECK(gBDestructorCalls
== 4);
200 // These smart pointers still own B resources.
208 static bool TestDefaultFree() {
209 CHECK(TestDefaultFreeGuts());
210 CHECK(gADestructorCalls
== 12);
211 CHECK(gBDestructorCalls
== 8);
215 static size_t FreeClassCounter
= 0;
221 void operator()(int* 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);
240 NewIntCustom
n3(new int);
241 CHECK(FreeClassCounter
== 1);
244 CHECK(FreeClassCounter
== 1);
246 CHECK(FreeClassCounter
== 2);
249 CHECK(FreeClassCounter
== 2);
252 CHECK(FreeClassCounter
== 3);
254 NewIntCustom
n4(new int, FreeClass());
255 CHECK(FreeClassCounter
== 3);
257 CHECK(FreeClassCounter
== 4);
259 CHECK(FreeClassCounter
== 5);
262 NewIntCustom
n5(new int, f
);
263 CHECK(FreeClassCounter
== 5);
264 int* p
= n5
.release();
265 CHECK(FreeClassCounter
== 5);
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
);
299 BDeleterRef
b1(new B
, delA
);
302 BDeleterRef
b2(new B
, delA
);
304 ADeleterRef
a2(std::move(b2
));
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;
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)));
338 static UniquePtr
<int, FreeSignature
> MallocedInt(int aI
) {
339 UniquePtr
<int, FreeSignature
> ptr(static_cast<int*>(malloc(sizeof(int))),
344 static bool TestFunctionReferenceDeleter() {
345 // Look for allocator mismatches and leaks to verify these bits
346 UniquePtr
<int, FreeSignature
> i1(MallocedInt(17));
349 SetMallocedInt(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);
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));
378 static size_t AAfter
;
379 static size_t BAfter
;
381 static bool TestVectorGuts() {
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();
393 CHECK(appendA
? vec
.append(new A
) : vec
.append(new B
));
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);
407 static bool TestVector() {
408 gADestructorCalls
= 0;
409 gBDestructorCalls
= 0;
411 CHECK(TestVectorGuts());
413 CHECK(gADestructorCalls
== 3 + AAfter
+ BAfter
);
414 CHECK(gBDestructorCalls
== 2 + BAfter
);
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
,
425 IntArray
n1(new int[5]);
427 CHECK(n1
.get() != nullptr);
431 CHECK(n1
.get() == nullptr);
433 int* p1
= new int[42];
436 IntArray
n2(std::move(n1
));
438 CHECK(n1
.get() == nullptr);
439 CHECK(n2
.get() == p1
);
442 CHECK(n1
.get() == p1
);
443 CHECK(n2
.get() == nullptr);
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];
457 CHECK(n1
.get() == p2
);
458 CHECK(n2
.get() == p3
);
461 CHECK(n2
.get() == p2
);
462 CHECK(n1
.get() == p3
);
465 CHECK(n1
.get() == p2
);
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
[]>());
477 UniquePtr
<A
[]> a3(nullptr);
489 template <typename T
>
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));
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));
521 static bool TestVoid() {
522 // UniquePtr<void> supports all operations except operator*() and
524 UniqueFreePtr
<void> p1(malloc(1));
525 UniqueFreePtr
<void> p2
;
529 CHECK((IsSame
<decltype(x
), void*>::value
));
531 p2
.reset(p1
.release());
532 CHECK(p1
.get() == nullptr);
533 CHECK(p2
.get() != nullptr);
552 if (!TestDefaultFree()) {
555 if (!TestFreeClass()) {
558 if (!TestReferenceDeleter()) {
561 if (!TestFunctionReferenceDeleter()) {
570 if (!TestMakeUnique()) {