From b9ade095dde35c94bdaa5f57909435360eae59ad Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Mon, 11 Dec 2023 17:06:08 +0000 Subject: [PATCH] Bug 1869256 - Add move assignment operator for SegmentedVector r=mccr8 The patch implements the move assigment operator in terms of the move constructor. This fulfills the requirements for std::swap to compile. Differential Revision: https://phabricator.services.mozilla.com/D196035 --- mfbt/SegmentedVector.h | 7 ++++ mfbt/tests/TestSegmentedVector.cpp | 63 +++++++++++++++++++----------- 2 files changed, 48 insertions(+), 22 deletions(-) diff --git a/mfbt/SegmentedVector.h b/mfbt/SegmentedVector.h index 05f1a4c53189..c22c3e8d1f53 100644 --- a/mfbt/SegmentedVector.h +++ b/mfbt/SegmentedVector.h @@ -137,6 +137,13 @@ class SegmentedVector : private AllocPolicy { SegmentedVector(SegmentedVector&& aOther) : mSegments(std::move(aOther.mSegments)) {} + SegmentedVector& operator=(SegmentedVector&& aOther) { + if (&aOther != this) { + this->~SegmentedVector(); + new (this) SegmentedVector(std::move(aOther)); + } + return *this; + } ~SegmentedVector() { Clear(); } diff --git a/mfbt/tests/TestSegmentedVector.cpp b/mfbt/tests/TestSegmentedVector.cpp index 4cfa19c09ae1..dd569ea7b6dc 100644 --- a/mfbt/tests/TestSegmentedVector.cpp +++ b/mfbt/tests/TestSegmentedVector.cpp @@ -35,6 +35,17 @@ class InfallibleAllocPolicy { } }; +template +void CheckContents(Vector& vector, size_t expectedLength) { + MOZ_RELEASE_ASSERT(vector.Length() == expectedLength); + size_t n = 0; + for (auto iter = vector.Iter(); !iter.Done(); iter.Next()) { + MOZ_RELEASE_ASSERT(iter.Get() == int(n)); + n++; + } + MOZ_RELEASE_ASSERT(n == expectedLength); +} + // We want to test Append(), which is fallible and marked with // [[nodiscard]]. But we're using an infallible alloc policy, and so // don't really need to check the result. Casting to |void| works with clang @@ -47,7 +58,7 @@ void TestBasics() { // A SegmentedVector with a POD element type. typedef SegmentedVector MyVector; MyVector v; - int i, n; + int i; MOZ_RELEASE_ASSERT(v.IsEmpty()); @@ -57,28 +68,14 @@ void TestBasics() { gDummy = v.Append(std::move(i)); } MOZ_RELEASE_ASSERT(!v.IsEmpty()); - MOZ_RELEASE_ASSERT(v.Length() == 100); - - n = 0; - for (auto iter = v.Iter(); !iter.Done(); iter.Next()) { - MOZ_RELEASE_ASSERT(iter.Get() == n); - n++; - } - MOZ_RELEASE_ASSERT(n == 100); + CheckContents(v, 100); // Add another 900 elements, then re-check. for (; i < 1000; i++) { v.InfallibleAppend(std::move(i)); } MOZ_RELEASE_ASSERT(!v.IsEmpty()); - MOZ_RELEASE_ASSERT(v.Length() == 1000); - - n = 0; - for (auto iter = v.Iter(); !iter.Done(); iter.Next()) { - MOZ_RELEASE_ASSERT(iter.Get() == n); - n++; - } - MOZ_RELEASE_ASSERT(n == 1000); + CheckContents(v, 1000); // Pop off all of the elements. MOZ_RELEASE_ASSERT(v.Length() == 1000); @@ -112,12 +109,33 @@ void TestBasics() { MOZ_RELEASE_ASSERT(v.Length() == 700); // Verify the contents are what we expect. - n = 0; - for (auto iter = v.Iter(); !iter.Done(); iter.Next()) { - MOZ_RELEASE_ASSERT(iter.Get() == n); - n++; + CheckContents(v, 700); +} + +void TestMoveAndSwap() { + typedef SegmentedVector MyVector; + MyVector v; + + for (int i = 0; i < 100; i++) { + (void)v.Append(i); } - MOZ_RELEASE_ASSERT(n == 700); + MOZ_RELEASE_ASSERT(!v.IsEmpty()); + CheckContents(v, 100); + + // Test move constructor. + MyVector w(std::move(v)); + CheckContents(w, 100); + MOZ_RELEASE_ASSERT(v.IsEmpty()); + + // Test move assignment. + v = std::move(w); + CheckContents(v, 100); + MOZ_RELEASE_ASSERT(w.IsEmpty()); + + // Test swap. + std::swap(v, w); + CheckContents(w, 100); + MOZ_RELEASE_ASSERT(v.IsEmpty()); } static size_t gNumDefaultCtors; @@ -361,6 +379,7 @@ void TestIterator() { int main(void) { TestBasics(); + TestMoveAndSwap(); TestConstructorsAndDestructors(); TestSegmentCapacitiesAndAlignments(); TestIterator();