From 3763c80ec6883df23ea9d69a9a65302b27ebe6a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Wed, 29 Oct 2025 00:12:43 +0100 Subject: [PATCH] Added C++20 remove and remove_if overloads to vector-like containers --- include/boost/container/deque.hpp | 22 +++++++++++++ include/boost/container/detail/algorithm.hpp | 34 ++++++++++++++++++++ include/boost/container/devector.hpp | 22 +++++++++++++ include/boost/container/small_vector.hpp | 22 +++++++++++++ include/boost/container/stable_vector.hpp | 22 +++++++++++++ include/boost/container/static_vector.hpp | 22 +++++++++++++ include/boost/container/string.hpp | 22 +++++++++++++ include/boost/container/vector.hpp | 21 ++++++++++++ test/vector_test.hpp | 26 +++++++++++++++ 9 files changed, 213 insertions(+) diff --git a/include/boost/container/deque.hpp b/include/boost/container/deque.hpp index 3c6a3c1..7acd2ba 100644 --- a/include/boost/container/deque.hpp +++ b/include/boost/container/deque.hpp @@ -3065,6 +3065,28 @@ template deque(InputIterator, InputIterator, Allocator const&) -> deque::value_type, Allocator>; #endif +//! Effects: Erases all elements that compare equal to v from the container c. +//! +//! Complexity: Linear. +template +inline typename deque::size_type erase(deque& c, const U& v) +{ + typename deque::size_type old_size = c.size(); + c.erase(boost::container::remove(c.begin(), c.end(), v), c.end()); + return old_size - c.size(); +} + +//! Effects: Erases all elements that satisfy the predicate pred from the container c. +//! +//! Complexity: Linear. +template +inline typename deque::size_type erase_if(deque& c, Pred pred) +{ + typename deque::size_type old_size = c.size(); + c.erase(boost::container::remove_if(c.begin(), c.end(), pred), c.end()); + return old_size - c.size(); +} + } //namespace container } //namespace boost diff --git a/include/boost/container/detail/algorithm.hpp b/include/boost/container/detail/algorithm.hpp index ce5582b..38399d8 100644 --- a/include/boost/container/detail/algorithm.hpp +++ b/include/boost/container/detail/algorithm.hpp @@ -22,6 +22,7 @@ #endif #include +#include namespace boost { namespace container { @@ -179,6 +180,39 @@ ForwardIt1 search(ForwardIt1 first1, ForwardIt1 last1, } } +template +InpIt find(InpIt first, InpIt last, const U& value) +{ + for (; first != last; ++first) + if (*first == value) + return first; + + return last; +} + + +template +FwdIt remove(FwdIt first, FwdIt last, const U& value) +{ + first = find(first, last, value); + if (first != last) + for (FwdIt i = first; ++i != last;) + if (!(*i == value)) + *first++ = boost::move(*i); + return first; +} + +template +FwdIt remove_if(FwdIt first, FwdIt last, Pred p) +{ + first = find_if(first, last, p); + if (first != last) + for (FwdIt i = first; ++i != last;) + if (!p(*i)) + *first++ = boost::move(*i); + return first; +} + } //namespace container { } //namespace boost { diff --git a/include/boost/container/devector.hpp b/include/boost/container/devector.hpp index 7a8245c..66e7c0c 100644 --- a/include/boost/container/devector.hpp +++ b/include/boost/container/devector.hpp @@ -3040,6 +3040,28 @@ class devector #endif // ifndef BOOST_CONTAINER_DOXYGEN_INVOKED }; +//! Effects: Erases all elements that compare equal to v from the container c. +//! +//! Complexity: Linear. +template +inline typename devector::size_type erase(devector& c, const U& v) +{ + typename devector::size_type old_size = c.size(); + c.erase(boost::container::remove(c.begin(), c.end(), v), c.end()); + return old_size - c.size(); +} + +//! Effects: Erases all elements that satisfy the predicate pred from the container c. +//! +//! Complexity: Linear. +template +inline typename devector::size_type erase_if(devector& c, Pred pred) +{ + typename devector::size_type old_size = c.size(); + c.erase(boost::container::remove_if(c.begin(), c.end(), pred), c.end()); + return old_size - c.size(); +} + }} // namespace boost::container #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED diff --git a/include/boost/container/small_vector.hpp b/include/boost/container/small_vector.hpp index c01718a..72c25b3 100644 --- a/include/boost/container/small_vector.hpp +++ b/include/boost/container/small_vector.hpp @@ -675,6 +675,28 @@ class small_vector { this->base_type::prot_shrink_to_fit_small(this->internal_capacity()); } }; +//! Effects: Erases all elements that compare equal to v from the container c. +//! +//! Complexity: Linear. +template +inline typename small_vector::size_type erase(small_vector& c, const U& v) +{ + typename small_vector::size_type old_size = c.size(); + c.erase(boost::container::remove(c.begin(), c.end(), v), c.end()); + return old_size - c.size(); +} + +//! Effects: Erases all elements that satisfy the predicate pred from the container c. +//! +//! Complexity: Linear. +template +inline typename small_vector::size_type erase_if(small_vector& c, Pred pred) +{ + typename small_vector::size_type old_size = c.size(); + c.erase(boost::container::remove_if(c.begin(), c.end(), pred), c.end()); + return old_size - c.size(); +} + }} #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED diff --git a/include/boost/container/stable_vector.hpp b/include/boost/container/stable_vector.hpp index f8952c8..09f61da 100644 --- a/include/boost/container/stable_vector.hpp +++ b/include/boost/container/stable_vector.hpp @@ -2251,6 +2251,28 @@ stable_vector(InputIterator, InputIterator, Allocator const&) -> #undef BOOST_CONTAINER_STABLE_VECTOR_CHECK_INVARIANT +//! Effects: Erases all elements that compare equal to v from the container c. +//! +//! Complexity: Linear. +template +inline typename stable_vector::size_type erase(stable_vector& c, const U& v) +{ + typename stable_vector::size_type old_size = c.size(); + c.erase(boost::container::remove(c.begin(), c.end(), v), c.end()); + return old_size - c.size(); +} + +//! Effects: Erases all elements that satisfy the predicate pred from the container c. +//! +//! Complexity: Linear. +template +inline typename stable_vector::size_type erase_if(stable_vector& c, Pred pred) +{ + typename stable_vector::size_type old_size = c.size(); + c.erase(boost::container::remove_if(c.begin(), c.end(), pred), c.end()); + return old_size - c.size(); +} + } //namespace container { //!has_trivial_destructor_after_move<> == true_type diff --git a/include/boost/container/static_vector.hpp b/include/boost/container/static_vector.hpp index 6481760..707c799 100644 --- a/include/boost/container/static_vector.hpp +++ b/include/boost/container/static_vector.hpp @@ -1333,6 +1333,28 @@ inline void swap(static_vector & x, static_vector & y #endif // BOOST_CONTAINER_DOXYGEN_INVOKED +//! Effects: Erases all elements that compare equal to v from the container c. +//! +//! Complexity: Linear. +template +inline typename static_vector::size_type erase(static_vector& c, const U& v) +{ + typename static_vector::size_type old_size = c.size(); + c.erase(boost::container::remove(c.begin(), c.end(), v), c.end()); + return old_size - c.size(); +} + +//! Effects: Erases all elements that satisfy the predicate pred from the container c. +//! +//! Complexity: Linear. +template +inline typename static_vector::size_type erase_if(static_vector& c, Pred pred) +{ + typename static_vector::size_type old_size = c.size(); + c.erase(boost::container::remove_if(c.begin(), c.end(), pred), c.end()); + return old_size - c.size(); +} + }} // namespace boost::container #include diff --git a/include/boost/container/string.hpp b/include/boost/container/string.hpp index 4a69e19..4f55fd1 100644 --- a/include/boost/container/string.hpp +++ b/include/boost/container/string.hpp @@ -3550,6 +3550,28 @@ getline(std::basic_istream& is, basic_stringEffects: Erases all elements that compare equal to v from the container c. +//! +//! Complexity: Linear. +template +inline typename basic_string::size_type erase(basic_string& c, const U& v) +{ + typename basic_string::size_type old_size = c.size(); + c.erase(boost::container::remove(c.begin(), c.end(), v), c.end()); + return old_size - c.size(); +} + +//! Effects: Erases all elements that satisfy the predicate pred from the container c. +//! +//! Complexity: Linear. +template +inline typename basic_string::size_type erase_if(basic_string& c, Pred pred) +{ + typename basic_string::size_type old_size = c.size(); + c.erase(boost::container::remove_if(c.begin(), c.end(), pred), c.end()); + return old_size - c.size(); +} + }} //GCC 12 has a regression for array-bounds warnings diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index 24e7a1e..8937515 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -3351,6 +3351,27 @@ vector(InputIterator, InputIterator, Allocator const&) -> #endif +//! Effects: Erases all elements that compare equal to v from the container c. +//! +//! Complexity: Linear. +template +inline typename vector::size_type erase(vector& c, const U& v) +{ + typename vector::size_type old_size = c.size(); + c.erase(boost::container::remove(c.begin(), c.end(), v), c.end()); + return old_size - c.size(); +} + +//! Effects: Erases all elements that satisfy the predicate pred from the container c. +//! +//! Complexity: Linear. +template +inline typename vector::size_type erase_if(vector& c, Pred pred) +{ + typename vector::size_type old_size = c.size(); + c.erase(boost::container::remove_if(c.begin(), c.end(), pred), c.end()); + return old_size - c.size(); +} }} //namespace boost::container diff --git a/test/vector_test.hpp b/test/vector_test.hpp index fb2550f..4c86aae 100644 --- a/test/vector_test.hpp +++ b/test/vector_test.hpp @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -558,6 +559,31 @@ int vector_move_assignable_only(boost::container::dtl::true_type) boostvector.resize(100u); if(!test_nth_index_of(boostvector)) return 1; + + //test erase/erase_if + IntType aux_vect[50]; + for(int i = 0; i < 50; ++i){ + aux_vect[i] = i; + } + int aux_vect2[50]; + for(int i = 0; i < 50; ++i){ + aux_vect2[i] = i; + } + + boostvector.clear(); + stdvector.clear(); + boostvector.insert(boostvector.end() + ,boost::make_move_iterator(&aux_vect[0]) + ,boost::make_move_iterator(aux_vect + 50)); + stdvector.insert(stdvector.end(), aux_vect2, aux_vect2 + 50); + + if (1 != erase(boostvector, 25)) + return 1; + stdvector.erase(boost::container::find(stdvector.begin(), stdvector.end(), 25)); + if(!test::CheckEqualContainers(boostvector, stdvector)) return false; + + if (0 != erase(boostvector, 25)) + return 1; } return 0; }