#ifndef OG_BINARY_BUFFER_H_ #define OG_BINARY_BUFFER_H_ #include #include #include #include #include #include #include #include using byte = unsigned char; inline namespace { template concept IsTupleLike = requires(T t) { std::tuple_size::value; }; template concept IsBasicType = std::integral || std::is_enum::value || std::same_as || std::same_as; template concept IsTupleConvertable = requires(T t) { IsTupleLike; }; static_assert(IsTupleLike>); } class BinaryBuffer { public: BinaryBuffer(); BinaryBuffer(std::size_t n, const byte *buf); template requires IsBasicType BinaryBuffer& operator>>(T& x) { if (sizeof(T) <= data.size()) { auto ptr = reinterpret_cast(&x); for (std::size_t i = 0; i < sizeof(T); ++i) { ptr[i] = data.front(); data.pop_front(); } } return *this; } template requires IsBasicType BinaryBuffer& operator<<(const T& x) { auto ptr = reinterpret_cast(&x); for (std::size_t i = 0; i < sizeof(T); ++i) { data.push_back(ptr[i]); } return *this; } template BinaryBuffer& operator<<(const std::vector& x) { uint32_t len = x.size(); *this << len; for (const T& element : x) *this << element; return *this; } template BinaryBuffer& operator>>(std::vector& x) { uint32_t len; *this >> len; x.resize(len); for (std::uint32_t i = 0; i < len; ++i) *this >> x[i]; return *this; } template requires IsTupleLike BinaryBuffer& operator<<(const T& x) { std::apply([this](const auto&... elements) { (*this << ... << elements); }, x); return *this; } template requires IsTupleLike BinaryBuffer& operator>>(T& x) { std::apply([this](auto&... elements) { (*this >> ... >> elements); }, x); return *this; } template requires IsTupleConvertable BinaryBuffer& operator<<(const T &x) { *this << x.asTuple(); return *this; } template requires IsTupleConvertable BinaryBuffer& operator>>(T &x) { *this >> x.asTuple(); return *this; } BinaryBuffer& operator<<(const std::string_view &); BinaryBuffer& operator>>(std::string&); std::size_t size() const; bool empty() const; void writeTo(std::FILE *out) const; friend std::ostream& operator<<(std::ostream &, const BinaryBuffer &); private: std::deque data; }; std::ostream& operator<<(std::ostream &, const BinaryBuffer &); #endif