1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
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
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/ArrayUtils.h"
8 #include "mozilla/Unused.h"
9 #include "mozilla/TimeStamp.h"
16 #include "nsDirectoryServiceDefs.h"
17 #include "nsDirectoryServiceUtils.h"
18 #include "nsComponentManagerUtils.h"
22 #include "gtest/gtest.h"
23 #include "mozilla/gtest/MozAssertions.h"
25 using namespace mozilla
;
27 namespace TestTArray
{
29 // Define this so we can use test_basic_array in test_comptr_array
31 inline bool operator<(const nsCOMPtr
<T
>& lhs
, const nsCOMPtr
<T
>& rhs
) {
32 return lhs
.get() < rhs
.get();
37 template <class ElementType
>
38 static bool test_basic_array(ElementType
* data
, size_t dataLen
,
39 const ElementType
& extra
) {
40 CopyableTArray
<ElementType
> ary
;
41 const nsTArray
<ElementType
>& cary
= ary
;
43 ary
.AppendElements(data
, dataLen
);
44 if (ary
.Length() != dataLen
) {
51 for (i
= 0; i
< ary
.Length(); ++i
) {
52 if (ary
[i
] != data
[i
]) return false;
54 for (i
= 0; i
< ary
.Length(); ++i
) {
55 if (ary
.SafeElementAt(i
, extra
) != data
[i
]) return false;
57 if (ary
.SafeElementAt(ary
.Length(), extra
) != extra
||
58 ary
.SafeElementAt(ary
.Length() * 10, extra
) != extra
)
60 // ensure sort results in ascending order
62 size_t j
= 0, k
= ary
.IndexOfFirstElementGt(extra
);
63 if (k
!= 0 && ary
[k
- 1] == extra
) return false;
64 for (i
= 0; i
< ary
.Length(); ++i
) {
65 k
= ary
.IndexOfFirstElementGt(ary
[i
]);
66 if (k
== 0 || ary
[k
- 1] != ary
[i
]) return false;
67 if (k
< j
) return false;
70 for (i
= ary
.Length(); --i
;) {
71 if (ary
[i
] < ary
[i
- 1]) return false;
72 if (ary
[i
] == ary
[i
- 1]) ary
.RemoveElementAt(i
);
77 for (i
= 0; i
< ary
.Length(); ++i
) {
78 if (ary
.BinaryIndexOf(ary
[i
]) != i
) return false;
80 if (ary
.BinaryIndexOf(extra
) != ary
.NoIndex
) return false;
81 size_t oldLen
= ary
.Length();
82 ary
.RemoveElement(data
[dataLen
/ 2]);
83 if (ary
.Length() != (oldLen
- 1)) return false;
84 if (!(ary
== ary
)) return false;
87 extra
, []() { return true; }, []() { return false; }))
90 extra
, [](size_t) { return true; }, []() { return false; }))
92 // On a non-const array, ApplyIf's first lambda may use either const or non-
93 // const element types.
95 extra
, [](ElementType
&) { return true; }, []() { return false; }))
98 extra
, [](const ElementType
&) { return true; },
99 []() { return false; }))
102 extra
, [](size_t, ElementType
&) { return true; },
103 []() { return false; }))
106 extra
, [](size_t, const ElementType
&) { return true; },
107 []() { return false; }))
111 extra
, []() { return true; }, []() { return false; }))
113 extra
, [](size_t) { return true; }, []() { return false; }))
114 // On a const array, ApplyIf's first lambda must only use const element
117 extra
, [](const ElementType
&) { return true; },
118 []() { return false; }))
120 extra
, [](size_t, const ElementType
&) { return true; },
121 []() { return false; }))
124 size_t index
= ary
.Length() / 2;
125 ary
.InsertElementAt(index
, extra
);
126 if (!(ary
== ary
)) return false;
127 if (ary
[index
] != extra
) return false;
128 if (ary
.IndexOf(extra
) == ary
.NoIndex
) return false;
129 if (ary
.LastIndexOf(extra
) == ary
.NoIndex
) return false;
130 // ensure proper searching
131 if (ary
.IndexOf(extra
) > ary
.LastIndexOf(extra
)) return false;
132 if (ary
.IndexOf(extra
, index
) != ary
.LastIndexOf(extra
, index
)) return false;
135 [&](size_t i
, const ElementType
& e
) {
136 return i
== index
&& e
== extra
;
138 []() { return false; }))
142 [&](size_t i
, const ElementType
& e
) {
143 return i
== index
&& e
== extra
;
145 []() { return false; }))
148 nsTArray
<ElementType
> copy(ary
.Clone());
149 if (!(ary
== copy
)) return false;
150 for (i
= 0; i
< copy
.Length(); ++i
) {
151 if (ary
[i
] != copy
[i
]) return false;
153 ary
.AppendElements(copy
);
154 size_t cap
= ary
.Capacity();
155 ary
.RemoveElementsAt(copy
.Length(), copy
.Length());
157 if (ary
.Capacity() == cap
) return false;
160 if (ary
.IndexOf(extra
) != ary
.NoIndex
) return false;
161 if (ary
.LastIndexOf(extra
) != ary
.NoIndex
) return false;
163 extra
, []() { return true; }, []() { return false; }))
166 extra
, []() { return true; }, []() { return false; }))
170 if (!ary
.IsEmpty()) return false;
171 if (!(ary
== nsTArray
<ElementType
>())) return false;
172 if (ary
== copy
) return false;
173 if (ary
.SafeElementAt(0, extra
) != extra
||
174 ary
.SafeElementAt(10, extra
) != extra
)
178 if (!(ary
== copy
)) return false;
179 for (i
= 0; i
< copy
.Length(); ++i
) {
180 if (ary
[i
] != copy
[i
]) return false;
183 ary
.InsertElementsAt(0, copy
);
184 if (ary
== copy
) return false;
185 ary
.RemoveElementsAt(0, copy
.Length());
186 for (i
= 0; i
< copy
.Length(); ++i
) {
187 if (ary
[i
] != copy
[i
]) return false;
190 // These shouldn't crash!
191 nsTArray
<ElementType
> empty
;
192 ary
.AppendElements(reinterpret_cast<ElementType
*>(0), 0);
193 ary
.AppendElements(empty
);
196 ary
.RemoveElement(extra
);
197 ary
.RemoveElement(extra
);
202 TEST(TArray
, test_int_array
)
204 int data
[] = {4, 6, 8, 2, 4, 1, 5, 7, 3};
205 ASSERT_TRUE(test_basic_array(data
, ArrayLength(data
), int(14)));
208 TEST(TArray
, test_int64_array
)
210 int64_t data
[] = {4, 6, 8, 2, 4, 1, 5, 7, 3};
211 ASSERT_TRUE(test_basic_array(data
, ArrayLength(data
), int64_t(14)));
214 TEST(TArray
, test_char_array
)
216 char data
[] = {4, 6, 8, 2, 4, 1, 5, 7, 3};
217 ASSERT_TRUE(test_basic_array(data
, ArrayLength(data
), char(14)));
220 TEST(TArray
, test_uint32_array
)
222 uint32_t data
[] = {4, 6, 8, 2, 4, 1, 5, 7, 3};
223 ASSERT_TRUE(test_basic_array(data
, ArrayLength(data
), uint32_t(14)));
230 Object() : mNum(0) {}
231 Object(const char* str
, uint32_t num
) : mStr(str
), mNum(num
) {}
232 Object(const Object
& other
) = default;
235 Object
& operator=(const Object
& other
) = default;
237 bool operator==(const Object
& other
) const {
238 return mStr
== other
.mStr
&& mNum
== other
.mNum
;
241 bool operator<(const Object
& other
) const {
242 // sort based on mStr only
243 return Compare(mStr
, other
.mStr
) < 0;
246 const char* Str() const { return mStr
.get(); }
247 uint32_t Num() const { return mNum
; }
254 TEST(TArray
, test_object_array
)
256 nsTArray
<Object
> objArray
;
257 const char kdata
[] = "hello world";
259 for (i
= 0; i
< ArrayLength(kdata
); ++i
) {
260 char x
[] = {kdata
[i
], '\0'};
261 objArray
.AppendElement(Object(x
, i
));
263 for (i
= 0; i
< ArrayLength(kdata
); ++i
) {
264 ASSERT_EQ(objArray
[i
].Str()[0], kdata
[i
]);
265 ASSERT_EQ(objArray
[i
].Num(), i
);
268 const char ksorted
[] = "\0 dehllloorw";
269 for (i
= 0; i
< ArrayLength(kdata
) - 1; ++i
) {
270 ASSERT_EQ(objArray
[i
].Str()[0], ksorted
[i
]);
278 Countable() { sCount
++; }
280 Countable(const Countable
& aOther
) { sCount
++; }
282 static int Count() { return sCount
; }
289 Moveable() { sCount
++; }
291 Moveable(const Moveable
& aOther
) { sCount
++; }
293 Moveable(Moveable
&& aOther
) {
294 // Do not increment sCount
297 static int Count() { return sCount
; }
300 class MoveOnly_RelocateUsingMemutils
{
302 MoveOnly_RelocateUsingMemutils() = default;
304 MoveOnly_RelocateUsingMemutils(const MoveOnly_RelocateUsingMemutils
&) =
306 MoveOnly_RelocateUsingMemutils(MoveOnly_RelocateUsingMemutils
&&) = default;
308 MoveOnly_RelocateUsingMemutils
& operator=(
309 const MoveOnly_RelocateUsingMemutils
&) = delete;
310 MoveOnly_RelocateUsingMemutils
& operator=(MoveOnly_RelocateUsingMemutils
&&) =
315 std::is_move_constructible_v
<nsTArray
<MoveOnly_RelocateUsingMemutils
>>);
317 std::is_move_assignable_v
<nsTArray
<MoveOnly_RelocateUsingMemutils
>>);
319 !std::is_copy_constructible_v
<nsTArray
<MoveOnly_RelocateUsingMemutils
>>);
321 !std::is_copy_assignable_v
<nsTArray
<MoveOnly_RelocateUsingMemutils
>>);
323 class MoveOnly_RelocateUsingMoveConstructor
{
325 MoveOnly_RelocateUsingMoveConstructor() = default;
327 MoveOnly_RelocateUsingMoveConstructor(
328 const MoveOnly_RelocateUsingMoveConstructor
&) = delete;
329 MoveOnly_RelocateUsingMoveConstructor(
330 MoveOnly_RelocateUsingMoveConstructor
&&) = default;
332 MoveOnly_RelocateUsingMoveConstructor
& operator=(
333 const MoveOnly_RelocateUsingMoveConstructor
&) = delete;
334 MoveOnly_RelocateUsingMoveConstructor
& operator=(
335 MoveOnly_RelocateUsingMoveConstructor
&&) = default;
337 } // namespace TestTArray
339 MOZ_DECLARE_RELOCATE_USING_MOVE_CONSTRUCTOR(
340 TestTArray::MoveOnly_RelocateUsingMoveConstructor
)
342 namespace TestTArray
{
343 static_assert(std::is_move_constructible_v
<
344 nsTArray
<MoveOnly_RelocateUsingMoveConstructor
>>);
346 std::is_move_assignable_v
<nsTArray
<MoveOnly_RelocateUsingMoveConstructor
>>);
347 static_assert(!std::is_copy_constructible_v
<
348 nsTArray
<MoveOnly_RelocateUsingMoveConstructor
>>);
349 static_assert(!std::is_copy_assignable_v
<
350 nsTArray
<MoveOnly_RelocateUsingMoveConstructor
>>);
351 } // namespace TestTArray
353 namespace TestTArray
{
356 int Countable::sCount
= 0;
358 int Moveable::sCount
= 0;
360 static nsTArray
<int> returns_by_value() {
361 nsTArray
<int> result
;
365 TEST(TArray
, test_return_by_value
)
367 nsTArray
<int> result
= returns_by_value();
368 ASSERT_TRUE(true); // This is just a compilation test.
371 TEST(TArray
, test_move_array
)
373 nsTArray
<Countable
> countableArray
;
375 for (i
= 0; i
< 4; ++i
) {
376 countableArray
.AppendElement(Countable());
379 ASSERT_EQ(Countable::Count(), 8);
381 const nsTArray
<Countable
>& constRefCountableArray
= countableArray
;
383 ASSERT_EQ(Countable::Count(), 8);
385 nsTArray
<Countable
> copyCountableArray(constRefCountableArray
.Clone());
387 ASSERT_EQ(Countable::Count(), 12);
389 nsTArray
<Countable
>&& moveRefCountableArray
= std::move(countableArray
);
390 moveRefCountableArray
.Length(); // Make compilers happy.
392 ASSERT_EQ(Countable::Count(), 12);
394 nsTArray
<Countable
> movedCountableArray(std::move(countableArray
));
396 ASSERT_EQ(Countable::Count(), 12);
399 FallibleTArray
<Countable
> differentAllocatorCountableArray(
400 std::move(copyCountableArray
));
402 copyCountableArray
= std::move(differentAllocatorCountableArray
);
403 differentAllocatorCountableArray
= std::move(copyCountableArray
);
404 // And the other ctor
405 nsTArray
<Countable
> copyCountableArray2(
406 std::move(differentAllocatorCountableArray
));
408 AutoTArray
<Countable
, 3> autoCountableArray(std::move(copyCountableArray2
));
410 copyCountableArray2
= std::move(autoCountableArray
);
411 // Mix with FallibleTArray
412 FallibleTArray
<Countable
> differentAllocatorCountableArray2(
413 std::move(copyCountableArray2
));
414 AutoTArray
<Countable
, 4> autoCountableArray2(
415 std::move(differentAllocatorCountableArray2
));
416 differentAllocatorCountableArray2
= std::move(autoCountableArray2
);
418 ASSERT_EQ(Countable::Count(), 12);
420 nsTArray
<Moveable
> moveableArray
;
421 for (i
= 0; i
< 4; ++i
) {
422 moveableArray
.AppendElement(Moveable());
425 ASSERT_EQ(Moveable::Count(), 4);
427 const nsTArray
<Moveable
>& constRefMoveableArray
= moveableArray
;
429 ASSERT_EQ(Moveable::Count(), 4);
431 nsTArray
<Moveable
> copyMoveableArray(constRefMoveableArray
.Clone());
433 ASSERT_EQ(Moveable::Count(), 8);
435 nsTArray
<Moveable
>&& moveRefMoveableArray
= std::move(moveableArray
);
436 moveRefMoveableArray
.Length(); // Make compilers happy.
438 ASSERT_EQ(Moveable::Count(), 8);
440 nsTArray
<Moveable
> movedMoveableArray(std::move(moveableArray
));
442 ASSERT_EQ(Moveable::Count(), 8);
445 FallibleTArray
<Moveable
> differentAllocatorMoveableArray(
446 std::move(copyMoveableArray
));
448 copyMoveableArray
= std::move(differentAllocatorMoveableArray
);
449 differentAllocatorMoveableArray
= std::move(copyMoveableArray
);
450 // And the other ctor
451 nsTArray
<Moveable
> copyMoveableArray2(
452 std::move(differentAllocatorMoveableArray
));
454 AutoTArray
<Moveable
, 3> autoMoveableArray(std::move(copyMoveableArray2
));
456 copyMoveableArray2
= std::move(autoMoveableArray
);
457 // Mix with FallibleTArray
458 FallibleTArray
<Moveable
> differentAllocatorMoveableArray2(
459 std::move(copyMoveableArray2
));
460 AutoTArray
<Moveable
, 4> autoMoveableArray2(
461 std::move(differentAllocatorMoveableArray2
));
462 differentAllocatorMoveableArray2
= std::move(autoMoveableArray2
);
464 ASSERT_EQ(Moveable::Count(), 8);
466 AutoTArray
<Moveable
, 8> moveableAutoArray
;
467 for (uint32_t i
= 0; i
< 4; ++i
) {
468 moveableAutoArray
.AppendElement(Moveable());
471 ASSERT_EQ(Moveable::Count(), 12);
473 const AutoTArray
<Moveable
, 8>& constRefMoveableAutoArray
= moveableAutoArray
;
475 ASSERT_EQ(Moveable::Count(), 12);
477 CopyableAutoTArray
<Moveable
, 8> copyMoveableAutoArray(
478 constRefMoveableAutoArray
);
480 ASSERT_EQ(Moveable::Count(), 16);
482 AutoTArray
<Moveable
, 8> movedMoveableAutoArray(std::move(moveableAutoArray
));
484 ASSERT_EQ(Moveable::Count(), 16);
487 template <typename TypeParam
>
488 class TArray_MoveOnlyTest
: public ::testing::Test
{};
490 TYPED_TEST_SUITE_P(TArray_MoveOnlyTest
);
492 static constexpr size_t kMoveOnlyTestArrayLength
= 4;
494 template <typename ArrayType
>
495 static auto MakeMoveOnlyArray() {
496 ArrayType moveOnlyArray
;
497 for (size_t i
= 0; i
< kMoveOnlyTestArrayLength
; ++i
) {
498 EXPECT_TRUE(moveOnlyArray
.AppendElement(typename
ArrayType::value_type(),
501 return moveOnlyArray
;
504 TYPED_TEST_P(TArray_MoveOnlyTest
, nsTArray_MoveConstruct
) {
505 auto moveOnlyArray
= MakeMoveOnlyArray
<nsTArray
<TypeParam
>>();
506 nsTArray
<TypeParam
> movedMoveOnlyArray(std::move(moveOnlyArray
));
508 ASSERT_EQ(0u, moveOnlyArray
.Length());
509 ASSERT_EQ(kMoveOnlyTestArrayLength
, movedMoveOnlyArray
.Length());
512 TYPED_TEST_P(TArray_MoveOnlyTest
, nsTArray_MoveAssign
) {
513 auto moveOnlyArray
= MakeMoveOnlyArray
<nsTArray
<TypeParam
>>();
514 nsTArray
<TypeParam
> movedMoveOnlyArray
;
515 movedMoveOnlyArray
= std::move(moveOnlyArray
);
517 ASSERT_EQ(0u, moveOnlyArray
.Length());
518 ASSERT_EQ(kMoveOnlyTestArrayLength
, movedMoveOnlyArray
.Length());
521 TYPED_TEST_P(TArray_MoveOnlyTest
, nsTArray_MoveReAssign
) {
522 nsTArray
<TypeParam
> movedMoveOnlyArray
;
523 movedMoveOnlyArray
= MakeMoveOnlyArray
<nsTArray
<TypeParam
>>();
524 // Re-assign, to check that move-assign does not only work on an empty array.
525 movedMoveOnlyArray
= MakeMoveOnlyArray
<nsTArray
<TypeParam
>>();
527 ASSERT_EQ(kMoveOnlyTestArrayLength
, movedMoveOnlyArray
.Length());
530 TYPED_TEST_P(TArray_MoveOnlyTest
, nsTArray_to_FallibleTArray_MoveConstruct
) {
531 auto moveOnlyArray
= MakeMoveOnlyArray
<nsTArray
<TypeParam
>>();
532 FallibleTArray
<TypeParam
> differentAllocatorMoveOnlyArray(
533 std::move(moveOnlyArray
));
535 ASSERT_EQ(0u, moveOnlyArray
.Length());
536 ASSERT_EQ(kMoveOnlyTestArrayLength
, differentAllocatorMoveOnlyArray
.Length());
539 TYPED_TEST_P(TArray_MoveOnlyTest
, nsTArray_to_FallibleTArray_MoveAssign
) {
540 auto moveOnlyArray
= MakeMoveOnlyArray
<nsTArray
<TypeParam
>>();
541 FallibleTArray
<TypeParam
> differentAllocatorMoveOnlyArray
;
542 differentAllocatorMoveOnlyArray
= std::move(moveOnlyArray
);
544 ASSERT_EQ(0u, moveOnlyArray
.Length());
545 ASSERT_EQ(kMoveOnlyTestArrayLength
, differentAllocatorMoveOnlyArray
.Length());
548 TYPED_TEST_P(TArray_MoveOnlyTest
, FallibleTArray_to_nsTArray_MoveConstruct
) {
549 auto moveOnlyArray
= MakeMoveOnlyArray
<FallibleTArray
<TypeParam
>>();
550 nsTArray
<TypeParam
> differentAllocatorMoveOnlyArray(std::move(moveOnlyArray
));
552 ASSERT_EQ(0u, moveOnlyArray
.Length());
553 ASSERT_EQ(kMoveOnlyTestArrayLength
, differentAllocatorMoveOnlyArray
.Length());
556 TYPED_TEST_P(TArray_MoveOnlyTest
, FallibleTArray_to_nsTArray_MoveAssign
) {
557 auto moveOnlyArray
= MakeMoveOnlyArray
<FallibleTArray
<TypeParam
>>();
558 nsTArray
<TypeParam
> differentAllocatorMoveOnlyArray
;
559 differentAllocatorMoveOnlyArray
= std::move(moveOnlyArray
);
561 ASSERT_EQ(0u, moveOnlyArray
.Length());
562 ASSERT_EQ(kMoveOnlyTestArrayLength
, differentAllocatorMoveOnlyArray
.Length());
565 TYPED_TEST_P(TArray_MoveOnlyTest
, AutoTArray_AutoStorage_MoveConstruct
) {
567 MakeMoveOnlyArray
<AutoTArray
<TypeParam
, kMoveOnlyTestArrayLength
>>();
568 AutoTArray
<TypeParam
, kMoveOnlyTestArrayLength
> autoMoveOnlyArray(
569 std::move(moveOnlyArray
));
571 ASSERT_EQ(0u, moveOnlyArray
.Length());
572 ASSERT_EQ(kMoveOnlyTestArrayLength
, autoMoveOnlyArray
.Length());
575 TYPED_TEST_P(TArray_MoveOnlyTest
, AutoTArray_AutoStorage_MoveAssign
) {
577 MakeMoveOnlyArray
<AutoTArray
<TypeParam
, kMoveOnlyTestArrayLength
>>();
578 AutoTArray
<TypeParam
, kMoveOnlyTestArrayLength
> autoMoveOnlyArray
;
579 autoMoveOnlyArray
= std::move(moveOnlyArray
);
581 ASSERT_EQ(0u, moveOnlyArray
.Length());
582 ASSERT_EQ(kMoveOnlyTestArrayLength
, autoMoveOnlyArray
.Length());
585 TYPED_TEST_P(TArray_MoveOnlyTest
,
586 nsTArray_to_AutoTArray_AutoStorage_MoveConstruct
) {
587 auto moveOnlyArray
= MakeMoveOnlyArray
<nsTArray
<TypeParam
>>();
588 AutoTArray
<TypeParam
, kMoveOnlyTestArrayLength
> autoMoveOnlyArray(
589 std::move(moveOnlyArray
));
591 ASSERT_EQ(0u, moveOnlyArray
.Length());
592 ASSERT_EQ(kMoveOnlyTestArrayLength
, autoMoveOnlyArray
.Length());
595 TYPED_TEST_P(TArray_MoveOnlyTest
,
596 nsTArray_to_AutoTArray_AutoStorage_MoveAssign
) {
597 auto moveOnlyArray
= MakeMoveOnlyArray
<nsTArray
<TypeParam
>>();
598 AutoTArray
<TypeParam
, kMoveOnlyTestArrayLength
> autoMoveOnlyArray
;
599 autoMoveOnlyArray
= std::move(moveOnlyArray
);
601 ASSERT_EQ(0u, moveOnlyArray
.Length());
602 ASSERT_EQ(kMoveOnlyTestArrayLength
, autoMoveOnlyArray
.Length());
605 TYPED_TEST_P(TArray_MoveOnlyTest
,
606 nsTArray_to_AutoTArray_HeapStorage_MoveConstruct
) {
607 auto moveOnlyArray
= MakeMoveOnlyArray
<nsTArray
<TypeParam
>>();
608 AutoTArray
<TypeParam
, kMoveOnlyTestArrayLength
- 1> autoMoveOnlyArray(
609 std::move(moveOnlyArray
));
611 ASSERT_EQ(0u, moveOnlyArray
.Length());
612 ASSERT_EQ(kMoveOnlyTestArrayLength
, autoMoveOnlyArray
.Length());
615 TYPED_TEST_P(TArray_MoveOnlyTest
,
616 nsTArray_to_AutoTArray_HeapStorage_MoveAssign
) {
617 auto moveOnlyArray
= MakeMoveOnlyArray
<nsTArray
<TypeParam
>>();
618 AutoTArray
<TypeParam
, kMoveOnlyTestArrayLength
- 1> autoMoveOnlyArray
;
619 autoMoveOnlyArray
= std::move(moveOnlyArray
);
621 ASSERT_EQ(0u, moveOnlyArray
.Length());
622 ASSERT_EQ(kMoveOnlyTestArrayLength
, autoMoveOnlyArray
.Length());
625 TYPED_TEST_P(TArray_MoveOnlyTest
,
626 FallibleTArray_to_AutoTArray_HeapStorage_MoveConstruct
) {
627 auto moveOnlyArray
= MakeMoveOnlyArray
<FallibleTArray
<TypeParam
>>();
628 AutoTArray
<TypeParam
, 4> autoMoveOnlyArray(std::move(moveOnlyArray
));
630 ASSERT_EQ(0u, moveOnlyArray
.Length());
631 ASSERT_EQ(kMoveOnlyTestArrayLength
, autoMoveOnlyArray
.Length());
634 TYPED_TEST_P(TArray_MoveOnlyTest
,
635 FallibleTArray_to_AutoTArray_HeapStorage_MoveAssign
) {
636 auto moveOnlyArray
= MakeMoveOnlyArray
<FallibleTArray
<TypeParam
>>();
637 AutoTArray
<TypeParam
, 4> autoMoveOnlyArray
;
638 autoMoveOnlyArray
= std::move(moveOnlyArray
);
640 ASSERT_EQ(0u, moveOnlyArray
.Length());
641 ASSERT_EQ(kMoveOnlyTestArrayLength
, autoMoveOnlyArray
.Length());
644 REGISTER_TYPED_TEST_SUITE_P(
645 TArray_MoveOnlyTest
, nsTArray_MoveConstruct
, nsTArray_MoveAssign
,
646 nsTArray_MoveReAssign
, nsTArray_to_FallibleTArray_MoveConstruct
,
647 nsTArray_to_FallibleTArray_MoveAssign
,
648 FallibleTArray_to_nsTArray_MoveConstruct
,
649 FallibleTArray_to_nsTArray_MoveAssign
, AutoTArray_AutoStorage_MoveConstruct
,
650 AutoTArray_AutoStorage_MoveAssign
,
651 nsTArray_to_AutoTArray_AutoStorage_MoveConstruct
,
652 nsTArray_to_AutoTArray_AutoStorage_MoveAssign
,
653 nsTArray_to_AutoTArray_HeapStorage_MoveConstruct
,
654 nsTArray_to_AutoTArray_HeapStorage_MoveAssign
,
655 FallibleTArray_to_AutoTArray_HeapStorage_MoveConstruct
,
656 FallibleTArray_to_AutoTArray_HeapStorage_MoveAssign
);
658 using BothMoveOnlyTypes
=
659 ::testing::Types
<MoveOnly_RelocateUsingMemutils
,
660 MoveOnly_RelocateUsingMoveConstructor
>;
661 INSTANTIATE_TYPED_TEST_SUITE_P(InstantiationOf
, TArray_MoveOnlyTest
,
666 TEST(TArray
, test_string_array
)
668 nsTArray
<nsCString
> strArray
;
669 const char kdata
[] = "hello world";
671 for (i
= 0; i
< ArrayLength(kdata
); ++i
) {
673 str
.Assign(kdata
[i
]);
674 strArray
.AppendElement(str
);
676 for (i
= 0; i
< ArrayLength(kdata
); ++i
) {
677 ASSERT_EQ(strArray
[i
].CharAt(0), kdata
[i
]);
680 const char kextra
[] = "foo bar";
681 size_t oldLen
= strArray
.Length();
682 strArray
.AppendElement(kextra
);
683 strArray
.RemoveElement(kextra
);
684 ASSERT_EQ(oldLen
, strArray
.Length());
686 ASSERT_EQ(strArray
.IndexOf("e"), size_t(1));
687 ASSERT_TRUE(strArray
.ApplyIf(
688 "e", [](size_t i
, nsCString
& s
) { return i
== 1 && s
== "e"; },
689 []() { return false; }));
692 const char ksorted
[] = "\0 dehllloorw";
693 for (i
= ArrayLength(kdata
); i
--;) {
694 ASSERT_EQ(strArray
[i
].CharAt(0), ksorted
[i
]);
695 if (i
> 0 && strArray
[i
] == strArray
[i
- 1]) strArray
.RemoveElementAt(i
);
697 for (i
= 0; i
< strArray
.Length(); ++i
) {
698 ASSERT_EQ(strArray
.BinaryIndexOf(strArray
[i
]), i
);
700 auto no_index
= strArray
.NoIndex
; // Fixes gtest compilation error
701 ASSERT_EQ(strArray
.BinaryIndexOf(""_ns
), no_index
);
703 nsCString rawArray
[MOZ_ARRAY_LENGTH(kdata
) - 1];
704 for (i
= 0; i
< ArrayLength(rawArray
); ++i
)
705 rawArray
[i
].Assign(kdata
+ i
); // substrings of kdata
708 test_basic_array(rawArray
, ArrayLength(rawArray
), nsCString("foopy")));
713 typedef nsCOMPtr
<nsIFile
> FilePointer
;
715 class nsFileNameComparator
{
717 bool Equals(const FilePointer
& a
, const char* b
) const {
719 a
->GetNativeLeafName(name
);
720 return name
.Equals(b
);
724 TEST(TArray
, test_comptr_array
)
727 NS_GetSpecialDirectory(NS_OS_TEMP_DIR
, getter_AddRefs(tmpDir
));
729 const char* kNames
[] = {"foo.txt", "bar.html", "baz.gif"};
730 nsTArray
<FilePointer
> fileArray
;
732 for (i
= 0; i
< ArrayLength(kNames
); ++i
) {
734 tmpDir
->Clone(getter_AddRefs(f
));
736 ASSERT_NS_SUCCEEDED(f
->AppendNative(nsDependentCString(kNames
[i
])));
737 fileArray
.AppendElement(f
);
740 ASSERT_EQ(fileArray
.IndexOf(kNames
[1], 0, nsFileNameComparator()), size_t(1));
741 ASSERT_TRUE(fileArray
.ApplyIf(
742 kNames
[1], 0, nsFileNameComparator(), [](size_t i
) { return i
== 1; },
743 []() { return false; }));
745 // It's unclear what 'operator<' means for nsCOMPtr, but whatever...
747 test_basic_array(fileArray
.Elements(), fileArray
.Length(), tmpDir
));
752 class RefcountedObject
{
754 RefcountedObject() : rc(0) { val
= std::rand(); }
756 MOZ_DIAGNOSTIC_ASSERT(rcchangeallowed
);
760 MOZ_DIAGNOSTIC_ASSERT(rcchangeallowed
);
761 if (--rc
== 0) delete this;
763 ~RefcountedObject() = default;
765 int32_t GetVal() const { return val
; }
767 static void AllowRCChange() { rcchangeallowed
= true; }
768 static void ForbidRCChange() { rcchangeallowed
= false; }
770 bool operator<(const RefcountedObject
& b
) const {
771 return this->GetVal() < b
.GetVal();
774 bool operator==(const RefcountedObject
& b
) const {
775 return this->GetVal() == b
.GetVal();
781 static bool rcchangeallowed
;
783 bool RefcountedObject::rcchangeallowed
= true;
785 class ObjectComparatorRaw
{
787 bool Equals(RefcountedObject
* const& a
, RefcountedObject
* const& b
) const {
788 return a
->GetVal() == b
->GetVal();
791 bool LessThan(RefcountedObject
* const& a
, RefcountedObject
* const& b
) const {
792 return a
->GetVal() < b
->GetVal();
796 class ObjectComparatorRefPtr
{
798 bool Equals(RefPtr
<RefcountedObject
> const& a
,
799 RefPtr
<RefcountedObject
> const& b
) const {
800 return a
->GetVal() == b
->GetVal();
803 bool LessThan(RefPtr
<RefcountedObject
> const& a
,
804 RefPtr
<RefcountedObject
> const& b
) const {
805 return a
->GetVal() < b
->GetVal();
809 TEST(TArray
, test_refptr_array
)
811 nsTArray
<RefPtr
<RefcountedObject
>> objArray
;
813 RefcountedObject
* a
= new RefcountedObject();
815 RefcountedObject
* b
= new RefcountedObject();
817 RefcountedObject
* c
= new RefcountedObject();
820 objArray
.AppendElement(a
);
821 objArray
.AppendElement(b
);
822 objArray
.AppendElement(c
);
824 ASSERT_EQ(objArray
.IndexOf(b
), size_t(1));
825 ASSERT_TRUE(objArray
.ApplyIf(
827 [&](size_t i
, RefPtr
<RefcountedObject
>& r
) { return i
== 1 && r
== b
; },
828 []() { return false; }));
835 TEST(TArray
, test_sort_refptr
)
837 int numobjects
= 1111111;
838 std::vector
<RefPtr
<RefcountedObject
>> myobjects
;
839 for (int i
= 0; i
< numobjects
; i
++) {
840 auto* obj
= new RefcountedObject();
841 myobjects
.push_back(obj
);
845 nsTArray
<RefPtr
<RefcountedObject
>> objArray(numobjects
);
846 std::vector
<RefPtr
<RefcountedObject
>> plainRefPtrArray(numobjects
, nullptr);
848 for (int i
= 0; i
< numobjects
; i
++) {
849 objArray
.AppendElement(myobjects
[i
]);
850 plainRefPtrArray
[i
] = myobjects
[i
];
853 ASSERT_EQ(objArray
.IndexOf(myobjects
[1]), size_t(1));
854 ASSERT_TRUE(objArray
.ApplyIf(
856 [&](size_t i
, RefPtr
<RefcountedObject
>& r
) {
857 return i
== 1 && r
== myobjects
[1];
859 []() { return false; }));
861 // Do not expect that sorting affects the reference counters of elements.
862 RefcountedObject::ForbidRCChange();
864 // Sort objArray with explicit, pointee value based comparator
865 objArray
.Sort(ObjectComparatorRefPtr());
866 for (int i
= 0; i
< numobjects
- 1; i
++) {
867 ASSERT_TRUE(objArray
[i
]->GetVal() <= objArray
[i
+ 1]->GetVal());
870 // std::sort plainRefPtrArray
871 auto comp
= ObjectComparatorRefPtr();
872 std::sort(plainRefPtrArray
.begin(), plainRefPtrArray
.end(),
873 [&comp
](auto const& left
, auto const& right
) {
874 return comp
.LessThan(left
, right
);
877 // We expect the order to be the same.
878 for (int i
= 0; i
< numobjects
; i
++) {
879 ASSERT_TRUE(objArray
[i
]->GetVal() == plainRefPtrArray
[i
]->GetVal());
882 RefcountedObject::AllowRCChange();
883 // Destroy the arrays
886 for (int i
= 0; i
< numobjects
; i
++) {
887 myobjects
.pop_back();
893 TEST(TArray
, test_ptrarray
)
895 nsTArray
<uint32_t*> ary
;
896 ASSERT_EQ(ary
.SafeElementAt(0), nullptr);
897 ASSERT_EQ(ary
.SafeElementAt(1000), nullptr);
900 ary
.AppendElement(&a
);
901 ASSERT_EQ(*ary
[0], a
);
902 ASSERT_EQ(*ary
.SafeElementAt(0), a
);
904 nsTArray
<const uint32_t*> cary
;
905 ASSERT_EQ(cary
.SafeElementAt(0), nullptr);
906 ASSERT_EQ(cary
.SafeElementAt(1000), nullptr);
908 const uint32_t b
= 14;
909 cary
.AppendElement(&a
);
910 cary
.AppendElement(&b
);
911 ASSERT_EQ(*cary
[0], a
);
912 ASSERT_EQ(*cary
[1], b
);
913 ASSERT_EQ(*cary
.SafeElementAt(0), a
);
914 ASSERT_EQ(*cary
.SafeElementAt(1), b
);
919 // This test relies too heavily on the existence of DebugGetHeader to be
920 // useful in non-debug builds.
922 TEST(TArray
, test_autoarray
)
924 uint32_t data
[] = {4, 6, 8, 2, 4, 1, 5, 7, 3};
925 AutoTArray
<uint32_t, MOZ_ARRAY_LENGTH(data
)> array
;
927 void* hdr
= array
.DebugGetHeader();
928 ASSERT_NE(hdr
, nsTArray
<uint32_t>().DebugGetHeader());
930 (AutoTArray
<uint32_t, MOZ_ARRAY_LENGTH(data
)>().DebugGetHeader()));
932 array
.AppendElement(1u);
933 ASSERT_EQ(hdr
, array
.DebugGetHeader());
935 array
.RemoveElement(1u);
936 array
.AppendElements(data
, ArrayLength(data
));
937 ASSERT_EQ(hdr
, array
.DebugGetHeader());
939 array
.AppendElement(2u);
940 ASSERT_NE(hdr
, array
.DebugGetHeader());
944 ASSERT_EQ(hdr
, array
.DebugGetHeader());
945 array
.AppendElements(data
, ArrayLength(data
));
946 ASSERT_EQ(hdr
, array
.DebugGetHeader());
948 nsTArray
<uint32_t> array2
;
949 void* emptyHdr
= array2
.DebugGetHeader();
950 array
.SwapElements(array2
);
951 ASSERT_NE(emptyHdr
, array
.DebugGetHeader());
952 ASSERT_NE(hdr
, array2
.DebugGetHeader());
954 for (i
= 0; i
< ArrayLength(data
); ++i
) {
955 ASSERT_EQ(array2
[i
], data
[i
]);
957 ASSERT_TRUE(array
.IsEmpty());
960 array
.AppendElements(data
, ArrayLength(data
));
961 uint32_t data3
[] = {5, 7, 11};
962 AutoTArray
<uint32_t, MOZ_ARRAY_LENGTH(data3
)> array3
;
963 array3
.AppendElements(data3
, ArrayLength(data3
));
964 array
.SwapElements(array3
);
965 for (i
= 0; i
< ArrayLength(data
); ++i
) {
966 ASSERT_EQ(array3
[i
], data
[i
]);
968 for (i
= 0; i
< ArrayLength(data3
); ++i
) {
969 ASSERT_EQ(array
[i
], data3
[i
]);
976 // IndexOf used to potentially scan beyond the end of the array. Test for
977 // this incorrect behavior by adding a value (5), removing it, then seeing
978 // if IndexOf finds it.
979 TEST(TArray
, test_indexof
)
982 array
.AppendElement(0);
983 // add and remove the 5
984 array
.AppendElement(5);
985 array
.RemoveElementAt(1);
986 // we should not find the 5!
987 auto no_index
= array
.NoIndex
; // Fixes gtest compilation error.
988 ASSERT_EQ(array
.IndexOf(5, 1), no_index
);
989 ASSERT_FALSE(array
.ApplyIf(
990 5, 1, []() { return true; }, []() { return false; }));
995 template <class Array
>
996 static bool is_heap(const Array
& ary
, size_t len
) {
998 while (index
< len
) {
999 if (ary
[index
] > ary
[(index
- 1) >> 1]) return false;
1007 // An array |arr| is using its auto buffer if |&arr < arr.Elements()| and
1008 // |arr.Elements() - &arr| is small.
1010 #define IS_USING_AUTO(arr) \
1011 ((uintptr_t) & (arr) < (uintptr_t)(arr).Elements() && \
1012 ((ptrdiff_t)(arr).Elements() - (ptrdiff_t) & (arr)) <= 16)
1014 #define CHECK_IS_USING_AUTO(arr) \
1016 ASSERT_TRUE(IS_USING_AUTO(arr)); \
1019 #define CHECK_NOT_USING_AUTO(arr) \
1021 ASSERT_FALSE(IS_USING_AUTO(arr)); \
1024 #define CHECK_USES_SHARED_EMPTY_HDR(arr) \
1026 nsTArray<int> _empty; \
1027 ASSERT_EQ(_empty.Elements(), (arr).Elements()); \
1030 #define CHECK_EQ_INT(actual, expected) \
1032 ASSERT_EQ((actual), (expected)); \
1035 #define CHECK_ARRAY(arr, data) \
1037 CHECK_EQ_INT((arr).Length(), (size_t)ArrayLength(data)); \
1038 for (size_t _i = 0; _i < ArrayLength(data); _i++) { \
1039 CHECK_EQ_INT((arr)[_i], (data)[_i]); \
1043 TEST(TArray
, test_swap
)
1045 // Test nsTArray::SwapElements. Unfortunately there are many cases.
1046 int data1
[] = {8, 6, 7, 5};
1047 int data2
[] = {3, 0, 9};
1049 // Swap two auto arrays.
1051 AutoTArray
<int, 8> a
;
1052 AutoTArray
<int, 6> b
;
1054 a
.AppendElements(data1
, ArrayLength(data1
));
1055 b
.AppendElements(data2
, ArrayLength(data2
));
1056 CHECK_IS_USING_AUTO(a
);
1057 CHECK_IS_USING_AUTO(b
);
1061 CHECK_IS_USING_AUTO(a
);
1062 CHECK_IS_USING_AUTO(b
);
1063 CHECK_ARRAY(a
, data2
);
1064 CHECK_ARRAY(b
, data1
);
1067 // Swap two auto arrays -- one whose data lives on the heap, the other whose
1068 // data lives on the stack -- which each fits into the other's auto storage.
1070 AutoTArray
<int, 3> a
;
1071 AutoTArray
<int, 3> b
;
1073 a
.AppendElements(data1
, ArrayLength(data1
));
1074 a
.RemoveElementAt(3);
1075 b
.AppendElements(data2
, ArrayLength(data2
));
1077 // Here and elsewhere, we assert that if we start with an auto array
1078 // capable of storing N elements, we store N+1 elements into the array, and
1079 // then we remove one element, that array is still not using its auto
1082 // This isn't at all required by the TArray API. It would be fine if, when
1083 // we shrink back to N elements, the TArray frees its heap storage and goes
1084 // back to using its stack storage. But we assert here as a check that the
1085 // test does what we expect. If the TArray implementation changes, just
1086 // change the failing assertions.
1087 CHECK_NOT_USING_AUTO(a
);
1089 // This check had better not change, though.
1090 CHECK_IS_USING_AUTO(b
);
1094 CHECK_IS_USING_AUTO(b
);
1095 CHECK_ARRAY(a
, data2
);
1096 int expectedB
[] = {8, 6, 7};
1097 CHECK_ARRAY(b
, expectedB
);
1100 // Swap two auto arrays which are using heap storage such that one fits into
1101 // the other's auto storage, but the other needs to stay on the heap.
1103 AutoTArray
<int, 3> a
;
1104 AutoTArray
<int, 2> b
;
1105 a
.AppendElements(data1
, ArrayLength(data1
));
1106 a
.RemoveElementAt(3);
1108 b
.AppendElements(data2
, ArrayLength(data2
));
1109 b
.RemoveElementAt(2);
1111 CHECK_NOT_USING_AUTO(a
);
1112 CHECK_NOT_USING_AUTO(b
);
1116 CHECK_NOT_USING_AUTO(b
);
1118 int expected1
[] = {3, 0};
1119 int expected2
[] = {8, 6, 7};
1121 CHECK_ARRAY(a
, expected1
);
1122 CHECK_ARRAY(b
, expected2
);
1125 // Swap two arrays, neither of which fits into the other's auto-storage.
1127 AutoTArray
<int, 1> a
;
1128 AutoTArray
<int, 3> b
;
1130 a
.AppendElements(data1
, ArrayLength(data1
));
1131 b
.AppendElements(data2
, ArrayLength(data2
));
1135 CHECK_ARRAY(a
, data2
);
1136 CHECK_ARRAY(b
, data1
);
1139 // Swap an empty nsTArray with a non-empty AutoTArray.
1142 AutoTArray
<int, 3> b
;
1144 b
.AppendElements(data2
, ArrayLength(data2
));
1145 CHECK_IS_USING_AUTO(b
);
1149 CHECK_ARRAY(a
, data2
);
1150 CHECK_EQ_INT(b
.Length(), size_t(0));
1151 CHECK_IS_USING_AUTO(b
);
1154 // Swap two big auto arrays.
1156 const unsigned size
= 8192;
1157 AutoTArray
<unsigned, size
> a
;
1158 AutoTArray
<unsigned, size
> b
;
1160 for (unsigned i
= 0; i
< size
; i
++) {
1162 b
.AppendElement(i
+ 1);
1165 CHECK_IS_USING_AUTO(a
);
1166 CHECK_IS_USING_AUTO(b
);
1170 CHECK_IS_USING_AUTO(a
);
1171 CHECK_IS_USING_AUTO(b
);
1173 CHECK_EQ_INT(a
.Length(), size_t(size
));
1174 CHECK_EQ_INT(b
.Length(), size_t(size
));
1176 for (unsigned i
= 0; i
< size
; i
++) {
1177 CHECK_EQ_INT(a
[i
], i
+ 1);
1178 CHECK_EQ_INT(b
[i
], i
);
1182 // Swap two arrays and make sure that their capacities don't increase
1187 b
.AppendElements(data2
, ArrayLength(data2
));
1189 CHECK_EQ_INT(a
.Capacity(), size_t(0));
1190 size_t bCapacity
= b
.Capacity();
1194 // Make sure that we didn't increase the capacity of either array.
1195 CHECK_ARRAY(a
, data2
);
1196 CHECK_EQ_INT(b
.Length(), size_t(0));
1197 CHECK_EQ_INT(b
.Capacity(), size_t(0));
1198 CHECK_EQ_INT(a
.Capacity(), bCapacity
);
1201 // Swap an auto array with a TArray, then clear the auto array and make sure
1202 // it doesn't forget the fact that it has an auto buffer.
1205 AutoTArray
<int, 3> b
;
1207 a
.AppendElements(data1
, ArrayLength(data1
));
1211 CHECK_EQ_INT(a
.Length(), size_t(0));
1212 CHECK_ARRAY(b
, data1
);
1216 CHECK_USES_SHARED_EMPTY_HDR(a
);
1217 CHECK_IS_USING_AUTO(b
);
1220 // Same thing as the previous test, but with more auto arrays.
1222 AutoTArray
<int, 16> a
;
1223 AutoTArray
<int, 3> b
;
1225 a
.AppendElements(data1
, ArrayLength(data1
));
1229 CHECK_EQ_INT(a
.Length(), size_t(0));
1230 CHECK_ARRAY(b
, data1
);
1234 CHECK_IS_USING_AUTO(a
);
1235 CHECK_IS_USING_AUTO(b
);
1238 // Swap an empty nsTArray and an empty AutoTArray.
1240 AutoTArray
<int, 8> a
;
1245 CHECK_IS_USING_AUTO(a
);
1246 CHECK_NOT_USING_AUTO(b
);
1247 CHECK_EQ_INT(a
.Length(), size_t(0));
1248 CHECK_EQ_INT(b
.Length(), size_t(0));
1251 // Swap empty auto array with non-empty AutoTArray using malloc'ed storage.
1252 // I promise, all these tests have a point.
1254 AutoTArray
<int, 2> a
;
1255 AutoTArray
<int, 1> b
;
1257 a
.AppendElements(data1
, ArrayLength(data1
));
1261 CHECK_IS_USING_AUTO(a
);
1262 CHECK_NOT_USING_AUTO(b
);
1263 CHECK_ARRAY(b
, data1
);
1264 CHECK_EQ_INT(a
.Length(), size_t(0));
1267 // Test fallible SwapElements of nsTArray.
1272 a
.AppendElements(data1
, ArrayLength(data1
));
1274 ASSERT_TRUE(a
.SwapElements(b
, fallible
));
1276 CHECK_ARRAY(b
, data1
);
1277 CHECK_EQ_INT(a
.Length(), size_t(0));
1280 // Test fallible SwapElements of FallibleTArray.
1282 FallibleTArray
<int> a
;
1283 FallibleTArray
<int> b
;
1285 ASSERT_TRUE(a
.AppendElements(data1
, ArrayLength(data1
), fallible
));
1287 ASSERT_TRUE(a
.SwapElements(b
, fallible
));
1289 CHECK_ARRAY(b
, data1
);
1290 CHECK_EQ_INT(a
.Length(), size_t(0));
1293 // Test fallible SwapElements of FallibleTArray with large AutoTArray.
1295 FallibleTArray
<int> a
;
1296 AutoTArray
<int, 8192> b
;
1298 ASSERT_TRUE(a
.AppendElements(data1
, ArrayLength(data1
), fallible
));
1300 ASSERT_TRUE(a
.SwapElements(b
, fallible
));
1302 CHECK_IS_USING_AUTO(b
);
1303 CHECK_ARRAY(b
, data1
);
1304 CHECK_EQ_INT(a
.Length(), size_t(0));
1308 // Bug 1171296: Disabled on andoid due to crashes.
1309 #if !defined(ANDROID)
1310 TEST(TArray
, test_fallible
)
1312 // Test that FallibleTArray works properly; that is, it never OOMs, but
1313 // instead eventually returns false.
1315 // This test is only meaningful on 32-bit systems. On a 64-bit system, we
1317 if (sizeof(void*) > 4) {
1322 // Allocate a bunch of 128MB arrays. Larger allocations will fail on some
1323 // platforms without actually hitting OOM.
1325 // 36 * 128MB > 4GB, so we should definitely OOM by the 36th array.
1326 const unsigned numArrays
= 36;
1327 FallibleTArray
<char> arrays
[numArrays
];
1329 for (size_t i
= 0; i
< numArrays
; i
++) {
1330 // SetCapacity allocates the requested capacity + a header, and we want to
1331 // avoid allocating more than 128MB overall because of the size padding it
1332 // will cause, which depends on allocator behavior, so use 128MB - an
1333 // arbitrary size larger than the array header, so that chances are good
1334 // that allocations will always be 128MB.
1335 bool success
= arrays
[i
].SetCapacity(128 * 1024 * 1024 - 1024, fallible
);
1337 // We got our OOM. Check that it didn't come too early.
1340 // 32-bit Windows sometimes OOMs on the 6th, 7th, or 8th. To keep the
1341 // test green, choose the lower of those: the important thing here is
1342 // that some allocations fail and some succeed. We're not too
1343 // concerned about how many iterations it takes.
1344 const size_t kOOMIterations
= 6;
1346 const size_t kOOMIterations
= 8;
1348 ASSERT_GE(i
, kOOMIterations
)
1349 << "Got OOM on iteration " << i
<< ". Too early!";
1354 << "Didn't OOM or crash? nsTArray::SetCapacity"
1359 TEST(TArray
, test_conversion_operator
)
1361 FallibleTArray
<int> f
;
1362 const FallibleTArray
<int> fconst
;
1365 const nsTArray
<int> tconst
;
1366 AutoTArray
<int, 8> tauto
;
1367 const AutoTArray
<int, 8> tautoconst
;
1369 #define CHECK_ARRAY_CAST(type) \
1371 const type<int>& z1 = f; \
1372 ASSERT_EQ((void*)&z1, (void*)&f); \
1373 const type<int>& z2 = fconst; \
1374 ASSERT_EQ((void*)&z2, (void*)&fconst); \
1375 const type<int>& z9 = t; \
1376 ASSERT_EQ((void*)&z9, (void*)&t); \
1377 const type<int>& z10 = tconst; \
1378 ASSERT_EQ((void*)&z10, (void*)&tconst); \
1379 const type<int>& z11 = tauto; \
1380 ASSERT_EQ((void*)&z11, (void*)&tauto); \
1381 const type<int>& z12 = tautoconst; \
1382 ASSERT_EQ((void*)&z12, (void*)&tautoconst); \
1385 CHECK_ARRAY_CAST(FallibleTArray
);
1386 CHECK_ARRAY_CAST(nsTArray
);
1388 #undef CHECK_ARRAY_CAST
1392 struct BufAccessor
: public T
{
1393 void* GetHdr() { return T::mHdr
; }
1396 TEST(TArray
, test_SetLengthAndRetainStorage_no_ctor
)
1398 // 1050 because sizeof(int)*1050 is more than a page typically.
1400 FallibleTArray
<int> f
;
1403 AutoTArray
<int, N
> tauto
;
1407 #define FOR_EACH(pre, post) \
1414 // Setup test arrays.
1415 FOR_EACH(; Unused
<<, .SetLength(N
, fallible
));
1416 for (int n
= 0; n
< N
; ++n
) {
1417 FOR_EACH(;, [n
] = n
);
1420 void* initial_Hdrs
[] = {
1421 static_cast<BufAccessor
<FallibleTArray
<int>>&>(f
).GetHdr(),
1422 static_cast<BufAccessor
<nsTArray
<int>>&>(t
).GetHdr(),
1423 static_cast<BufAccessor
<AutoTArray
<int, N
>>&>(tauto
).GetHdr(), nullptr};
1425 // SetLengthAndRetainStorage(n), should NOT overwrite memory when T hasn't
1426 // a default constructor.
1427 FOR_EACH(;, .SetLengthAndRetainStorage(8));
1428 FOR_EACH(;, .SetLengthAndRetainStorage(12));
1429 for (int n
= 0; n
< 12; ++n
) {
1432 ASSERT_EQ(tauto
[n
], n
);
1434 FOR_EACH(;, .SetLengthAndRetainStorage(0));
1435 FOR_EACH(;, .SetLengthAndRetainStorage(N
));
1436 for (int n
= 0; n
< N
; ++n
) {
1439 ASSERT_EQ(tauto
[n
], n
);
1442 void* current_Hdrs
[] = {
1443 static_cast<BufAccessor
<FallibleTArray
<int>>&>(f
).GetHdr(),
1444 static_cast<BufAccessor
<nsTArray
<int>>&>(t
).GetHdr(),
1445 static_cast<BufAccessor
<AutoTArray
<int, N
>>&>(tauto
).GetHdr(), nullptr};
1447 // SetLengthAndRetainStorage(n) should NOT have reallocated the internal
1449 ASSERT_EQ(sizeof(initial_Hdrs
), sizeof(current_Hdrs
));
1450 for (size_t n
= 0; n
< sizeof(current_Hdrs
) / sizeof(current_Hdrs
[0]); ++n
) {
1451 ASSERT_EQ(current_Hdrs
[n
], initial_Hdrs
[n
]);
1459 template <typename Comparator
>
1460 bool TestCompareMethods(const Comparator
& aComp
) {
1461 nsTArray
<int> ary({57, 4, 16, 17, 3, 5, 96, 12});
1465 const int sorted
[] = {3, 4, 5, 12, 16, 17, 57, 96};
1466 for (size_t i
= 0; i
< MOZ_ARRAY_LENGTH(sorted
); i
++) {
1467 if (sorted
[i
] != ary
[i
]) {
1472 if (!ary
.ContainsSorted(5, aComp
)) {
1475 if (ary
.ContainsSorted(42, aComp
)) {
1479 if (ary
.BinaryIndexOf(16, aComp
) != 4) {
1486 struct IntComparator
{
1487 bool Equals(int aLeft
, int aRight
) const { return aLeft
== aRight
; }
1489 bool LessThan(int aLeft
, int aRight
) const { return aLeft
< aRight
; }
1492 TEST(TArray
, test_comparator_objects
)
1494 ASSERT_TRUE(TestCompareMethods(IntComparator()));
1496 TestCompareMethods([](int aLeft
, int aRight
) { return aLeft
- aRight
; }));
1500 uint64_t size
[40] = {};
1503 TEST(TArray
, test_AutoTArray_SwapElements
)
1505 AutoTArray
<Big
, 40> oneArray
;
1506 AutoTArray
<Big
, 40> another
;
1508 for (size_t i
= 0; i
< 8; ++i
) {
1509 oneArray
.AppendElement(Big());
1511 oneArray
[0].size
[10] = 1;
1512 for (size_t i
= 0; i
< 9; ++i
) {
1513 another
.AppendElement(Big());
1515 oneArray
.SwapElements(another
);
1517 ASSERT_EQ(oneArray
.Length(), 9u);
1518 ASSERT_EQ(another
.Length(), 8u);
1520 ASSERT_EQ(oneArray
[0].size
[10], 0u);
1521 ASSERT_EQ(another
[0].size
[10], 1u);
1524 } // namespace TestTArray