44 requires std::is_integral_v<T> && std::is_unsigned_v<T>
47 for (std::size_t i =
sizeof(T); i > 0U; --i)
49 out.push_back(
static_cast<std::uint8_t
>(value >> ((i - 1U) *
kBitsPerByte)));
63 requires std::is_integral_v<T> && std::is_unsigned_v<T>
66 for (std::size_t i = 0U; i <
sizeof(T); ++i)
68 out.push_back(
static_cast<std::uint8_t
>(value >> (i *
kBitsPerByte)));
77 requires std::is_integral_v<T> && std::is_unsigned_v<T>
80 for (std::size_t i = 0U; i <
sizeof(T); ++i)
82 out[i] =
static_cast<std::uint8_t
>(value >> (i *
kBitsPerByte));
89inline void PutU8(std::vector<std::uint8_t>& out, std::uint8_t value)
97inline void PutU16(std::vector<std::uint8_t>& out, std::uint16_t value)
105inline void PutU32(std::vector<std::uint8_t>& out, std::uint32_t value)
114inline void PutBytes(std::vector<std::uint8_t>& out,
const std::uint8_t* data, std::size_t len)
116 out.insert(out.end(), data, data + len);
123template <std::
size_t N>
124inline void PutFixed(std::vector<std::uint8_t>& out,
const std::array<std::uint8_t, N>& data)
126 out.insert(out.end(), data.begin(), data.end());
131inline void PutFixed(std::vector<std::uint8_t>& out,
const std::vector<std::uint8_t>& data)
133 out.insert(out.end(), data.begin(), data.end());
139inline void PutFixed(std::vector<std::uint8_t>& out,
const std::string& data)
141 out.insert(out.end(), data.begin(), data.end());
154 requires std::is_integral_v<T> && std::is_unsigned_v<T>
159 for (std::size_t i = 0U; i <
sizeof(T); ++i)
161 value =
static_cast<T
>((value << kBitsPerByte) | static_cast<T>(data[i]));
173 requires std::is_integral_v<T> && std::is_unsigned_v<T>
178 for (std::size_t i = 0U; i <
sizeof(T); ++i)
180 value =
static_cast<T
>(
204 explicit Reader(std::span<const std::uint8_t> bytes)
211 explicit Reader(
const std::vector<std::uint8_t>& v)
232 [[nodiscard]]
const std::uint8_t*
Cursor()
const
244 throw std::out_of_range(
"wire::Reader: not enough data");
260 Need(
sizeof(std::uint16_t));
261 const auto value = ReadBigEndian<std::uint16_t>(&
data[
pos]);
262 pos +=
sizeof(std::uint16_t);
270 Need(
sizeof(std::uint32_t));
272 const auto value = ReadBigEndian<std::uint32_t>(&
data[
pos]);
273 pos +=
sizeof(std::uint32_t);
281 Need(
sizeof(std::uint16_t));
283 const auto value = ReadLittleEndian<std::uint16_t>(&
data[
pos]);
285 pos +=
sizeof(std::uint16_t);
293 Need(
sizeof(std::uint32_t));
295 const auto value = ReadLittleEndian<std::uint32_t>(&
data[
pos]);
297 pos +=
sizeof(std::uint32_t);
315 template <std::
size_t N>
319 std::array<std::uint8_t, N> value{};
321 std::span source{
data +
pos, N};
322 std::ranges::copy(source, value.begin());
347 throw std::out_of_range(
"wire::Reader: offset is beyond the end of the buffer");
Lightweight cursor for parsing a big-endian byte buffer without copies.
std::uint8_t U8()
Read and consume one byte.
const std::uint8_t * Cursor() const
Pointer to the next unread byte.
std::size_t Position() const
Current read offset from the start of the buffer.
std::uint32_t U32()
Read and consume a big-endian 32-bit value.
const std::uint8_t * data
Pointer to the start of the underlying buffer (not owned).
Reader(const std::uint8_t *data, std::size_t len)
Construct a reader over a raw pointer/length pair.
std::size_t Remaining() const
Number of bytes not yet consumed.
std::array< std::uint8_t, N > Fixed()
Read and consume a fixed-size byte array.
Reader(std::span< const std::uint8_t > bytes)
Construct a reader over a byte span.
void SkipTo(std::size_t offset)
Move the read position to an absolute byte offset.
std::uint32_t U32LittleEndian()
Read and consume a little-endian 32-bit value.
std::size_t pos
Current read offset from the start of the buffer.
void Need(std::size_t n) const
Assert that at least n bytes remain.
void Skip(std::size_t n)
Advance the read position without returning the skipped bytes.
Reader(const std::vector< std::uint8_t > &v)
Construct a reader over an existing byte vector.
std::vector< std::uint8_t > ReadBytes(std::size_t n)
Read and consume a variable-length byte range.
std::uint16_t U16()
Read and consume a big-endian 16-bit value.
std::uint16_t U16LittleEndian()
Read and consume a little-endian 16-bit value.
std::size_t len
Total length of the underlying buffer in bytes.
void PutBytes(std::vector< std::uint8_t > &out, const std::uint8_t *data, std::size_t len)
Append a raw byte range to a buffer.
void PutFixed(std::vector< std::uint8_t > &out, const std::array< std::uint8_t, N > &data)
Append a fixed-size byte array to a buffer.
constexpr T ReadLittleEndian(const std::uint8_t *data)
Decode an unsigned integral value from little-endian bytes.
constexpr T ReadBigEndian(const std::uint8_t *data)
Decode an unsigned integral value from big-endian bytes.
void PutU8(std::vector< std::uint8_t > &out, std::uint8_t value)
Append a single byte to a buffer.
constexpr unsigned kBitsPerByte
void PutU16(std::vector< std::uint8_t > &out, std::uint16_t value)
Append a 16-bit value to a buffer in big-endian order.
void PutLittleEndian(std::vector< std::uint8_t > &out, T value)
Append an unsigned integral value to a buffer in little-endian order.
void PutU32(std::vector< std::uint8_t > &out, std::uint32_t value)
Append a 32-bit value to a buffer in big-endian order.
void PutBigEndian(std::vector< std::uint8_t > &out, T value)
Append an unsigned integral value to a buffer in big-endian order.