llarp/util/buffer.hpp
Namespaces
| Name |
|---|
| llarp [crypto.hpp] |
Classes
| Name | |
|---|---|
| struct | llarp_buffer_t TODO: replace usage of these with std::span (via a backport until we move to C++20). |
| struct | ManagedBuffer Provide a copyable/moveable wrapper around [llarp_buffer_t](). |
| struct | llarp::OwnedBuffer |
| struct | llarp::OwnedBuffer::destroyer |
Source code
#pragma once
#ifndef ANDROID
#include <memory_resource>
#endif
#include <type_traits>
#include "common.hpp"
#include "mem.h"
#include "types.hpp"
#include <cassert>
#include <iterator>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <utility>
#include <algorithm>
#include <memory>
#include <vector>
#include <string_view>
namespace llarp
{
using byte_view_t = std::basic_string_view<byte_t>;
}
struct ManagedBuffer;
struct [[deprecated("this type is stupid, use something else")]] llarp_buffer_t
{
byte_t* base{nullptr};
byte_t* cur{nullptr};
size_t sz{0};
byte_t
operator[](size_t x)
{
return *(this->base + x);
}
llarp_buffer_t() = default;
llarp_buffer_t(byte_t* b, byte_t* c, size_t s) : base(b), cur(c), sz(s)
{}
llarp_buffer_t(const ManagedBuffer&) = delete;
llarp_buffer_t(ManagedBuffer&&) = delete;
template <typename Byte>
static constexpr bool is_basic_byte = sizeof(Byte) == 1 and std::is_trivially_copyable_v<Byte>;
template <
typename Byte,
typename = std::enable_if_t<not std::is_const_v<Byte> && is_basic_byte<Byte>>>
llarp_buffer_t(Byte* buf, size_t sz) : base{reinterpret_cast<byte_t*>(buf)}, cur{base}, sz{sz}
{}
template <
typename Byte,
typename = std::enable_if_t<not std::is_const_v<Byte> && is_basic_byte<Byte>>>
llarp_buffer_t(std::vector<Byte>& b) : llarp_buffer_t{b.data(), b.size()}
{}
template <
typename Byte,
size_t N,
typename = std::enable_if_t<not std::is_const_v<Byte> && is_basic_byte<Byte>>>
llarp_buffer_t(std::array<Byte, N>& b) : llarp_buffer_t{b.data(), b.size()}
{}
// These overloads, const_casting away the const, are not just gross but downright dangerous:
template <typename Byte, typename = std::enable_if_t<is_basic_byte<Byte>>>
[[deprecated("dangerous constructor that casts away constness, be very careful")]] llarp_buffer_t(
const Byte* buf, size_t sz)
: llarp_buffer_t{const_cast<Byte*>(buf), sz}
{}
template <typename Byte, typename = std::enable_if_t<is_basic_byte<Byte>>>
[[deprecated("dangerous constructor that casts away constness, be very careful")]] llarp_buffer_t(
const std::vector<Byte>& b)
: llarp_buffer_t{const_cast<Byte*>(b.data()), b.size()}
{}
template <typename Byte, size_t N, typename = std::enable_if_t<is_basic_byte<Byte>>>
[[deprecated("dangerous constructor that casts away constness, be very careful")]] llarp_buffer_t(
const std::array<Byte, N>& b)
: llarp_buffer_t{const_cast<Byte*>(b.data()), b.size()}
{}
template <
typename T,
typename = std::void_t<decltype(std::declval<T>().data() + std::declval<T>().size())>>
explicit llarp_buffer_t(T&& t) : llarp_buffer_t{t.data(), t.size()}
{}
byte_t*
begin()
{
return base;
}
const byte_t*
begin() const
{
return base;
}
byte_t*
end()
{
return base + sz;
}
const byte_t*
end() const
{
return base + sz;
}
size_t
size_left() const
{
size_t diff = cur - base;
assert(diff <= sz);
if (diff > sz)
return 0;
return sz - diff;
}
template <typename OutputIt>
bool
read_into(OutputIt begin, OutputIt end);
template <typename InputIt>
bool
write(InputIt begin, InputIt end);
bool
writef(const char* fmt, ...) __attribute__((format(printf, 2, 3)));
bool
put_uint16(uint16_t i);
bool
put_uint32(uint32_t i);
bool
put_uint64(uint64_t i);
bool
read_uint16(uint16_t& i);
bool
read_uint32(uint32_t& i);
bool
read_uint64(uint64_t& i);
size_t
read_until(char delim, byte_t* result, size_t resultlen);
std::vector<byte_t>
copy() const;
llarp::byte_view_t
view_all() const
{
return {base, sz};
}
llarp::byte_view_t
view_remaining() const
{
return {cur, size_left()};
}
bool
startswith(std::string_view prefix_str) const
{
llarp::byte_view_t prefix{
reinterpret_cast<const byte_t*>(prefix_str.data()), prefix_str.size()};
return view_remaining().substr(0, prefix.size()) == prefix;
}
private:
friend struct ManagedBuffer;
llarp_buffer_t(const llarp_buffer_t&) = default;
llarp_buffer_t(llarp_buffer_t&&) = default;
};
template <typename OutputIt>
bool
llarp_buffer_t::read_into(OutputIt begin, OutputIt end)
{
auto dist = std::distance(begin, end);
if (static_cast<decltype(dist)>(size_left()) >= dist)
{
std::copy_n(cur, dist, begin);
cur += dist;
return true;
}
return false;
}
template <typename InputIt>
bool
llarp_buffer_t::write(InputIt begin, InputIt end)
{
auto dist = std::distance(begin, end);
if (static_cast<decltype(dist)>(size_left()) >= dist)
{
cur = std::copy(begin, end, cur);
return true;
}
return false;
}
struct [[deprecated("deprecated along with llarp_buffer_t")]] ManagedBuffer
{
llarp_buffer_t underlying;
ManagedBuffer() = delete;
explicit ManagedBuffer(const llarp_buffer_t& b) : underlying(b)
{}
ManagedBuffer(ManagedBuffer&&) = default;
ManagedBuffer(const ManagedBuffer&) = default;
operator const llarp_buffer_t&() const
{
return underlying;
}
};
namespace llarp
{
using byte_view_t = std::basic_string_view<byte_t>;
// Wrapper around a std::unique_ptr<byte_t[]> that owns its own memory and is also implicitly
// convertible to a llarp_buffer_t.
struct OwnedBuffer
{
#if defined(__APPLE__) || defined(ANDROID)
// apple does not implement std::pmr even though they have it in the headers because of course
// they don't, why would they?
using alloc_t = std::allocator<byte_t>;
#else
using alloc_t = std::pmr::polymorphic_allocator<byte_t>;
#endif
struct destroyer
{
alloc_t& alloc;
size_t sz;
void
operator()(byte_t* ptr)
{
alloc.deallocate(ptr, sz);
}
};
using bufptr_t = std::unique_ptr<byte_t[], destroyer>;
alloc_t _alloc;
bufptr_t buf;
size_t sz;
#if defined(__APPLE__) || defined(ANDROID)
// Create a new, uninitialized owned buffer of the given size.
explicit OwnedBuffer(size_t sz)
: _alloc{}, buf{bufptr_t{_alloc.allocate(sz), destroyer{_alloc, sz}}}, sz{sz}
{}
#else
// Create a new, uninitialized owned buffer of the given size.
explicit OwnedBuffer(std::pmr::memory_resource* res, size_t sz)
: _alloc{res}, buf{bufptr_t{_alloc.allocate(sz), destroyer{_alloc, sz}}}, sz{sz}
{}
#endif
#if defined(__APPLE__) || defined(ANDROID)
// copy content from existing memory
explicit OwnedBuffer(const byte_t* ptr, size_t sz) : OwnedBuffer{sz}
{
std::copy_n(ptr, sz, buf.get());
}
#else
// copy content from existing memory
explicit OwnedBuffer(
const byte_t* ptr,
size_t sz,
std::pmr::memory_resource* res = std::pmr::get_default_resource())
: OwnedBuffer{res, sz}
{
std::copy_n(ptr, sz, buf.get());
}
#endif
OwnedBuffer(const OwnedBuffer&) = delete;
OwnedBuffer&
operator=(const OwnedBuffer&) = delete;
OwnedBuffer(OwnedBuffer&&) = default;
OwnedBuffer&
operator=(OwnedBuffer&&) = delete;
// Implicit conversion so that this OwnedBuffer can be passed to anything taking a
// llarp_buffer_t
operator llarp_buffer_t()
{
return {buf.get(), sz};
}
// Creates an owned buffer by copying from a llarp_buffer_t. (Can also be used to copy from
// another OwnedBuffer via the implicit conversion operator above).
static OwnedBuffer
copy_from(const llarp_buffer_t& b);
// Creates an owned buffer by copying the used portion of a llarp_buffer_t (i.e. from base to
// cur), for when a llarp_buffer_t is used in write mode.
static OwnedBuffer
copy_used(const llarp_buffer_t& b);
std::vector<byte_t>
copy() const;
};
} // namespace llarp
Updated on 2026-01-10 at 22:49:45 +0000