diff --git a/xpcom/glue/nsDeque.cpp b/xpcom/glue/nsDeque.cpp index e8a28c6a9690..c5c31c9964a4 100644 --- a/xpcom/glue/nsDeque.cpp +++ b/xpcom/glue/nsDeque.cpp @@ -369,6 +369,31 @@ nsDeque::ObjectAt(int32_t aIndex) const return result; } +void* +nsDeque::RemoveObjectAt(int32_t aIndex) +{ + if (aIndex < 0 || aIndex >= mSize) { + return 0; + } + void* result = mData[modulus(mOrigin + aIndex, mCapacity)]; + + // "Shuffle down" all elements in the array by 1, overwritting the element + // being removed. + for (int32_t i = aIndex; i < mSize; ++i) { + mData[modulus(mOrigin + i, mCapacity)] = + mData[modulus(mOrigin + i + 1, mCapacity)]; + } + mSize--; + + return result; +} + +void* +nsDeque::Last() const +{ + return ObjectAt(mSize - 1); +} + /** * Call this method when you want to iterate all the * members of the container, passing a functor along @@ -384,3 +409,24 @@ nsDeque::ForEach(nsDequeFunctor& aFunctor) const aFunctor(ObjectAt(i)); } } + +/** + * Call this method when you want to iterate all the + * members of the container, calling the functor you + * passed with each member. This process will interrupt + * if your function returns non 0 to this method. + * + * @param aFunctor object to call for each member + * @return first nonzero result of aFunctor or 0. + */ +const void* +nsDeque::FirstThat(nsDequeFunctor& aFunctor) const +{ + for (int32_t i = 0; i < mSize; ++i) { + void* obj = aFunctor(ObjectAt(i)); + if (obj) { + return obj; + } + } + return 0; +} diff --git a/xpcom/glue/nsDeque.h b/xpcom/glue/nsDeque.h index 1b06899e7828..371868184768 100644 --- a/xpcom/glue/nsDeque.h +++ b/xpcom/glue/nsDeque.h @@ -140,6 +140,14 @@ public: */ void* ObjectAt(int aIndex) const; + /** + * Removes and returns the a member from the deque. + * + * @param index of desired item + * @return element which was removed + */ + void* RemoveObjectAt(int aIndex); + /** * Remove all items from container without destroying them. */ @@ -152,6 +160,8 @@ public: */ void Erase(); + void* Last() const; + /** * Call this method when you want to iterate all the * members of the container, passing a functor along @@ -161,6 +171,17 @@ public: */ void ForEach(nsDequeFunctor& aFunctor) const; + /** + * Call this method when you want to iterate all the + * members of the container, calling the functor you + * passed with each member. This process will interrupt + * if your function returns non 0 to this method. + * + * @param aFunctor object to call for each member + * @return first nonzero result of aFunctor or 0. + */ + const void* FirstThat(nsDequeFunctor& aFunctor) const; + void SetDeallocator(nsDequeFunctor* aDeallocator); size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; diff --git a/xpcom/glue/tests/gtest/TestNsDeque.cpp b/xpcom/glue/tests/gtest/TestNsDeque.cpp index 9767770254ea..6a387c1dc897 100644 --- a/xpcom/glue/tests/gtest/TestNsDeque.cpp +++ b/xpcom/glue/tests/gtest/TestNsDeque.cpp @@ -63,6 +63,24 @@ namespace TestNsDeque { int GetSum() { return sum; } }; + + + class NumberSevenFinder: public nsDequeFunctor + { + virtual void* operator()(void* aObject) + { + if (aObject) + { + int value = *(int*)aObject; + if (value == 7) + { + return (int*)1; + } + } + + return 0; + } + }; } using namespace TestNsDeque; @@ -183,7 +201,7 @@ TEST(NsDeque, OriginalFlaw) -TEST(NsDeque, TestObjectAt) +TEST(NsDeque, TestRemove) { nsDeque d; const int count = 10; @@ -199,11 +217,39 @@ TEST(NsDeque, TestObjectAt) d.PopFront(); d.PopFront(); - // d = [2..5] + // d = [2,5] for (int i=2; i<=5; i++) { int t = *(int*)d.ObjectAt(i-2); EXPECT_EQ(i,t) << "Verify ObjectAt()"; } + + d.RemoveObjectAt(1); + // d == [2,4,5] + static const int t1[] = {2,4,5}; + EXPECT_TRUE(VerifyContents(d, t1, 3)) << "verify contents t1"; + + d.PushFront(&ints[1]); + d.PushFront(&ints[0]); + d.PushFront(&ints[7]); + d.PushFront(&ints[6]); + // d == [6,7,0,1,2,4,5] // (0==mOrigin) + static const int t2[] = {6,7,0,1,2,4,5}; + EXPECT_TRUE(VerifyContents(d, t2, 7)) << "verify contents t2"; + + d.RemoveObjectAt(1); + // d == [6,0,1,2,4,5] // (1==mOrigin) + static const int t3[] = {6,0,1,2,4,5}; + EXPECT_TRUE(VerifyContents(d, t3, 6)) << "verify contents t3"; + + d.RemoveObjectAt(5); + // d == [6,0,1,2,4] // (1==mOrigin) + static const int t4[] = {6,0,1,2,4}; + EXPECT_TRUE(VerifyContents(d, t4, 5)) << "verify contents t4"; + + d.RemoveObjectAt(0); + // d == [0,1,2,4] // (2==mOrigin) + static const int t5[] = {0,1,2,4}; + EXPECT_TRUE(VerifyContents(d, t5, 4)) << "verify contents t5"; } TEST(NsDeque, TestPushFront) @@ -258,6 +304,7 @@ TEST(NsDeque,TestEmpty) EXPECT_EQ(nullptr, d.Peek()) << "Invalid operation should return nullptr"; EXPECT_EQ(nullptr, d.PeekFront()) << "Invalid operation should return nullptr"; EXPECT_EQ(nullptr, d.ObjectAt(0)) << "Invalid operation should return nullptr"; + EXPECT_EQ(nullptr, d.Last()) << "Invalid operation should return nullptr"; // Fill it up and drain it. for (size_t i = 0; i < numberOfEntries; i++) { @@ -277,6 +324,7 @@ TEST(NsDeque,TestEmpty) EXPECT_EQ(nullptr, d.Peek()) << "Invalid operation should return nullptr"; EXPECT_EQ(nullptr, d.PeekFront()) <<"Invalid operation should return nullptr"; EXPECT_EQ(nullptr, d.ObjectAt(0)) << "Invalid operation should return nullptr"; + EXPECT_EQ(nullptr, d.Last()) <<"Invalid operation should return nullptr"; } TEST(NsDeque,TestEmptyMethod) @@ -299,6 +347,7 @@ TEST(NsDeque,TestEmptyMethod) EXPECT_EQ(nullptr, d.Peek()) << "Invalid operation should return nullptr"; EXPECT_EQ(nullptr, d.PeekFront()) <<"Invalid operation should return nullptr"; EXPECT_EQ(nullptr, d.ObjectAt(0)) << "Invalid operation should return nullptr"; + EXPECT_EQ(nullptr, d.Last()) <<"Invalid operation should return nullptr"; // Fill it up before calling Erase for (size_t i = 0; i < numberOfEntries; i++) { @@ -315,6 +364,7 @@ TEST(NsDeque,TestEmptyMethod) EXPECT_EQ(nullptr, d.Peek()) << "Invalid operation should return nullptr"; EXPECT_EQ(nullptr, d.PeekFront()) <<"Invalid operation should return nullptr"; EXPECT_EQ(nullptr, d.ObjectAt(0)) << "Invalid operation should return nullptr"; + EXPECT_EQ(nullptr, d.Last()) <<"Invalid operation should return nullptr"; } TEST(NsDeque,TestEraseShouldCallDeallocator) @@ -339,6 +389,7 @@ TEST(NsDeque,TestEraseShouldCallDeallocator) EXPECT_EQ(nullptr, d.Peek()) << "Invalid operation should return nullptr"; EXPECT_EQ(nullptr, d.PeekFront()) <<"Invalid operation should return nullptr"; EXPECT_EQ(nullptr, d.ObjectAt(0)) << "Invalid operation should return nullptr"; + EXPECT_EQ(nullptr, d.Last()) <<"Invalid operation should return nullptr"; for (size_t i=0; i < NumTestValues; i++) { @@ -368,6 +419,7 @@ TEST(NsDeque,TestEmptyShouldNotCallDeallocator) EXPECT_EQ(nullptr, d.Peek()) << "Invalid operation should return nullptr"; EXPECT_EQ(nullptr, d.PeekFront()) <<"Invalid operation should return nullptr"; EXPECT_EQ(nullptr, d.ObjectAt(0)) << "Invalid operation should return nullptr"; + EXPECT_EQ(nullptr, d.Last()) <<"Invalid operation should return nullptr"; for (size_t i=0; i < NumTestValues; i++) { @@ -394,5 +446,9 @@ TEST(NsDeque, TestForEachAndFirstThat) d.ForEach(adder); EXPECT_EQ(sum, adder.GetSum()) << "For each should iterate over values"; + NumberSevenFinder finder; + const int* value = (const int*)d.FirstThat(finder); + EXPECT_EQ(7, *value) << "FirstThat should return value matching functor"; + d.Erase(); }