Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/core/StarDataStream.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/core/StarDataStream.hpp')
-rw-r--r--source/core/StarDataStream.hpp393
1 files changed, 393 insertions, 0 deletions
diff --git a/source/core/StarDataStream.hpp b/source/core/StarDataStream.hpp
new file mode 100644
index 0000000..2508a00
--- /dev/null
+++ b/source/core/StarDataStream.hpp
@@ -0,0 +1,393 @@
+#ifndef STAR_DATA_STREAM_HPP
+#define STAR_DATA_STREAM_HPP
+
+#include "StarString.hpp"
+
+namespace Star {
+
+STAR_EXCEPTION(DataStreamException, IOException);
+
+// Writes complex types to bytes in a portable big-endian fashion.
+class DataStream {
+public:
+ DataStream();
+ virtual ~DataStream() = default;
+
+ static unsigned const CurrentStreamVersion = 1;
+
+ // DataStream defaults to big-endian order for all primitive types
+ ByteOrder byteOrder() const;
+ void setByteOrder(ByteOrder byteOrder);
+
+ // DataStream can optionally write strings as null terminated rather than
+ // length prefixed
+ bool nullTerminatedStrings() const;
+ void setNullTerminatedStrings(bool nullTerminatedStrings);
+
+ // streamCompatibilityVersion defaults to CurrentStreamVersion, but can be
+ // changed for compatibility with older versions of DataStream serialization.
+ unsigned streamCompatibilityVersion() const;
+ void setStreamCompatibilityVersion(unsigned streamCompatibilityVersion);
+
+ // Do direct reads and writes
+ virtual void readData(char* data, size_t len) = 0;
+ virtual void writeData(char const* data, size_t len) = 0;
+
+ // These do not read / write sizes, they simply read / write directly.
+ ByteArray readBytes(size_t len);
+ void writeBytes(ByteArray const& ba);
+
+ DataStream& operator<<(bool d);
+ DataStream& operator<<(char c);
+ DataStream& operator<<(int8_t d);
+ DataStream& operator<<(uint8_t d);
+ DataStream& operator<<(int16_t d);
+ DataStream& operator<<(uint16_t d);
+ DataStream& operator<<(int32_t d);
+ DataStream& operator<<(uint32_t d);
+ DataStream& operator<<(int64_t d);
+ DataStream& operator<<(uint64_t d);
+ DataStream& operator<<(float d);
+ DataStream& operator<<(double d);
+
+ DataStream& operator>>(bool& d);
+ DataStream& operator>>(char& c);
+ DataStream& operator>>(int8_t& d);
+ DataStream& operator>>(uint8_t& d);
+ DataStream& operator>>(int16_t& d);
+ DataStream& operator>>(uint16_t& d);
+ DataStream& operator>>(int32_t& d);
+ DataStream& operator>>(uint32_t& d);
+ DataStream& operator>>(int64_t& d);
+ DataStream& operator>>(uint64_t& d);
+ DataStream& operator>>(float& d);
+ DataStream& operator>>(double& d);
+
+ // Writes and reads a VLQ encoded integer. Can write / read anywhere from 1
+ // to 10 bytes of data, with integers of smaller (absolute) value taking up
+ // fewer bytes. size_t version can be used to portably write a size_t type,
+ // and portably and efficiently handles the case of NPos.
+
+ size_t writeVlqU(uint64_t i);
+ size_t writeVlqI(int64_t i);
+ size_t writeVlqS(size_t i);
+
+ size_t readVlqU(uint64_t& i);
+ size_t readVlqI(int64_t& i);
+ size_t readVlqS(size_t& i);
+
+ uint64_t readVlqU();
+ int64_t readVlqI();
+ size_t readVlqS();
+
+ // The following functions write / read data with length and then content
+ // following, but note that the length is encoded as an unsigned VLQ integer.
+ // String objects are encoded in utf8, and can optionally be written as null
+ // terminated rather than length then content.
+
+ DataStream& operator<<(const char* s);
+ DataStream& operator<<(std::string const& d);
+ DataStream& operator<<(ByteArray const& d);
+ DataStream& operator<<(String const& s);
+
+ DataStream& operator>>(std::string& d);
+ DataStream& operator>>(ByteArray& d);
+ DataStream& operator>>(String& s);
+
+ // All enum types are automatically serializable
+
+ template <typename EnumType, typename = typename std::enable_if<std::is_enum<EnumType>::value>::type>
+ DataStream& operator<<(EnumType const& e);
+
+ template <typename EnumType, typename = typename std::enable_if<std::is_enum<EnumType>::value>::type>
+ DataStream& operator>>(EnumType& e);
+
+ // Convenience method to avoid temporary.
+ template <typename T>
+ T read();
+
+ // Convenient argument style reading / writing
+
+ template <typename Data>
+ void read(Data& data);
+
+ template <typename Data>
+ void write(Data const& data);
+
+ // Argument style reading / writing with casting.
+
+ template <typename ReadType, typename Data>
+ void cread(Data& data);
+
+ template <typename WriteType, typename Data>
+ void cwrite(Data const& data);
+
+ // Argument style reading / writing of variable length integers. Arguments
+ // are explicitly casted, so things like enums are allowed.
+
+ template <typename IntegralType>
+ void vuread(IntegralType& data);
+
+ template <typename IntegralType>
+ void viread(IntegralType& data);
+
+ template <typename IntegralType>
+ void vsread(IntegralType& data);
+
+ template <typename IntegralType>
+ void vuwrite(IntegralType const& data);
+
+ template <typename IntegralType>
+ void viwrite(IntegralType const& data);
+
+ template <typename IntegralType>
+ void vswrite(IntegralType const& data);
+
+ // Store a fixed point number as a variable length integer
+
+ template <typename FloatType>
+ void vfread(FloatType& data, FloatType base);
+
+ template <typename FloatType>
+ void vfwrite(FloatType const& data, FloatType base);
+
+ // Read a shared / unique ptr, and store whether the pointer is initialized.
+
+ template <typename PointerType, typename ReadFunction>
+ void pread(PointerType& pointer, ReadFunction readFunction);
+
+ template <typename PointerType, typename WriteFunction>
+ void pwrite(PointerType const& pointer, WriteFunction writeFunction);
+
+ template <typename PointerType>
+ void pread(PointerType& pointer);
+
+ template <typename PointerType>
+ void pwrite(PointerType const& pointer);
+
+ // WriteFunction should be void (DataStream& ds, Element const& e)
+ template <typename Container, typename WriteFunction>
+ void writeContainer(Container const& container, WriteFunction function);
+
+ // ReadFunction should be void (DataStream& ds, Element& e)
+ template <typename Container, typename ReadFunction>
+ void readContainer(Container& container, ReadFunction function);
+
+ template <typename Container, typename WriteFunction>
+ void writeMapContainer(Container& map, WriteFunction function);
+
+ // Specialization of readContainer for map types (whose elements are a pair
+ // with the key type marked const)
+ template <typename Container, typename ReadFunction>
+ void readMapContainer(Container& map, ReadFunction function);
+
+ template <typename Container>
+ void writeContainer(Container const& container);
+
+ template <typename Container>
+ void readContainer(Container& container);
+
+ template <typename Container>
+ void writeMapContainer(Container const& container);
+
+ template <typename Container>
+ void readMapContainer(Container& container);
+
+private:
+ void writeStringData(char const* data, size_t len);
+
+ ByteOrder m_byteOrder;
+ bool m_nullTerminatedStrings;
+ unsigned m_streamCompatibilityVersion;
+};
+
+template <typename EnumType, typename>
+DataStream& DataStream::operator<<(EnumType const& e) {
+ *this << (typename std::underlying_type<EnumType>::type)e;
+ return *this;
+}
+
+template <typename EnumType, typename>
+DataStream& DataStream::operator>>(EnumType& e) {
+ typename std::underlying_type<EnumType>::type i;
+ *this >> i;
+ e = (EnumType)i;
+ return *this;
+}
+
+template <typename T>
+T DataStream::read() {
+ T t;
+ *this >> t;
+ return t;
+}
+
+template <typename Data>
+void DataStream::read(Data& data) {
+ *this >> data;
+}
+
+template <typename Data>
+void DataStream::write(Data const& data) {
+ *this << data;
+}
+
+template <typename ReadType, typename Data>
+void DataStream::cread(Data& data) {
+ ReadType v;
+ *this >> v;
+ data = (Data)v;
+}
+
+template <typename WriteType, typename Data>
+void DataStream::cwrite(Data const& data) {
+ WriteType v = (WriteType)data;
+ *this << v;
+}
+
+template <typename IntegralType>
+void DataStream::vuread(IntegralType& data) {
+ uint64_t i = readVlqU();
+ data = (IntegralType)i;
+}
+
+template <typename IntegralType>
+void DataStream::viread(IntegralType& data) {
+ int64_t i = readVlqI();
+ data = (IntegralType)i;
+}
+
+template <typename IntegralType>
+void DataStream::vsread(IntegralType& data) {
+ size_t s = readVlqS();
+ data = (IntegralType)s;
+}
+
+template <typename IntegralType>
+void DataStream::vuwrite(IntegralType const& data) {
+ writeVlqU((uint64_t)data);
+}
+
+template <typename IntegralType>
+void DataStream::viwrite(IntegralType const& data) {
+ writeVlqI((int64_t)data);
+}
+
+template <typename IntegralType>
+void DataStream::vswrite(IntegralType const& data) {
+ writeVlqS((size_t)data);
+}
+
+template <typename FloatType>
+void DataStream::vfread(FloatType& data, FloatType base) {
+ int64_t i = readVlqI();
+ data = (FloatType)i * base;
+}
+
+template <typename FloatType>
+void DataStream::vfwrite(FloatType const& data, FloatType base) {
+ writeVlqI((int64_t)round(data / base));
+}
+
+template <typename PointerType, typename ReadFunction>
+void DataStream::pread(PointerType& pointer, ReadFunction readFunction) {
+ bool initialized = read<bool>();
+ if (initialized) {
+ auto element = make_unique<typename std::decay<typename PointerType::element_type>::type>();
+ readFunction(*this, *element);
+ pointer.reset(element.release());
+ } else {
+ pointer.reset();
+ }
+}
+
+template <typename PointerType, typename WriteFunction>
+void DataStream::pwrite(PointerType const& pointer, WriteFunction writeFunction) {
+ if (pointer) {
+ write(true);
+ writeFunction(*this, *pointer);
+ } else {
+ write(false);
+ }
+}
+
+template <typename PointerType>
+void DataStream::pread(PointerType& pointer) {
+ return pread(pointer, [](DataStream& ds, typename std::decay<typename PointerType::element_type>::type& value) {
+ ds.read(value);
+ });
+}
+
+template <typename PointerType>
+void DataStream::pwrite(PointerType const& pointer) {
+ return pwrite(pointer, [](DataStream& ds, typename std::decay<typename PointerType::element_type>::type const& value) {
+ ds.write(value);
+ });
+}
+
+template <typename Container, typename WriteFunction>
+void DataStream::writeContainer(Container const& container, WriteFunction function) {
+ writeVlqU(container.size());
+ for (auto const& elem : container)
+ function(*this, elem);
+}
+
+template <typename Container, typename ReadFunction>
+void DataStream::readContainer(Container& container, ReadFunction function) {
+ container.clear();
+ size_t size = readVlqU();
+ for (size_t i = 0; i < size; ++i) {
+ typename Container::value_type elem;
+ function(*this, elem);
+ container.insert(container.end(), elem);
+ }
+}
+
+template <typename Container, typename WriteFunction>
+void DataStream::writeMapContainer(Container& map, WriteFunction function) {
+ writeVlqU(map.size());
+ for (auto const& elem : map)
+ function(*this, elem.first, elem.second);
+}
+
+template <typename Container, typename ReadFunction>
+void DataStream::readMapContainer(Container& map, ReadFunction function) {
+ map.clear();
+ size_t size = readVlqU();
+ for (size_t i = 0; i < size; ++i) {
+ typename Container::key_type key;
+ typename Container::mapped_type mapped;
+ function(*this, key, mapped);
+ map.insert(make_pair(move(key), move(mapped)));
+ }
+}
+
+template <typename Container>
+void DataStream::writeContainer(Container const& container) {
+ writeContainer(container, [](DataStream& ds, typename Container::value_type const& element) { ds << element; });
+}
+
+template <typename Container>
+void DataStream::readContainer(Container& container) {
+ readContainer(container, [](DataStream& ds, typename Container::value_type& element) { ds >> element; });
+}
+
+template <typename Container>
+void DataStream::writeMapContainer(Container const& container) {
+ writeMapContainer(container, [](DataStream& ds, typename Container::key_type const& key, typename Container::mapped_type const& mapped) {
+ ds << key;
+ ds << mapped;
+ });
+}
+
+template <typename Container>
+void DataStream::readMapContainer(Container& container) {
+ readMapContainer(container, [](DataStream& ds, typename Container::key_type& key, typename Container::mapped_type& mapped) {
+ ds >> key;
+ ds >> mapped;
+ });
+}
+
+}
+
+#endif