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