Algorithms

This page describes the algorithms provided for working with buffer sequences. After reading, you will know how to measure, copy, slice, and iterate buffer sequences efficiently.

Code snippets on this page assume the following declarations are in effect:
#include <boost/buffers.hpp>
using namespace boost::buffers;

Measuring Size

The function size returns the total number of bytes across all buffers in a sequence. This differs from the number of buffers, which length returns.

std::array<const_buffer, 3> buffers = {
    const_buffer("Hello", 5),
    const_buffer(", ", 2),
    const_buffer("World!", 6)
};

std::size_t total_bytes = size(buffers);   // 13
std::size_t num_buffers = length(buffers); // 3

For custom buffer sequence types, the size calculation can be optimized through the size_tag customization point. See Customization.

Copying Data

The function copy transfers bytes from a source buffer sequence to a destination buffer sequence:

template<class MutableBufferSequence, class ConstBufferSequence>
std::size_t
copy(
    MutableBufferSequence const& dest,
    ConstBufferSequence const& src,
    std::size_t at_most = std::size_t(-1));

The function copies up to at_most bytes, limited by the sizes of both sequences. It returns the actual number of bytes copied.

Basic Usage

char source[] = "Hello, Buffers!";
char dest[32];

const_buffer src(source, 15);
mutable_buffer dst(dest, sizeof(dest));

std::size_t n = copy(dst, src);
// n == 15
// dest contains "Hello, Buffers!"

Copying Between Sequences

The function handles scatter/gather copying transparently:

// Source: two separate regions
std::array<const_buffer, 2> src = {
    const_buffer("Hello, ", 7),
    const_buffer("World!", 6)
};

// Destination: one contiguous region
char storage[32];
mutable_buffer dst(storage, sizeof(storage));

std::size_t n = copy(dst, src);
// n == 13
// storage contains "Hello, World!"

Partial Copies

The at_most parameter limits the number of bytes copied:

char source[] = "Hello, Buffers!";
char dest[5];

const_buffer src(source, 15);
mutable_buffer dst(dest, sizeof(dest));

std::size_t n = copy(dst, src);
// n == 5 (limited by destination size)
// dest contains "Hello"

n = copy(dst, src, 3);
// n == 3 (limited by at_most)
// dest contains "Hel"

Getting the First Buffer

The function front returns the first buffer in a sequence. If the sequence is empty, it returns an empty buffer:

std::array<const_buffer, 2> buffers = {
    const_buffer("First", 5),
    const_buffer("Second", 6)
};

const_buffer first = front(buffers);
// first.data() points to "First"
// first.size() == 5

This is useful when you need to examine or process the beginning of a buffer sequence without iterating:

template<class ConstBufferSequence>
bool starts_with_http(ConstBufferSequence const& bs)
{
    const_buffer b = front(bs);
    if(b.size() < 4)
        return false;
    return std::memcmp(b.data(), "HTTP", 4) == 0;
}

Slicing Buffer Sequences

Slicing creates a view of a subset of bytes from a buffer sequence. The library provides two families of functions:

  • Copy functions return a new sequence representing the slice

  • In-place functions modify the sequence object directly

Copy Slicing Functions

These functions return a new buffer sequence without modifying the original:

Function Description

prefix(bs

Return the first n bytes

suffix(bs

Return the last n bytes

sans_prefix(bs

Return all bytes except the first n

sans_suffix(bs

Return all bytes except the last n

char data[] = "Hello, World!";
const_buffer original(data, 13);

auto first_five = prefix(original, 5);
// size(first_five) == 5, represents "Hello"

auto last_six = suffix(original, 6);
// size(last_six) == 6, represents "World!"

auto without_hello = sans_prefix(original, 7);
// size(without_hello) == 6, represents "World!"

auto without_world = sans_suffix(original, 7);
// size(without_world) == 6, represents "Hello,"

In-Place Slicing Functions

These functions modify the buffer sequence object directly. They require the sequence type to support the slice customization point (built-in types like const_buffer and mutable_buffer support this):

Function Description

keep_prefix(bs

Remove all but the first n bytes

keep_suffix(bs

Remove all but the last n bytes

remove_prefix(bs

Remove the first n bytes

remove_suffix(bs

Remove the last n bytes

char data[] = "Hello, World!";
const_buffer buf(data, 13);

remove_prefix(buf, 7);
// buf now represents "World!" (6 bytes)

keep_prefix(buf, 5);
// buf now represents "World" (5 bytes)

The slice_of Wrapper

For buffer sequence types that do not natively support slicing, the library provides slice_of, a wrapper that tracks prefix and suffix offsets:

std::vector<const_buffer> buffers = /* ... */;

// slice_of wraps the sequence and enables slicing
slice_of<std::vector<const_buffer>> sliced(buffers);

remove_prefix(sliced, 100);
// sliced now represents buffers with 100 bytes removed from the front

The type alias slice_type selects the appropriate type: the original type if it supports slicing natively, or slice_of<T> otherwise.

Iterating Buffer Sequences

Use begin and end from this library to iterate any buffer sequence, including single-buffer types:

template<class ConstBufferSequence>
void process(ConstBufferSequence const& bs)
{
    for(auto it = buffers::begin(bs); it != buffers::end(bs); ++it)
    {
        const_buffer b(*it);
        // Process b.data() and b.size()
    }
}

These functions handle both range types and single-buffer types uniformly. Using std::begin and std::end would fail for single-buffer types.

Complete Iteration Example

#include <boost/buffers.hpp>
#include <iostream>
#include <iomanip>

using namespace boost::buffers;

template<class ConstBufferSequence>
void hex_dump(ConstBufferSequence const& bs)
{
    std::size_t offset = 0;
    for(auto it = buffers::begin(bs); it != buffers::end(bs); ++it)
    {
        const_buffer b(*it);
        auto const* p = static_cast<unsigned char const*>(b.data());
        for(std::size_t i = 0; i < b.size(); ++i, ++offset)
        {
            if(offset % 16 == 0)
                std::cout << std::hex << std::setw(8)
                          << std::setfill('0') << offset << ": ";

            std::cout << std::hex << std::setw(2)
                      << std::setfill('0') << static_cast<int>(p[i]) << ' ';

            if(offset % 16 == 15)
                std::cout << '\n';
        }
    }
    if(offset % 16 != 0)
        std::cout << '\n';
}

Algorithm Summary

Algorithm Purpose Header

size

Return total bytes in sequence

<boost/buffers/buffer.hpp>

length

Return number of buffers in sequence

<boost/buffers/buffer.hpp>

copy

Copy bytes between sequences

<boost/buffers/copy.hpp>

front

Return first buffer in sequence

<boost/buffers/front.hpp>

prefix

Return first n bytes as new sequence

<boost/buffers/slice.hpp>

suffix

Return last n bytes as new sequence

<boost/buffers/slice.hpp>

sans_prefix

Return sequence without first n bytes

<boost/buffers/slice.hpp>

sans_suffix

Return sequence without last n bytes

<boost/buffers/slice.hpp>

remove_prefix

Remove first n bytes in place

<boost/buffers/slice.hpp>

remove_suffix

Remove last n bytes in place

<boost/buffers/slice.hpp>

keep_prefix

Keep only first n bytes in place

<boost/buffers/slice.hpp>

keep_suffix

Keep only last n bytes in place

<boost/buffers/slice.hpp>

begin

Return iterator to first buffer

<boost/buffers/buffer.hpp>

end

Return iterator past last buffer

<boost/buffers/buffer.hpp>