Reputation: 104
I'm looking for an existing function similar to memcpy that can be told to copy x bytes and then skip y bytes, repeating until a specified amount has been copied.
Imagine a buffer with data: AABAAB
(I've used characters, but the data I'm manipulating is not string data).
When applied to this buffer and told to copy 2 bytes and skip 1 byte, the destination buffer would contain: AAAA
.
I haven't found anything looking through STL and Boost, but am hoping there's something in either that I've missed.
Or perhaps there's a clever (and not nasty) way of using more common functions to achieve the same thing.
Upvotes: 0
Views: 1619
Reputation: 71
Using chunk
, transform
, and take
, this is possible:
data | std::views::chunk(N) | std::views::transform(std::views::take(M));
data | std::views::chunk(N)
: create a range of ranges, of which each range is N elements long
data | std::views::chunk(N) | std::views::transform(...);
: apply ...
to each range within the range of ranges
data | std::views::chunk(N) | std::views::transform(std::views::take(M));
: take the first M elements of each chunk as a range.
e.g.
#include <fmt/ranges.h>
#include <array>
#include <ranges>
int main()
{
std::array data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
auto data_view = data | std::views::chunk(4) | std::views::transform(std::views::take(3));
fmt::println("{}\n", data_view);
}
// [[1, 2, 3], [5, 6, 7], [9, 0]]
Upvotes: 0
Reputation: 104
There doesn't appear to be a direct equivalent of memcpy for doing what I wanted. Boost does seem to often some useful helper functions, but I ended up implementing a simple looping function to do the job as it seemed the most simple & appropriate solution.
Upvotes: 0
Reputation: 16421
You might want to look into boost::adaptors::strided
.
You'd probably write something like this:
boost::copy(boost::make_iterator_range(in, in+size) | boost::adaptors::strided(2), out);
While this produces lots of assembly, it seems to also be perfectly inlineable by the compiler: compiler explorer example.
To remove every nth element you could also resort to boost::adaptors::filtered
with a predicate that disallows every nth element (strided
does the opposite and keeps every nth one):
char const* input = "AABAAB";
unsigned counter{};
auto pred = [&counter](auto const&){ return ++counter % 3; };
boost::copy(boost::make_iterator_range(input, input+strlen(input)) | boost::adaptors::filtered(pred),
std::ostream_iterator<char>(cout));
Upvotes: 2