grae22
grae22

Reputation: 104

memcpy equivalent for skipping x bytes while copying (not just initial x bytes)?

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

Answers (3)

xzaton jw
xzaton jw

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

grae22
grae22

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

krzaq
krzaq

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));

live example;

Upvotes: 2

Related Questions