diff options
author | Roland Reichwein <mail@reichwein.it> | 2023-01-05 18:10:39 +0100 |
---|---|---|
committer | Roland Reichwein <mail@reichwein.it> | 2023-01-05 18:10:39 +0100 |
commit | cdf2c1132ec9a12ea6d91c8deb1700c1a590c18d (patch) | |
tree | 1e792e0de184c2cabf9e923479e224d8b8126edf /archive.h | |
parent | 7973293c311e27ff08a1488c9759c1b5b0fda30e (diff) |
Added archive.h
Diffstat (limited to 'archive.h')
-rw-r--r-- | archive.h | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/archive.h b/archive.h new file mode 100644 index 0000000..1218505 --- /dev/null +++ b/archive.h @@ -0,0 +1,227 @@ +#pragma once + +#include <boost/coroutine2/coroutine.hpp> +#include <boost/endian/conversion.hpp> + +#include <cstdint> +#include <ostream> +#include <iostream> +#include <istream> +#include <sstream> +#include <string> +#include <vector> + +typedef boost::coroutines2::coroutine<void> coro_t; + +// Serialization, similar to Boost Serialization +// but for portable binary archive +// using big endian coding (network byte order) +namespace Serialization { + +class OArchive +{ +public: + OArchive(std::ostream& os): os(os) {} + ~OArchive() {} + + template<class T> + OArchive& operator &(T& v) { + v.serialize(*this); + + return *this; + }; + + template <class T> + OArchive& write_fundamental(T& v) + { + T value = boost::endian::native_to_big(v); + os.write(reinterpret_cast<char*>(&value), sizeof(value)); + return *this; + } + + OArchive& operator &(uint8_t& v) + { + return write_fundamental(v); + }; + + OArchive& operator &(uint16_t& v) + { + return write_fundamental(v); + }; + + OArchive& operator &(uint32_t& v) + { + return write_fundamental(v); + }; + + OArchive& operator &(uint64_t& v) + { + return write_fundamental(v); + }; + + OArchive& operator &(int64_t& v) + { + return write_fundamental(*reinterpret_cast<uint64_t*>(&v)); + }; + + OArchive& operator &(std::vector<uint8_t>& v) + { + uint32_t size = static_cast<uint32_t>(v.size()); + *this & size; + os.write((char*)v.data(), size); + return *this; + }; + + OArchive& operator &(std::string& v) + { + uint32_t size = static_cast<uint32_t>(v.size()); + *this & size; + os.write((char*)v.data(), v.size()); + return *this; + }; + +private: + std::ostream &os; +}; + +class IArchive +{ +public: + IArchive(std::istream& is): is(is) {} + IArchive(std::stringstream& is, coro_t::pull_type& coro) : is(is), mStringStream(&is), mCoro(&coro) {} + ~IArchive() {} + + template<class T> + IArchive& operator &(T& v) + { + v.serialize(*this); + + return *this; + }; + + template <class T> + IArchive& read_fundamental(T& v) + { + // in coroutine case, wait for input, if necessary + if (mCoro && mStringStream) { + while (true) { + auto pindex {mStringStream->tellp()}; + auto gindex {mStringStream->tellg()}; + if (pindex != std::stringstream::pos_type(-1) && gindex != std::stringstream::pos_type(-1) && pindex >= gindex) { + if (static_cast<size_t>(pindex - gindex) < sizeof(v)) + (*mCoro)(); + else + break; + } else { + std::cerr << "Error: read_fundamental: Bad stringstream indices: " << pindex << ", " << gindex << std::endl; + break; + } + } + } + + // now, we have enough bytes available + T value; + is.read((char*)&value, sizeof(value)); + v = boost::endian::big_to_native(value); + return *this; + } + + IArchive& operator &(uint8_t& v) + { + return read_fundamental(v); + }; + + IArchive& operator &(uint16_t& v) + { + return read_fundamental(v); + }; + + IArchive& operator &(uint32_t& v) + { + return read_fundamental(v); + }; + + IArchive& operator &(uint64_t& v) + { + return read_fundamental(v); + }; + + IArchive& operator &(int64_t& v) + { + uint64_t uv; + read_fundamental(uv); + v = *reinterpret_cast<int64_t*>(&uv); + return *this; + }; + + template <class T> + IArchive& read_bytes_vector(T& v) + { + uint32_t size; + *this & size; + + v.resize(size); + + // in coroutine case, wait for input, if necessary + if (mCoro && mStringStream) { + while (true) { + auto pindex {mStringStream->tellp()}; + auto gindex {mStringStream->tellg()}; + if (pindex != std::stringstream::pos_type(-1) && gindex != std::stringstream::pos_type(-1) && pindex >= gindex) { + if (static_cast<uint32_t>(pindex - gindex) < size) + (*mCoro)(); + else + break; + } else { + std::cerr << "Error: read_bytes_vector: Bad stringstream indices: " << pindex << ", " << gindex << std::endl; + break; + } + } + } + + // now, we have enough bytes available + is.read((char*)v.data(), size); + return *this; + } + + IArchive& operator &(std::vector<uint8_t>& v) + { + return read_bytes_vector(v); + }; + + IArchive& operator &(std::string& v) + { + return read_bytes_vector(v); + }; + +private: + std::istream &is; + std::stringstream* mStringStream{ }; // for i/o sizes access + coro_t::pull_type* mCoro{ }; // optional for coroutine +}; + +// - Free functions ---------------------------------------------------------- + +template<class Archive, class T> +void serialize(Archive& ar, T& v) +{ + ar & v; +} + +template<class T> +OArchive& operator <<(OArchive& ar, T& v) +{ + serialize(ar, v); + + return ar; +}; + +template<class T> +IArchive& operator >>(IArchive& ar, T& v) +{ + serialize(ar, v); + + return ar; +}; + +} |