v1.4.4
This commit is contained in:
commit
9c94d113d3
10260 changed files with 1237388 additions and 0 deletions
393
source/core/StarDataStream.hpp
Normal file
393
source/core/StarDataStream.hpp
Normal file
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue