Bug 1562789 - SmallPointerArray should support moves, and have an IsEmpty() helper. r=froydnj

This also implicitly deletes its copy-assignment operator and copy-constructor,
which is great since it's a huge footgun.

Differential Revision: https://phabricator.services.mozilla.com/D36549
This commit is contained in:
Emilio Cobos Álvarez
2019-07-02 18:50:04 +00:00
parent cdae31ad02
commit a2765d482b
2 changed files with 53 additions and 1 deletions

View File

@@ -10,6 +10,7 @@
#define mozilla_SmallPointerArray_h
#include "mozilla/Assertions.h"
#include "mozilla/PodOperations.h"
#include <algorithm>
#include <iterator>
@@ -19,7 +20,7 @@
namespace mozilla {
// Array class for situations where a small number of NON-NULL elements (<= 2)
// is expected, a large number of elements must be accomodated if necessary,
// is expected, a large number of elements must be accommodated if necessary,
// and the size of the class must be minimal. Typical vector implementations
// will fulfill the first two requirements by simply adding inline storage
// alongside the rest of their member variables. While this strategy works,
@@ -49,6 +50,17 @@ class SmallPointerArray {
}
}
SmallPointerArray(SmallPointerArray&& aOther) {
PodCopy(mArray, aOther.mArray, 2);
aOther.mArray[0].mValue = nullptr;
aOther.mArray[1].mVector = nullptr;
}
SmallPointerArray& operator=(SmallPointerArray&& aOther) {
std::swap(mArray, aOther.mArray);
return *this;
}
void Clear() {
if (first()) {
first() = nullptr;
@@ -160,6 +172,8 @@ class SmallPointerArray {
return 0;
}
bool IsEmpty() const { return Length() == 0; }
T* ElementAt(size_t aIndex) const {
MOZ_ASSERT(aIndex < Length());
if (first()) {

View File

@@ -192,8 +192,46 @@ void TestRangeBasedLoops() {
MOZ_RELEASE_ASSERT(entries == 0);
}
void TestMove() {
using namespace mozilla;
SmallPointerArray<void> testArray;
testArray.AppendElement(PTR1);
testArray.AppendElement(PTR2);
SmallPointerArray<void> moved = std::move(testArray);
MOZ_RELEASE_ASSERT(testArray.IsEmpty());
MOZ_RELEASE_ASSERT(moved.Length() == 2);
MOZ_RELEASE_ASSERT(moved[0] == PTR1);
MOZ_RELEASE_ASSERT(moved[1] == PTR2);
// Heap case.
moved.AppendElement(PTR3);
SmallPointerArray<void> another = std::move(moved);
MOZ_RELEASE_ASSERT(testArray.IsEmpty());
MOZ_RELEASE_ASSERT(moved.IsEmpty());
MOZ_RELEASE_ASSERT(another.Length() == 3);
MOZ_RELEASE_ASSERT(another[0] == PTR1);
MOZ_RELEASE_ASSERT(another[1] == PTR2);
MOZ_RELEASE_ASSERT(another[2] == PTR3);
// Move assignment.
testArray = std::move(another);
MOZ_RELEASE_ASSERT(moved.IsEmpty());
MOZ_RELEASE_ASSERT(another.IsEmpty());
MOZ_RELEASE_ASSERT(testArray.Length() == 3);
MOZ_RELEASE_ASSERT(testArray[0] == PTR1);
MOZ_RELEASE_ASSERT(testArray[1] == PTR2);
MOZ_RELEASE_ASSERT(testArray[2] == PTR3);
}
int main() {
TestArrayManipulation();
TestRangeBasedLoops();
TestMove();
return 0;
}