I very often find myself wanting to filter a vector based on its index rather than its values.
auto some_values = std::vector{1, 0, 4, 6, 2};
// Somewhere I figure out which items to remove.
// This may be from user interaction or something
// nothing to do with the original values:
const auto removing = std::vector<bool>{0, 0, 1, 0, 1};
So, I'm tempted to use erase_if
like so:
std::erase_if(some_values, [it = removing.begin()](auto) mutable {return *it++;});
It seems to works for gcc and clang. However, there doesn't seem to be anything on the std::erase cppref page about the order in which the predicate is called, so I assume this is undefined behaviour?
Same issue with std::remove_if
. Note that zipping the ranges won't work for most zipping options as usually the resultant range can't resize the underlying data.
Using a for loop and creating a copy of the array isn't too much boilerplate, but I'm currently applying filters to some low-ish level code where I can't just copy all the data. Some of the data will be huge and needs to be responsive during these filter operations.
Worst-case scenario I can add functions like this to solve the problem:
template <class T, auto N, class Pred>
size_t RemoveIfIndex(std::span<T, N> span, Pred&& pred)
{
size_t write = 0; // Also behaves as a counter
// Initialise to the first deleted index:
for (; (write < span.size()) && !pred(write); ++write);
// Shuffle the elements:
for (size_t read = write + 1; read < span.size(); ++read)
{
if (!pred(read))
{
span[write] = span[read];
++write;
}
}
return write;
}
template <class T, class Alloc, class Pred>
size_t EraseIfIndex(std::vector<T, Alloc>& vec, Pred&& pred)
{
const size_t new_size = RemoveIfIndex(std::span{vec.begin(), vec.end()}, pred);
vec.resize(new_size);
return new_size;
}
But I'm hesitant to add more code to our low-level library when there's similar categories of functions I'll need to add (that need index info), and I suspect there's some insight into ranges/adaptors/filters that I'm missing that'd make these functions unnecessary.