---
title: llarp/util/buffer.hpp

---

# llarp/util/buffer.hpp



## Namespaces

| Name           |
| -------------- |
| **[llarp](Namespaces/namespacellarp.md)** <br>[crypto.hpp] |

## Classes

|                | Name           |
| -------------- | -------------- |
| struct | **[llarp_buffer_t](Classes/structllarp__buffer__t.md)** <br>TODO: replace usage of these with std::span (via a backport until we move to C++20).  |
| struct | **[ManagedBuffer](Classes/structManagedBuffer.md)** <br>Provide a copyable/moveable wrapper around `[llarp_buffer_t]()`.  |
| struct | **[llarp::OwnedBuffer](Classes/structllarp_1_1OwnedBuffer.md)**  |




## Source code

```cpp
#pragma once

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

#ifndef _WIN32
  bool writef(const char* fmt, ...) __attribute__((format(printf, 2, 3)));

#elif defined(__MINGW64__) || defined(__MINGW32__)
  bool writef(const char* fmt, ...) __attribute__((__format__(__MINGW_PRINTF_FORMAT, 2, 3)));
#else
  bool writef(const char* fmt, ...);
#endif

  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
  {
    std::unique_ptr<byte_t[]> buf;
    size_t sz;

    template <typename T, typename = std::enable_if_t<sizeof(T) == 1>>
    OwnedBuffer(std::unique_ptr<T[]> buf, size_t sz)
        : buf{reinterpret_cast<byte_t*>(buf.release())}, sz{sz}
    {}

    // Create a new, uninitialized owned buffer of the given size.
    explicit OwnedBuffer(size_t sz) : OwnedBuffer{std::make_unique<byte_t[]>(sz), sz}
    {}

    // copy content from existing memory
    explicit OwnedBuffer(const byte_t* ptr, size_t sz) : OwnedBuffer{sz}
    {
      std::copy_n(ptr, sz, buf.get());
    }

    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 2023-01-06 at 19:35:06 +0000
