/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim:set ts=2 sw=2 sts=2 et cindent: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Define this so we can use test_basic_array in test_comptr_array template <class T> inlinebooloperator<(const nsCOMPtr<T>& lhs, const nsCOMPtr<T>& rhs) { return lhs.get() < rhs.get();
}
ary.AppendElements(data, dataLen); if (ary.Length() != dataLen) { returnfalse;
} if (!(ary == ary)) { returnfalse;
}
size_t i; for (i = 0; i < ary.Length(); ++i) { if (ary[i] != data[i]) returnfalse;
} for (i = 0; i < ary.Length(); ++i) { if (ary.SafeElementAt(i, extra) != data[i]) returnfalse;
} if (ary.SafeElementAt(ary.Length(), extra) != extra ||
ary.SafeElementAt(ary.Length() * 10, extra) != extra) returnfalse; // ensure sort results in ascending order
ary.Sort();
size_t j = 0, k = ary.IndexOfFirstElementGt(extra); if (k != 0 && ary[k - 1] == extra) returnfalse; for (i = 0; i < ary.Length(); ++i) {
k = ary.IndexOfFirstElementGt(ary[i]); if (k == 0 || ary[k - 1] != ary[i]) returnfalse; if (k < j) returnfalse;
j = k;
} for (i = ary.Length(); --i;) { if (ary[i] < ary[i - 1]) returnfalse; if (ary[i] == ary[i - 1]) ary.RemoveElementAt(i);
} if (!(ary == ary)) { returnfalse;
} for (i = 0; i < ary.Length(); ++i) { if (ary.BinaryIndexOf(ary[i]) != i) returnfalse;
} if (ary.BinaryIndexOf(extra) != ary.NoIndex) returnfalse;
size_t oldLen = ary.Length();
ary.RemoveElement(data[dataLen / 2]); if (ary.Length() != (oldLen - 1)) returnfalse; if (!(ary == ary)) returnfalse;
if (ary.ApplyIf(extra, []() { returntrue; }, []() { returnfalse; })) returnfalse; if (ary.ApplyIf(extra, [](size_t) { returntrue; }, []() { returnfalse; })) returnfalse; // On a non-const array, ApplyIf's first lambda may use either const or non- // const element types. if (ary.ApplyIf(
extra, [](ElementType&) { returntrue; }, []() { returnfalse; })) returnfalse; if (ary.ApplyIf(
extra, [](const ElementType&) { returntrue; },
[]() { returnfalse; })) returnfalse; if (ary.ApplyIf(
extra, [](size_t, ElementType&) { returntrue; },
[]() { returnfalse; })) returnfalse; if (ary.ApplyIf(
extra, [](size_t, const ElementType&) { returntrue; },
[]() { returnfalse; })) returnfalse;
if (cary.ApplyIf(extra, []() { returntrue; }, []() { returnfalse; })) if (cary.ApplyIf(
extra, [](size_t) { returntrue; }, []() { returnfalse; })) // On a const array, ApplyIf's first lambda must only use const element // types. if (cary.ApplyIf(
extra, [](const ElementType&) { returntrue; },
[]() { returnfalse; })) if (cary.ApplyIf(
extra, [](size_t, const ElementType&) { returntrue; },
[]() { returnfalse; })) returnfalse;
size_t index = ary.Length() / 2;
ary.InsertElementAt(index, extra); if (!(ary == ary)) returnfalse; if (ary[index] != extra) returnfalse; if (ary.IndexOf(extra) == ary.NoIndex) returnfalse; if (ary.LastIndexOf(extra) == ary.NoIndex) returnfalse; // ensure proper searching if (ary.IndexOf(extra) > ary.LastIndexOf(extra)) returnfalse; if (ary.IndexOf(extra, index) != ary.LastIndexOf(extra, index)) returnfalse; if (!ary.ApplyIf(
extra,
[&](size_t i, const ElementType& e) { return i == index && e == extra;
},
[]() { returnfalse; })) returnfalse; if (!cary.ApplyIf(
extra,
[&](size_t i, const ElementType& e) { return i == index && e == extra;
},
[]() { returnfalse; })) returnfalse;
nsTArray<ElementType> copy(ary.Clone()); if (!(ary == copy)) returnfalse; for (i = 0; i < copy.Length(); ++i) { if (ary[i] != copy[i]) returnfalse;
}
ary.AppendElements(copy);
size_t cap = ary.Capacity();
ary.RemoveElementsAt(copy.Length(), copy.Length());
ary.Compact(); if (ary.Capacity() == cap) returnfalse;
ary.Clear(); if (ary.IndexOf(extra) != ary.NoIndex) returnfalse; if (ary.LastIndexOf(extra) != ary.NoIndex) returnfalse; if (ary.ApplyIf(extra, []() { returntrue; }, []() { returnfalse; })) returnfalse; if (cary.ApplyIf(extra, []() { returntrue; }, []() { returnfalse; })) returnfalse;
ary.Clear(); if (!ary.IsEmpty()) returnfalse; if (!(ary == nsTArray<ElementType>())) returnfalse; if (ary == copy) returnfalse; if (ary.SafeElementAt(0, extra) != extra ||
ary.SafeElementAt(10, extra) != extra) returnfalse;
ary = copy; if (!(ary == copy)) returnfalse; for (i = 0; i < copy.Length(); ++i) { if (ary[i] != copy[i]) returnfalse;
}
ary.InsertElementsAt(0, copy); if (ary == copy) returnfalse;
ary.RemoveElementsAt(0, copy.Length()); for (i = 0; i < copy.Length(); ++i) { if (ary[i] != copy[i]) returnfalse;
}
// These shouldn't crash!
nsTArray<ElementType> empty;
ary.AppendElements(reinterpret_cast<ElementType*>(0), 0);
ary.AppendElements(empty);
// See bug 324981
ary.RemoveElement(extra);
ary.RemoveElement(extra);
TYPED_TEST_P(TArray_MoveOnlyTest, nsTArray_MoveReAssign) {
nsTArray<TypeParam> movedMoveOnlyArray;
movedMoveOnlyArray = MakeMoveOnlyArray<nsTArray<TypeParam>>(); // Re-assign, to check that move-assign does not only work on an empty array.
movedMoveOnlyArray = MakeMoveOnlyArray<nsTArray<TypeParam>>();
// It's unclear what 'operator<' means for nsCOMPtr, but whatever...
ASSERT_TRUE(
test_basic_array(fileArray.Elements(), fileArray.Length(), tmpDir));
}
RefcountedObject* a = new RefcountedObject();
a->AddRef();
RefcountedObject* b = new RefcountedObject();
b->AddRef();
RefcountedObject* c = new RefcountedObject();
c->AddRef();
for (int i = 0; i < numobjects; i++) {
objArray.AppendElement(myobjects[i]);
plainRefPtrArray[i] = myobjects[i];
}
ASSERT_EQ(objArray.IndexOf(myobjects[1]), size_t(1));
ASSERT_TRUE(objArray.ApplyIf(
myobjects[1],
[&](size_t i, RefPtr<RefcountedObject>& r) { return i == 1 && r == myobjects[1];
},
[]() { returnfalse; }));
// Do not expect that sorting affects the reference counters of elements.
RefcountedObject::ForbidRCChange();
// Sort objArray with explicit, pointee value based comparator
objArray.Sort(ObjectComparatorRefPtr()); for (int i = 0; i < numobjects - 1; i++) {
ASSERT_TRUE(objArray[i]->GetVal() <= objArray[i + 1]->GetVal());
}
// This test relies too heavily on the existence of DebugGetHeader to be // useful in non-debug builds. #ifdef DEBUG
TEST(TArray, test_autoarray)
{
uint32_t data[] = {4, 6, 8, 2, 4, 1, 5, 7, 3};
AutoTArray<uint32_t, std::size(data)> array;
nsTArray<uint32_t> array2; void* emptyHdr = array2.DebugGetHeader();
array.SwapElements(array2);
ASSERT_NE(emptyHdr, array.DebugGetHeader());
ASSERT_NE(hdr, array2.DebugGetHeader());
size_t i; for (i = 0; i < std::size(data); ++i) {
ASSERT_EQ(array2[i], data[i]);
}
ASSERT_TRUE(array.IsEmpty());
array.Compact();
array.AppendElements(data, std::size(data));
uint32_t data3[] = {5, 7, 11};
AutoTArray<uint32_t, std::size(data3)> array3;
array3.AppendElements(data3, std::size(data3));
array.SwapElements(array3); for (i = 0; i < std::size(data); ++i) {
ASSERT_EQ(array3[i], data[i]);
} for (i = 0; i < std::size(data3); ++i) {
ASSERT_EQ(array[i], data3[i]);
}
} #endif
//----
// IndexOf used to potentially scan beyond the end of the array. Test for // this incorrect behavior by adding a value (5), removing it, then seeing // if IndexOf finds it.
TEST(TArray, test_indexof)
{
nsTArray<int> array;
array.AppendElement(0); // add and remove the 5
array.AppendElement(5);
array.RemoveElementAt(1); // we should not find the 5! auto no_index = array.NoIndex; // Fixes gtest compilation error.
ASSERT_EQ(array.IndexOf(5, 1), no_index);
ASSERT_FALSE(
array.ApplyIf(5, 1, []() { returntrue; }, []() { returnfalse; }));
}
// Swap two auto arrays -- one whose data lives on the heap, the other whose // data lives on the stack -- which each fits into the other's auto storage.
{
AutoTArray<int, 3> a;
AutoTArray<int, 3> b;
// Here and elsewhere, we assert that if we start with an auto array // capable of storing N elements, we store N+1 elements into the array, and // then we remove one element, that array is still not using its auto // buffer. // // This isn't at all required by the TArray API. It would be fine if, when // we shrink back to N elements, the TArray frees its heap storage and goes // back to using its stack storage. But we assert here as a check that the // test does what we expect. If the TArray implementation changes, just // change the failing assertions.
CHECK_NOT_USING_AUTO(a);
// This check had better not change, though.
CHECK_IS_USING_AUTO(b);
// Swap two auto arrays which are using heap storage such that one fits into // the other's auto storage, but the other needs to stay on the heap.
{
AutoTArray<int, 3> a;
AutoTArray<int, 2> b;
a.AppendElements(data1, std::size(data1));
a.RemoveElementAt(3);
for (unsigned i = 0; i < size; i++) {
CHECK_EQ_INT(a[i], i + 1);
CHECK_EQ_INT(b[i], i);
}
}
// Swap two arrays and make sure that their capacities don't increase // unnecessarily.
{
nsTArray<int> a;
nsTArray<int> b;
b.AppendElements(data2, std::size(data2));
// Make sure that we didn't increase the capacity of either array.
CHECK_ARRAY(a, data2);
CHECK_EQ_INT(b.Length(), size_t(0));
CHECK_EQ_INT(b.Capacity(), size_t(0));
CHECK_EQ_INT(a.Capacity(), bCapacity);
}
// Swap an auto array with a TArray, then clear the auto array and make sure // it doesn't forget the fact that it has an auto buffer.
{
nsTArray<int> a;
AutoTArray<int, 3> b;
// Swap empty auto array with non-empty AutoTArray using malloc'ed storage. // I promise, all these tests have a point.
{
AutoTArray<int, 2> a;
AutoTArray<int, 1> b;
// Bug 1171296: Disabled on andoid due to crashes. #if !defined(ANDROID)
TEST(TArray, test_fallible)
{ // Test that FallibleTArray works properly; that is, it never OOMs, but // instead eventually returns false. // // This test is only meaningful on 32-bit systems. On a 64-bit system, we // might never OOM. if (sizeof(void*) > 4) {
ASSERT_TRUE(true); return;
}
// Allocate a bunch of 128MB arrays. Larger allocations will fail on some // platforms without actually hitting OOM. // // 36 * 128MB > 4GB, so we should definitely OOM by the 36th array. constunsigned numArrays = 36;
FallibleTArray<char> arrays[numArrays]; bool oomed = false; for (size_t i = 0; i < numArrays; i++) { // SetCapacity allocates the requested capacity + a header, and we want to // avoid allocating more than 128MB overall because of the size padding it // will cause, which depends on allocator behavior, so use 128MB - an // arbitrary size larger than the array header, so that chances are good // that allocations will always be 128MB. bool success = arrays[i].SetCapacity(128 * 1024 * 1024 - 1024, fallible); if (!success) { // We got our OOM. Check that it didn't come too early.
oomed = true; # ifdef XP_WIN // 32-bit Windows sometimes OOMs on the 6th, 7th, or 8th. To keep the // test green, choose the lower of those: the important thing here is // that some allocations fail and some succeed. We're not too // concerned about how many iterations it takes. const size_t kOOMIterations = 6; # else const size_t kOOMIterations = 8; # endif
ASSERT_GE(i, kOOMIterations)
<< "Got OOM on iteration " << i << ". Too early!";
}
}
ASSERT_TRUE(oomed)
<< "Didn't OOM or crash? nsTArray::SetCapacity" "must be lying.";
} #endif
template <class T> struct BufAccessor : public T { void* GetHdr() { return T::mHdr; }
};
TEST(TArray, test_SetLengthAndRetainStorage_no_ctor)
{ // 1050 because sizeof(int)*1050 is more than a page typically. constint N = 1050;
FallibleTArray<int> f;
nsTArray<int> t;
AutoTArray<int, N> tauto;
#define LPAREN ( #define RPAREN ) #define FOR_EACH(pre, post) \ do { \
pre f post; \
pre t post; \
pre tauto post; \
} while (0)
// Setup test arrays.
FOR_EACH(; Unused <<, .SetLength(N, fallible)); for (int n = 0; n < N; ++n) {
FOR_EACH(;, [n] = n);
}
// SetLengthAndRetainStorage(n), should NOT overwrite memory when T hasn't // a default constructor.
FOR_EACH(;, .SetLengthAndRetainStorage(8));
FOR_EACH(;, .SetLengthAndRetainStorage(12)); for (int n = 0; n < 12; ++n) {
ASSERT_EQ(f[n], n);
ASSERT_EQ(t[n], n);
ASSERT_EQ(tauto[n], n);
}
FOR_EACH(;, .SetLengthAndRetainStorage(0));
FOR_EACH(;, .SetLengthAndRetainStorage(N)); for (int n = 0; n < N; ++n) {
ASSERT_EQ(f[n], n);
ASSERT_EQ(t[n], n);
ASSERT_EQ(tauto[n], n);
}
// SetLengthAndRetainStorage(n) should NOT have reallocated the internal // memory.
ASSERT_EQ(sizeof(initial_Hdrs), sizeof(current_Hdrs)); for (size_t n = 0; n < sizeof(current_Hdrs) / sizeof(current_Hdrs[0]); ++n) {
ASSERT_EQ(current_Hdrs[n], initial_Hdrs[n]);
}
for (size_t i = 0; i < 8; ++i) {
oneArray.AppendElement(Big());
}
oneArray[0].size[10] = 1; for (size_t i = 0; i < 9; ++i) {
another.AppendElement(Big());
}
oneArray.SwapElements(another);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.