diff --git a/src/support/inplace_vector.h b/src/support/inplace_vector.h index 21826ea737d..09b8d3abf15 100644 --- a/src/support/inplace_vector.h +++ b/src/support/inplace_vector.h @@ -24,8 +24,11 @@ #ifndef wasm_support_inplace_vector_h #define wasm_support_inplace_vector_h +#include #include #include +#include +#include #include #include "support/parent_index_iterator.h" @@ -134,9 +137,9 @@ template class inplace_vector { Iterator(inplace_vector* parent, size_t index) : wasm::ParentIndexIterator*, Iterator>{parent, index} {} - Iterator(const Iterator& other) = default; T& operator*() { return (*this->parent)[this->index]; } + T* operator->() { return &(*this->parent)[this->index]; } }; struct ConstIterator @@ -151,6 +154,7 @@ template class inplace_vector { ConstIterator(const ConstIterator& other) = default; const T& operator*() const { return (*this->parent)[this->index]; } + const T* operator->() const { return &(*this->parent)[this->index]; } }; Iterator begin() { return Iterator(this, 0); } @@ -158,13 +162,62 @@ template class inplace_vector { ConstIterator begin() const { return ConstIterator(this, 0); } ConstIterator end() const { return ConstIterator(this, size()); } - void erase(Iterator a, Iterator b) { - // Atm we only support erasing at the end, which is very efficient. - assert(b == end()); - resize(a.index); + Iterator erase(ConstIterator first, ConstIterator last) { + assert(first.index <= last.index); + assert(last.index <= usedFixed); + size_t numToErase = last.index - first.index; + if (numToErase > 0) { + std::move(fixed.begin() + last.index, + fixed.begin() + usedFixed, + fixed.begin() + first.index); + usedFixed -= numToErase; + } + return Iterator(this, first.index); + } + + Iterator erase(Iterator first, Iterator last) { + return erase(ConstIterator(this, first.index), + ConstIterator(this, last.index)); } + + Iterator erase(ConstIterator pos) { return erase(pos, pos + 1); } + + Iterator erase(Iterator pos) { return erase(pos, pos + 1); } }; +namespace detail { + +template struct is_inplace_vector_or_derived { +private: + template + static std::true_type test(const inplace_vector*); + static std::false_type test(...); + +public: + static constexpr bool value = decltype(test(std::declval()))::value; +}; + +} // namespace detail + +template + requires detail::is_inplace_vector_or_derived::value +size_t erase_if(Vector& c, Pred pred) { + auto it = std::remove_if(c.begin(), c.end(), pred); + auto r = std::distance(it, c.end()); + c.erase(it, c.end()); + return r; +} + } // namespace wasm +namespace std { + +template + requires wasm::detail::is_inplace_vector_or_derived::value +size_t erase_if(Vector& c, Pred pred) { + return wasm::erase_if(c, pred); +} + +} // namespace std + #endif // wasm_support_inplace_vector_h diff --git a/test/gtest/inplace_vector.cpp b/test/gtest/inplace_vector.cpp index 34c1a3d3e1b..0480bc9f79f 100644 --- a/test/gtest/inplace_vector.cpp +++ b/test/gtest/inplace_vector.cpp @@ -42,3 +42,45 @@ TEST_F(InplaceVectorTest, I) { EXPECT_EQ(normal, std::vector({10, 20, 30})); } + +TEST_F(InplaceVectorTest, Erase) { + inplace_vector vec{10, 20, 30, 40, 50}; + + // Erase single element in the middle (30 at index 2) + auto it = vec.erase(vec.begin() + 2); + EXPECT_EQ(*it, 40); + EXPECT_EQ(vec.size(), 4u); + EXPECT_EQ(vec[0], 10); + EXPECT_EQ(vec[1], 20); + EXPECT_EQ(vec[2], 40); + EXPECT_EQ(vec[3], 50); + + // Erase range at beginning [10, 20] + it = vec.erase(vec.begin(), vec.begin() + 2); + EXPECT_EQ(*it, 40); + EXPECT_EQ(vec.size(), 2u); + EXPECT_EQ(vec[0], 40); + EXPECT_EQ(vec[1], 50); + + // Erase at end + it = vec.erase(vec.begin() + 1, vec.end()); + EXPECT_EQ(it, vec.end()); + EXPECT_EQ(vec.size(), 1u); + EXPECT_EQ(vec[0], 40); +} + +TEST_F(InplaceVectorTest, EraseIf) { + // Test std::erase_if on inplace_vector + inplace_vector vec{1, 2, 3, 4, 5}; + size_t erased = std::erase_if(vec, [](int x) { return x % 2 == 0; }); + EXPECT_EQ(erased, 2u); + EXPECT_EQ(vec.size(), 3u); + EXPECT_EQ(vec[0], 1); + EXPECT_EQ(vec[1], 3); + EXPECT_EQ(vec[2], 5); + + // Erase remaining elements + erased = std::erase_if(vec, [](int x) { return x > 0; }); + EXPECT_EQ(erased, 3u); + EXPECT_TRUE(vec.empty()); +}