зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1539322
- Add Vector::eraseIf and Vector::eraseIfEqual - r=froydnj
Convenience functions to erase elements based on a predicate, or by comparing to a value. They are optimized to use the minimal amount of moves necessary. Differential Revision: https://phabricator.services.mozilla.com/D25016 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
d2abc5343d
Коммит
d8e4582b6c
|
@ -800,6 +800,20 @@ class MOZ_NON_PARAM Vector final : private AllocPolicy {
|
|||
*/
|
||||
void erase(T* aBegin, T* aEnd);
|
||||
|
||||
/**
|
||||
* Removes all elements that satisfy the predicate, shifting existing elements
|
||||
* lower to fill erased gaps.
|
||||
*/
|
||||
template <typename Pred>
|
||||
void eraseIf(Pred aPred);
|
||||
|
||||
/**
|
||||
* Removes all elements that compare equal to |aU|, shifting existing elements
|
||||
* lower to fill erased gaps.
|
||||
*/
|
||||
template <typename U>
|
||||
void eraseIfEqual(const U& aU);
|
||||
|
||||
/**
|
||||
* Measure the size of the vector's heap-allocated storage.
|
||||
*/
|
||||
|
@ -1285,6 +1299,26 @@ inline void Vector<T, N, AP>::erase(T* aBegin, T* aEnd) {
|
|||
shrinkBy(aEnd - aBegin);
|
||||
}
|
||||
|
||||
template <typename T, size_t N, class AP>
|
||||
template <typename Pred>
|
||||
void Vector<T, N, AP>::eraseIf(Pred aPred) {
|
||||
// remove_if finds the first element to be erased, and then efficiently move-
|
||||
// assigns elements to effectively overwrite elements that satisfy the
|
||||
// predicate. It returns the new end pointer, after which there are only
|
||||
// moved-from elements ready to be destroyed, so we just need to shrink the
|
||||
// vector accordingly.
|
||||
T* newEnd = std::remove_if(begin(), end(),
|
||||
[&aPred](const T& aT) { return aPred(aT); });
|
||||
MOZ_ASSERT(newEnd <= end());
|
||||
shrinkBy(end() - newEnd);
|
||||
}
|
||||
|
||||
template <typename T, size_t N, class AP>
|
||||
template <typename U>
|
||||
void Vector<T, N, AP>::eraseIfEqual(const U& aU) {
|
||||
return eraseIf([&aU](const T& aT) { return aT == aU; });
|
||||
}
|
||||
|
||||
template <typename T, size_t N, class AP>
|
||||
template <typename U>
|
||||
MOZ_ALWAYS_INLINE bool Vector<T, N, AP>::append(const U* aInsBegin,
|
||||
|
|
|
@ -22,6 +22,7 @@ struct mozilla::detail::VectorTesting {
|
|||
static void testExtractOrCopyRawBuffer();
|
||||
static void testReplaceRawBuffer();
|
||||
static void testInsert();
|
||||
static void testErase();
|
||||
static void testPodResizeToFit();
|
||||
};
|
||||
|
||||
|
@ -136,6 +137,8 @@ struct S {
|
|||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const S& rhs) const { return j == rhs.j && *k == *rhs.k; }
|
||||
|
||||
S(const S&) = delete;
|
||||
S& operator=(const S&) = delete;
|
||||
};
|
||||
|
@ -437,6 +440,97 @@ void mozilla::detail::VectorTesting::testInsert() {
|
|||
MOZ_RELEASE_ASSERT(S::destructCount == 1);
|
||||
}
|
||||
|
||||
void mozilla::detail::VectorTesting::testErase() {
|
||||
S::resetCounts();
|
||||
|
||||
Vector<S, 8> vec;
|
||||
MOZ_RELEASE_ASSERT(vec.reserve(8));
|
||||
for (size_t i = 0; i < 7; i++) {
|
||||
vec.infallibleEmplaceBack(i, i * i);
|
||||
}
|
||||
|
||||
// vec: [0, 1, 2, 3, 4, 5, 6]
|
||||
MOZ_RELEASE_ASSERT(vec.length() == 7);
|
||||
MOZ_ASSERT(vec.reserved() == 8);
|
||||
MOZ_RELEASE_ASSERT(S::constructCount == 7);
|
||||
MOZ_RELEASE_ASSERT(S::moveCount == 0);
|
||||
MOZ_RELEASE_ASSERT(S::destructCount == 0);
|
||||
S::resetCounts();
|
||||
|
||||
vec.erase(&vec[4]);
|
||||
// vec: [0, 1, 2, 3, 5, 6]
|
||||
MOZ_RELEASE_ASSERT(vec.length() == 6);
|
||||
MOZ_ASSERT(vec.reserved() == 8);
|
||||
MOZ_RELEASE_ASSERT(S::constructCount == 0);
|
||||
// 5 and 6 should have been moved into 4 and 5.
|
||||
MOZ_RELEASE_ASSERT(S::moveCount == 2);
|
||||
MOZ_RELEASE_ASSERT(S::destructCount == 1);
|
||||
MOZ_RELEASE_ASSERT(vec[4] == S(5, 5 * 5));
|
||||
MOZ_RELEASE_ASSERT(vec[5] == S(6, 6 * 6));
|
||||
S::resetCounts();
|
||||
|
||||
vec.erase(&vec[3], &vec[5]);
|
||||
// vec: [0, 1, 2, 6]
|
||||
MOZ_RELEASE_ASSERT(vec.length() == 4);
|
||||
MOZ_ASSERT(vec.reserved() == 8);
|
||||
MOZ_RELEASE_ASSERT(S::constructCount == 0);
|
||||
// 6 should have been moved into 3.
|
||||
MOZ_RELEASE_ASSERT(S::moveCount == 1);
|
||||
MOZ_RELEASE_ASSERT(S::destructCount == 2);
|
||||
MOZ_RELEASE_ASSERT(vec[3] == S(6, 6 * 6));
|
||||
|
||||
S s2(2, 2 * 2);
|
||||
S::resetCounts();
|
||||
|
||||
vec.eraseIfEqual(s2);
|
||||
// vec: [0, 1, 6]
|
||||
MOZ_RELEASE_ASSERT(vec.length() == 3);
|
||||
MOZ_ASSERT(vec.reserved() == 8);
|
||||
MOZ_RELEASE_ASSERT(S::constructCount == 0);
|
||||
// 6 should have been moved into 2.
|
||||
MOZ_RELEASE_ASSERT(S::moveCount == 1);
|
||||
MOZ_RELEASE_ASSERT(S::destructCount == 1);
|
||||
MOZ_RELEASE_ASSERT(vec[2] == S(6, 6 * 6));
|
||||
S::resetCounts();
|
||||
|
||||
// Predicate to find one element.
|
||||
vec.eraseIf([](const S& s) { return s.j == 1; });
|
||||
// vec: [0, 6]
|
||||
MOZ_RELEASE_ASSERT(vec.length() == 2);
|
||||
MOZ_ASSERT(vec.reserved() == 8);
|
||||
MOZ_RELEASE_ASSERT(S::constructCount == 0);
|
||||
// 6 should have been moved into 1.
|
||||
MOZ_RELEASE_ASSERT(S::moveCount == 1);
|
||||
MOZ_RELEASE_ASSERT(S::destructCount == 1);
|
||||
MOZ_RELEASE_ASSERT(vec[1] == S(6, 6 * 6));
|
||||
S::resetCounts();
|
||||
|
||||
// Generic predicate that flags everything.
|
||||
vec.eraseIf([](auto&&) { return true; });
|
||||
// vec: []
|
||||
MOZ_RELEASE_ASSERT(vec.length() == 0);
|
||||
MOZ_ASSERT(vec.reserved() == 8);
|
||||
MOZ_RELEASE_ASSERT(S::constructCount == 0);
|
||||
MOZ_RELEASE_ASSERT(S::moveCount == 0);
|
||||
MOZ_RELEASE_ASSERT(S::destructCount == 2);
|
||||
|
||||
for (size_t i = 0; i < 7; i++) {
|
||||
vec.infallibleEmplaceBack(i, i * i);
|
||||
}
|
||||
// vec: [0, 1, 2, 3, 4, 5, 6]
|
||||
MOZ_RELEASE_ASSERT(vec.length() == 7);
|
||||
S::resetCounts();
|
||||
|
||||
// Predicate that flags all even numbers.
|
||||
vec.eraseIf([](const S& s) { return s.j % 2 == 0; });
|
||||
// vec: [1 (was 0), 3 (was 1), 5 (was 2)]
|
||||
MOZ_RELEASE_ASSERT(vec.length() == 3);
|
||||
MOZ_ASSERT(vec.reserved() == 8);
|
||||
MOZ_RELEASE_ASSERT(S::constructCount == 0);
|
||||
MOZ_RELEASE_ASSERT(S::moveCount == 3);
|
||||
MOZ_RELEASE_ASSERT(S::destructCount == 4);
|
||||
}
|
||||
|
||||
void mozilla::detail::VectorTesting::testPodResizeToFit() {
|
||||
// Vectors not using inline storage realloc capacity to exact length.
|
||||
Vector<int, 0> v1;
|
||||
|
@ -576,6 +670,7 @@ int main() {
|
|||
VectorTesting::testExtractOrCopyRawBuffer();
|
||||
VectorTesting::testReplaceRawBuffer();
|
||||
VectorTesting::testInsert();
|
||||
VectorTesting::testErase();
|
||||
VectorTesting::testPodResizeToFit();
|
||||
TestVectorBeginNonNull();
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче