Bug 1665462 - Add moving Vector::appendAll(Vector&&) overload. r=jwalden

Differential Revision: https://phabricator.services.mozilla.com/D90522
This commit is contained in:
Simon Giesecke 2020-10-29 19:41:43 +00:00
parent d87f6fb19c
commit 29d19d608b
3 changed files with 91 additions and 7 deletions

View File

@ -120,6 +120,11 @@ class GCVector {
MOZ_MUST_USE bool appendAll(const U& aU) {
return vector.append(aU.begin(), aU.end());
}
template <typename T2, size_t MinInlineCapacity2, typename AllocPolicy2>
MOZ_MUST_USE bool appendAll(
GCVector<T2, MinInlineCapacity2, AllocPolicy2>&& aU) {
return vector.appendAll(aU.begin(), aU.end());
}
MOZ_MUST_USE bool appendN(const T& val, size_t count) {
return vector.appendN(val, count);
@ -264,7 +269,7 @@ class MutableWrappedPtrOperations<JS::GCVector<T, Capacity, AllocPolicy>,
vec().infallibleEmplaceBack(std::forward<Args>(args)...);
}
template <typename U>
MOZ_MUST_USE bool appendAll(const U& aU) {
MOZ_MUST_USE bool appendAll(U&& aU) {
return vec().appendAll(aU);
}
MOZ_MUST_USE bool appendN(const T& aT, size_t aN) {

View File

@ -423,6 +423,8 @@ class MOZ_NON_PARAM Vector final : private AllocPolicy {
}
#endif
bool internalEnsureCapacity(size_t aNeeded);
/* Append operations guaranteed to succeed due to pre-reserved space. */
template <typename U>
void internalAppend(U&& aU);
@ -431,6 +433,8 @@ class MOZ_NON_PARAM Vector final : private AllocPolicy {
void internalAppendN(const T& aT, size_t aN);
template <typename U>
void internalAppend(const U* aBegin, size_t aLength);
template <typename U>
void internalMoveAppend(U* aBegin, size_t aLength);
public:
static const size_t sMaxInlineStorage = MinInlineCapacity;
@ -667,11 +671,15 @@ class MOZ_NON_PARAM Vector final : private AllocPolicy {
template <typename U, size_t O, class BP>
MOZ_MUST_USE bool appendAll(const Vector<U, O, BP>& aU);
template <typename U, size_t O, class BP>
MOZ_MUST_USE bool appendAll(Vector<U, O, BP>&& aU);
MOZ_MUST_USE bool appendN(const T& aT, size_t aN);
template <typename U>
MOZ_MUST_USE bool append(const U* aBegin, const U* aEnd);
template <typename U>
MOZ_MUST_USE bool append(const U* aBegin, size_t aLength);
template <typename U>
MOZ_MUST_USE bool moveAppend(U* aBegin, U* aEnd);
/*
* Guaranteed-infallible append operations for use upon vectors whose
@ -1347,11 +1355,8 @@ void Vector<T, N, AP>::eraseIfEqual(const U& aU) {
}
template <typename T, size_t N, class AP>
template <typename U>
MOZ_ALWAYS_INLINE bool Vector<T, N, AP>::append(const U* aInsBegin,
const U* aInsEnd) {
MOZ_REENTRANCY_GUARD_ET_AL;
size_t aNeeded = PointerRangeSize(aInsBegin, aInsEnd);
MOZ_ALWAYS_INLINE bool Vector<T, N, AP>::internalEnsureCapacity(
size_t aNeeded) {
if (mLength + aNeeded > mTail.mCapacity) {
if (MOZ_UNLIKELY(!growStorageBy(aNeeded))) {
return false;
@ -1364,7 +1369,19 @@ MOZ_ALWAYS_INLINE bool Vector<T, N, AP>::append(const U* aInsBegin,
mTail.mReserved = mLength + aNeeded;
}
#endif
internalAppend(aInsBegin, aNeeded);
return true;
}
template <typename T, size_t N, class AP>
template <typename U>
MOZ_ALWAYS_INLINE bool Vector<T, N, AP>::append(const U* aInsBegin,
const U* aInsEnd) {
MOZ_REENTRANCY_GUARD_ET_AL;
const size_t needed = PointerRangeSize(aInsBegin, aInsEnd);
if (!internalEnsureCapacity(needed)) {
return false;
}
internalAppend(aInsBegin, needed);
return true;
}
@ -1378,6 +1395,28 @@ MOZ_ALWAYS_INLINE void Vector<T, N, AP>::internalAppend(const U* aInsBegin,
mLength += aInsLength;
}
template <typename T, size_t N, class AP>
template <typename U>
MOZ_ALWAYS_INLINE bool Vector<T, N, AP>::moveAppend(U* aInsBegin, U* aInsEnd) {
MOZ_REENTRANCY_GUARD_ET_AL;
const size_t needed = PointerRangeSize(aInsBegin, aInsEnd);
if (!internalEnsureCapacity(needed)) {
return false;
}
internalMoveAppend(aInsBegin, needed);
return true;
}
template <typename T, size_t N, class AP>
template <typename U>
MOZ_ALWAYS_INLINE void Vector<T, N, AP>::internalMoveAppend(U* aInsBegin,
size_t aInsLength) {
MOZ_ASSERT(mLength + aInsLength <= mTail.mReserved);
MOZ_ASSERT(mTail.mReserved <= mTail.mCapacity);
Impl::moveConstruct(endNoCheck(), aInsBegin, aInsBegin + aInsLength);
mLength += aInsLength;
}
template <typename T, size_t N, class AP>
template <typename U>
MOZ_ALWAYS_INLINE bool Vector<T, N, AP>::append(U&& aU) {
@ -1405,6 +1444,22 @@ MOZ_ALWAYS_INLINE bool Vector<T, N, AP>::appendAll(
return append(aOther.begin(), aOther.length());
}
template <typename T, size_t N, class AP>
template <typename U, size_t O, class BP>
MOZ_ALWAYS_INLINE bool Vector<T, N, AP>::appendAll(Vector<U, O, BP>&& aOther) {
if (empty() && capacity() < aOther.length()) {
*this = std::move(aOther);
return true;
}
if (moveAppend(aOther.begin(), aOther.end())) {
aOther.clearAndFree();
return true;
}
return false;
}
template <typename T, size_t N, class AP>
template <class U>
MOZ_ALWAYS_INLINE bool Vector<T, N, AP>::append(const U* aInsBegin,

View File

@ -6,9 +6,11 @@
#include <utility>
#include "mozilla/IntegerRange.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Vector.h"
using mozilla::IntegerRange;
using mozilla::MakeUnique;
using mozilla::UniquePtr;
using mozilla::Vector;
@ -25,6 +27,7 @@ struct mozilla::detail::VectorTesting {
static void testInsert();
static void testErase();
static void testShrinkStorageToFit();
static void testAppend();
};
void mozilla::detail::VectorTesting::testReserved() {
@ -662,6 +665,26 @@ void mozilla::detail::VectorTesting::testShrinkStorageToFit() {
}
}
void mozilla::detail::VectorTesting::testAppend() {
// Test moving append/appendAll with a move-only type
Vector<UniquePtr<int>> bv;
for (const int val : IntegerRange<int>(0, 3)) {
MOZ_RELEASE_ASSERT(bv.append(MakeUnique<int>(val)));
}
Vector<UniquePtr<int>> otherbv;
for (const int val : IntegerRange<int>(3, 8)) {
MOZ_RELEASE_ASSERT(otherbv.append(MakeUnique<int>(val)));
}
MOZ_RELEASE_ASSERT(bv.appendAll(std::move(otherbv)));
MOZ_RELEASE_ASSERT(otherbv.length() == 0);
MOZ_RELEASE_ASSERT(bv.length() == 8);
for (const int val : IntegerRange<int>(0, 8)) {
MOZ_RELEASE_ASSERT(*bv[val] == val);
}
}
// Declare but leave (permanently) incomplete.
struct Incomplete;
@ -777,5 +800,6 @@ int main() {
VectorTesting::testInsert();
VectorTesting::testErase();
VectorTesting::testShrinkStorageToFit();
VectorTesting::testAppend();
TestVectorBeginNonNull();
}