10#ifndef ENDIAN_BUFFER_HPP
11#define ENDIAN_BUFFER_HPP
14#include "../core/bitmath_func.hpp"
15#include "../strings_type.h"
23template <
typename Tcont =
typename std::vector<u
int8_t>,
typename Titer =
typename std::back_insert_iterator<Tcont>>
32 EndianBufferWriter &operator <<(
const std::string &data) {
return *
this << std::string_view{ data }; }
34 EndianBufferWriter &operator <<(
const char *data) {
return *
this << std::string_view{ data }; }
36 EndianBufferWriter &operator <<(
bool data) {
return *this << static_cast<uint8_t>(data ? 1 : 0); }
38 template <
typename... Targs>
41 this->
WriteTuple(data, std::index_sequence_for<Targs...>{});
45 template <
typename... Targs>
48 this->WriteVariant(variant);
59 this->
Write(data.base());
63 template <
class T>
requires (!std::is_class_v<T>)
66 if constexpr (std::is_enum_v<T>) {
74 template <
typename Tvalue,
typename Tbuf = std::vector<u
int8_t>>
75 static Tbuf FromValue(
const Tvalue &data)
85 template <
class Ttuple,
size_t... Tindices>
86 void WriteTuple(
const Ttuple &values, std::index_sequence<Tindices...>)
88 ((*this << std::get<Tindices>(values)), ...);
91 template <
typename T, std::
size_t I = 0>
92 void WriteVariant(
const T &variant )
94 if constexpr (I < std::variant_size_v<T>) {
95 if (I == variant.index()) {
96 static_assert(std::variant_size_v<T> < std::numeric_limits<uint8_t>::max());
97 this->
Write(
static_cast<uint8_t
>(variant.index()));
98 *this << std::get<I>(variant);
102 WriteVariant<T, I + 1>(variant);
109 for (
auto c : value) {
112 this->buffer++ =
'\0';
119 static_assert(
sizeof(T) <= 8,
"Value can't be larger than 8 bytes");
121 if constexpr (
sizeof(T) > 1) {
122 this->buffer++ =
GB(value, 0, 8);
123 this->buffer++ =
GB(value, 8, 8);
124 if constexpr (
sizeof(T) > 2) {
125 this->buffer++ =
GB(value, 16, 8);
126 this->buffer++ =
GB(value, 24, 8);
128 if constexpr (
sizeof(T) > 4) {
129 this->buffer++ =
GB(value, 32, 8);
130 this->buffer++ =
GB(value, 40, 8);
131 this->buffer++ =
GB(value, 48, 8);
132 this->buffer++ =
GB(value, 56, 8);
135 this->buffer++ = value;
155 void rewind() { this->read_pos = 0; }
159 EndianBufferReader &operator >>(
bool &data) { data = this->Read<uint8_t>() != 0;
return *
this; }
161 template <
typename... Targs>
164 this->
ReadTuple(data, std::index_sequence_for<Targs...>{});
168 template <
typename... Targs>
171 this->ReadVariant(this->Read<uint8_t>(), variant);
180 template <ConvertibleThroughBase T>
183 data = T{this->Read<typename T::BaseType>()};
187 template <
class T>
requires (!std::is_class_v<T>)
190 if constexpr (std::is_enum_v<T>) {
191 data =
static_cast<T
>(this->Read<std::underlying_type_t<T>>());
193 data = this->Read<T>();
198 template <
typename Tvalue>
199 static Tvalue ToValue(std::span<const uint8_t>
buffer)
209 template <
class Ttuple,
size_t... Tindices>
210 void ReadTuple(Ttuple &values, std::index_sequence<Tindices...>)
212 ((*
this >> std::get<Tindices>(values)), ...);
215 template <
typename T, std::
size_t I = 0>
216 void ReadVariant(uint8_t index, T &variant)
218 if constexpr (I < std::variant_size_v<T>) {
220 ReadVariant<T, I + 1>(index, variant);
224 std::variant_alternative_t<I, T> data;
234 while (this->read_pos < this->
buffer.size()) {
235 char ch = this->Read<char>();
236 if (ch ==
'\0')
break;
246 static_assert(!std::is_const_v<T>,
"Can't read into const variables");
247 static_assert(
sizeof(T) <= 8,
"Value can't be larger than 8 bytes");
249 if (
read_pos +
sizeof(T) > this->buffer.size())
return {};
251 T value =
static_cast<T
>(this->buffer[this->read_pos++]);
252 if constexpr (
sizeof(T) > 1) {
253 value +=
static_cast<T
>(this->buffer[this->read_pos++]) << 8;
255 if constexpr (
sizeof(T) > 2) {
256 value +=
static_cast<T
>(this->buffer[this->read_pos++]) << 16;
257 value +=
static_cast<T
>(this->buffer[this->read_pos++]) << 24;
259 if constexpr (
sizeof(T) > 4) {
260 value +=
static_cast<T
>(this->buffer[this->read_pos++]) << 32;
261 value +=
static_cast<T
>(this->buffer[this->read_pos++]) << 40;
262 value +=
static_cast<T
>(this->buffer[this->read_pos++]) << 48;
263 value +=
static_cast<T
>(this->buffer[this->read_pos++]) << 56;
debug_inline static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
Container for an encoded string, created by GetEncodedString.
std::string string
The encoded string.
Endian-aware buffer adapter that always reads values in little endian order.
size_t read_pos
Current read position.
std::span< const uint8_t > buffer
Reference to storage buffer.
void ReadTuple(Ttuple &values, std::index_sequence< Tindices... >)
Helper function to read a tuple from the buffer.
T Read()
Fundamental read function.
std::string ReadStr()
Read overload for string data.
Endian-aware buffer adapter that always writes values in little endian order.
void WriteTuple(const Ttuple &values, std::index_sequence< Tindices... >)
Helper function to write a tuple to the buffer.
Titer buffer
Output iterator for the destination buffer.
void Write(T value)
Fundamental write function.
void Write(std::string_view value)
Write overload for string values.
A type is considered 'convertible through base()' when it has a 'base()' function that returns someth...
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23)