JD2022-TU1/main/extern/dtest/dtcore/inc/dtstream.h

741 lines
21 KiB
C++

#pragma once
#include "dtcore/inc/dtstring.h"
#include "dtcore/inc/dtbytebuffer.h"
#include "dtcore/inc/dtvector.h"
#include "dtcore/inc/dtqueue.h"
#include "dtcore/inc/dtmap.h"
#include "dtcore/inc/dtset.h"
#include "dtcore/inc/dtstrongtype.h"
#include "dtcore/inc/dtchrono.h"
#include "dtcore/inc/dterror.h"
#pragma warning(push)
#include <memory>
#pragma warning(pop)
namespace dt
{
static const char SERIALIZE_VERSION_MEMBER_NAME[] = "_version";
enum StreamType
{
StreamType_None = 0,
StreamType_Binary = 1,
StreamType_String = 2,
StreamType_S8 = 3,
StreamType_S16 = 4,
StreamType_S32 = 5,
StreamType_S64 = 6,
StreamType_U8 = 7,
StreamType_U16 = 8,
StreamType_U32 = 9,
StreamType_U64 = 10,
StreamType_Float = 11,
StreamType_Double = 12,
StreamType_Bool = 13,
StreamType_Object = 14,
StreamType_List = 15,
};
// Stream interface for serialization. See StreamTextOutput, StreamBinaryInput and
// StreamBinaryOutput classes for actual implementation of this interface.
class Stream
{
public:
DT_CORE_DLL_ENTRY virtual ~Stream() {}
DT_CORE_DLL_ENTRY virtual void SerializeBinary(const ByteBuffer& data) = 0;
DT_CORE_DLL_ENTRY virtual bool SerializeBinary(ByteBuffer& data) = 0;
DT_CORE_DLL_ENTRY virtual void SerializeString(const String& data) = 0;
DT_CORE_DLL_ENTRY virtual bool SerializeString(String& data) = 0;
DT_CORE_DLL_ENTRY virtual void SerializeNumeral(const S8& data) = 0;
DT_CORE_DLL_ENTRY virtual bool SerializeNumeral(S8& data) = 0;
DT_CORE_DLL_ENTRY virtual void SerializeNumeral(const S16& data) = 0;
DT_CORE_DLL_ENTRY virtual bool SerializeNumeral(S16& data) = 0;
DT_CORE_DLL_ENTRY virtual void SerializeNumeral(const S32& data) = 0;
DT_CORE_DLL_ENTRY virtual bool SerializeNumeral(S32& data) = 0;
DT_CORE_DLL_ENTRY virtual void SerializeNumeral(const S64& data) = 0;
DT_CORE_DLL_ENTRY virtual bool SerializeNumeral(S64& data) = 0;
DT_CORE_DLL_ENTRY virtual void SerializeNumeral(const U8& data) = 0;
DT_CORE_DLL_ENTRY virtual bool SerializeNumeral(U8& data) = 0;
DT_CORE_DLL_ENTRY virtual void SerializeNumeral(const U16& data) = 0;
DT_CORE_DLL_ENTRY virtual bool SerializeNumeral(U16& data) = 0;
DT_CORE_DLL_ENTRY virtual void SerializeNumeral(const U32& data) = 0;
DT_CORE_DLL_ENTRY virtual bool SerializeNumeral(U32& data) = 0;
DT_CORE_DLL_ENTRY virtual void SerializeNumeral(const U64& data) = 0;
DT_CORE_DLL_ENTRY virtual bool SerializeNumeral(U64& data) = 0;
DT_CORE_DLL_ENTRY virtual void SerializeNumeral(const float& data) = 0;
DT_CORE_DLL_ENTRY virtual bool SerializeNumeral(float& data) = 0;
DT_CORE_DLL_ENTRY virtual void SerializeNumeral(const double& data) = 0;
DT_CORE_DLL_ENTRY virtual bool SerializeNumeral(double& data) = 0;
DT_CORE_DLL_ENTRY virtual void SerializeBool(const bool& data) = 0;
DT_CORE_DLL_ENTRY virtual bool SerializeBool(bool& data) = 0;
DT_CORE_DLL_ENTRY virtual void SerializeSize(const SizeT& data) = 0;
DT_CORE_DLL_ENTRY virtual bool SerializeSize(SizeT& data) = 0;
DT_CORE_DLL_ENTRY virtual void SerializeVersion(U8& data) = 0;
DT_CORE_DLL_ENTRY virtual bool SerializeMember(const char* name) = 0;
DT_CORE_DLL_ENTRY virtual void SerializeKey(const String& name) = 0;
DT_CORE_DLL_ENTRY virtual bool SerializeKey(String& name) = 0;
DT_CORE_DLL_ENTRY virtual void ObjectStart(const void* pointer) = 0;
DT_CORE_DLL_ENTRY virtual void ObjectEnd(const void* pointer) = 0;
DT_CORE_DLL_ENTRY virtual void ListStart(const void* pointer) = 0;
DT_CORE_DLL_ENTRY virtual void ListEnd(const void* pointer) = 0;
DT_CORE_DLL_ENTRY virtual bool IsInput() const = 0;
};
// Base class that define the basic serialization methods
class Serializable
{
public:
DT_CORE_DLL_ENTRY virtual ~Serializable() {}
DT_CORE_DLL_ENTRY virtual void Serialize(U8 version, Stream& stream) = 0;
DT_CORE_DLL_ENTRY virtual U8 GetSerializeVersion() const { return 1; }
};
// Helper macros for serialization
#define dtVariable(variable) dt::StreamMember<decltype(variable)>(#variable, variable)
#define dtVariableNamed(variable, variableName) dt::StreamMember<decltype(variable)>(variableName, variable)
#define dtVariableEnumNamed(variable, variableName) dt::StreamMemberEnum<decltype(variable)>(variableName, variable)
#define dtMember(member) dt::StreamMember<decltype(member)>(#member, this->member)
#define dtMemberEnum(member) dt::StreamMemberEnum<decltype(member)>(#member, this->member)
// Helper template class for serialization of class members
template <typename T> class StreamMember
{
public:
StreamMember(const char* name, T& member)
: m_Name(name)
, m_Member(member)
{}
const char* GetName() const { return m_Name; }
T& GetMember() const { return m_Member; }
private:
const char* m_Name;
T& m_Member;
};
template <typename T> class StreamMemberEnum
{
public:
StreamMemberEnum(const char* name, T& member)
: m_Name(name)
, m_Member(member)
{}
const char* GetName() const { return m_Name; }
T& GetMember() const { return m_Member; }
private:
const char* m_Name;
T& m_Member;
};
class StreamObjectStart
{
public:
DT_CORE_DLL_ENTRY StreamObjectStart(const void* pointer)
: m_Pointer(pointer)
{}
DT_CORE_DLL_ENTRY const void* GetPointer() const { return m_Pointer; }
private:
const void* m_Pointer;
};
class StreamObjectEnd
{
public:
DT_CORE_DLL_ENTRY StreamObjectEnd(const void* pointer)
: m_Pointer(pointer)
{}
DT_CORE_DLL_ENTRY const void* GetPointer() const { return m_Pointer; }
private:
const void* m_Pointer;
};
class StreamListStart
{
public:
DT_CORE_DLL_ENTRY StreamListStart(const void* pointer)
: m_Pointer(pointer)
{}
DT_CORE_DLL_ENTRY const void* GetPointer() const { return m_Pointer; }
private:
const void* m_Pointer;
};
class StreamListEnd
{
public:
DT_CORE_DLL_ENTRY StreamListEnd(const void* pointer)
: m_Pointer(pointer)
{}
DT_CORE_DLL_ENTRY const void* GetPointer() const { return m_Pointer; }
private:
const void* m_Pointer;
};
// Serialization macros
template <typename T, class ALLOCATOR> Stream& operator<<(Stream& stream, const Vector<T, ALLOCATOR>& data)
{
stream.ListStart(&data);
DT_ASSERT(!stream.IsInput());
SizeT size(data.Size());
stream.SerializeSize(size);
for (auto i = data.Begin(); i != data.End(); ++i)
{
stream << *i;
}
stream.ListEnd(&data);
return stream;
}
template <typename T, class ALLOCATOR> Stream& operator<<(Stream& stream, Vector<T, ALLOCATOR>& data)
{
stream.ListStart(&data);
if (stream.IsInput())
{
SizeT size(0);
stream.SerializeSize(size);
data.Resize(size);
}
else
{
SizeT size(data.Size());
stream.SerializeSize(size);
}
for (auto i = data.Begin(); i != data.End(); ++i)
{
stream << *i;
}
stream.ListEnd(&data);
return stream;
}
template <typename T, class ALLOCATOR> Stream& operator<<(Stream& stream, const Queue<T, ALLOCATOR>& data)
{
stream.ListStart(&data);
DT_ASSERT(!stream.IsInput());
SizeT size(data.Size());
stream.SerializeSize(size);
for (auto i = data.Begin(); i != data.End(); ++i)
{
stream << *i;
}
stream.ListEnd(&data);
return stream;
}
template <typename T, class ALLOCATOR> Stream& operator<<(Stream& stream, Queue<T, ALLOCATOR>& data)
{
stream.ListStart(&data);
if (stream.IsInput())
{
SizeT size(0);
stream.SerializeSize(size);
data.Resize(size);
}
else
{
SizeT size(data.Size());
stream.SerializeSize(size);
}
for (auto i = data.Begin(); i != data.End(); ++i)
{
stream << *i;
}
stream.ListEnd(&data);
return stream;
}
template <class VALUE, class KEYTRAITS, class ALLOCATOR>
Stream& operator<<(Stream& stream, const Map<String, VALUE, KEYTRAITS, ALLOCATOR>& data)
{
stream.ObjectStart(&data);
SizeT size(data.Size());
stream.SerializeSize(size);
DT_ASSERT(!stream.IsInput());
for (const auto& i : data)
{
stream.SerializeKey(i.first);
stream << i.second;
}
stream.ObjectEnd(&data);
return stream;
}
#pragma warning(push)
#pragma warning(disable: 4700) // uninitialized local variable 'value' used
template <class VALUE, class KEYTRAITS, class ALLOCATOR>
Stream& operator<<(Stream& stream, Map<String, VALUE, KEYTRAITS, ALLOCATOR>& data)
{
stream.ObjectStart(&data);
SizeT size(data.Size());
stream.SerializeSize(size);
if (stream.IsInput())
{
for (SizeT i = 0; i < size; i++)
{
String key;
stream.SerializeKey(key);
VALUE value;
stream << value;
data.InsertOrAssign(key, value);
}
}
else
{
for (const auto& i : data)
{
stream.SerializeKey(i.first);
stream << i.second;
}
}
stream.ObjectEnd(&data);
return stream;
}
#pragma warning(pop)
template <class KEY, class VALUE, class KEYTRAITS, class ALLOCATOR>
Stream& operator<<(Stream& stream, const Map<KEY, VALUE, KEYTRAITS, ALLOCATOR>& data)
{
stream.ObjectStart(&data);
SizeT size(data.Size());
stream.SerializeSize(size);
DT_ASSERT(!stream.IsInput());
for (const auto& i : data)
{
String key;
key << i.first;
stream.SerializeKey(key);
stream << i.second;
}
stream.ObjectEnd(&data);
return stream;
}
#pragma warning(push)
#pragma warning(disable: 4700) // uninitialized local variable 'value' used
template <class KEY, class VALUE, class KEYTRAITS, class ALLOCATOR>
Stream& operator<<(Stream& stream, Map<KEY, VALUE, KEYTRAITS, ALLOCATOR>& data)
{
stream.ObjectStart(&data);
SizeT size(data.Size());
stream.SerializeSize(size);
if (stream.IsInput())
{
String keyStr;
KEY key;
VALUE value;
for (SizeT i = 0; i < size; i++)
{
stream.SerializeKey(keyStr);
stream << value;
data.InsertOrAssign(keyStr >> key, value);
}
}
else
{
for (const auto& i : data)
{
String key;
key << i.first;
stream.SerializeKey(key);
stream << i.second;
}
}
stream.ObjectEnd(&data);
return stream;
}
#pragma warning(pop)
template <class VALUE, class KEYTRAITS, class ALLOCATOR>
Stream& operator<<(Stream& stream, const Set<VALUE, KEYTRAITS, ALLOCATOR>& data)
{
stream.ListStart(&data);
SizeT size(data.Size());
stream.SerializeSize(size);
DT_ASSERT(!stream.IsInput());
for (auto i = data.Begin(); i != data.End(); ++i)
{
stream << *i;
}
stream.ListEnd(&data);
return stream;
}
#pragma warning(push)
#pragma warning(disable: 4700) // uninitialized local variable 'value' used
template <class VALUE, class KEYTRAITS, class ALLOCATOR>
Stream& operator<<(Stream& stream, Set<VALUE, KEYTRAITS, ALLOCATOR>& data)
{
stream.ListStart(&data);
SizeT size(data.Size());
stream.SerializeSize(size);
if (stream.IsInput())
{
VALUE value;
for (SizeT i = 0; i < size; i++)
{
stream << value;
data.Insert(value);
}
}
else
{
for (auto i = data.Begin(); i != data.End(); ++i)
{
stream << *i;
}
}
stream.ListEnd(&data);
return stream;
}
#pragma warning(pop)
inline Stream& operator<<(Stream& stream, String& data)
{
stream.SerializeString(data);
return stream;
}
inline Stream& operator<<(Stream& stream, const String& data)
{
stream.SerializeString(data);
return stream;
}
template <typename T, typename Param> inline Stream& operator<<(Stream& stream, StrongType<T, Param>& data)
{
stream.SerializeNumeral(data.UnboxValue());
return stream;
}
template <typename T, typename Param> inline Stream& operator<<(Stream& stream, const StrongType<T, Param>& data)
{
stream.SerializeNumeral(data.UnboxValue());
return stream;
}
template <typename Rep, typename Period> inline Stream& operator<<(Stream& stream, std::chrono::duration<Rep, Period>& data)
{
if (stream.IsInput())
{
Rep r = 0;
if (stream.SerializeNumeral(r))
{
data = std::chrono::duration<Rep, Period>(r);
}
}
else
{
stream.SerializeNumeral(data.count());
}
return stream;
}
template <typename Rep, typename Period> inline Stream& operator<<(Stream& stream, const std::chrono::duration<Rep, Period>& data)
{
stream.SerializeNumeral(data.count());
return stream;
}
inline Stream& operator<<(Stream& stream, const char* data)
{
stream.SerializeString(data);
return stream;
}
inline Stream& operator<<(Stream& stream, S8& data)
{
stream.SerializeNumeral(data);
return stream;
}
inline Stream& operator<<(Stream& stream, const S8& data)
{
stream.SerializeNumeral(data);
return stream;
}
inline Stream& operator<<(Stream& stream, S16& data)
{
stream.SerializeNumeral(data);
return stream;
}
inline Stream& operator<<(Stream& stream, const S16& data)
{
stream.SerializeNumeral(data);
return stream;
}
inline Stream& operator<<(Stream& stream, S32& data)
{
stream.SerializeNumeral(data);
return stream;
}
inline Stream& operator<<(Stream& stream, const S32& data)
{
stream.SerializeNumeral(data);
return stream;
}
inline Stream& operator<<(Stream& stream, S64& data)
{
stream.SerializeNumeral(data);
return stream;
}
inline Stream& operator<<(Stream& stream, const S64& data)
{
stream.SerializeNumeral(data);
return stream;
}
inline Stream& operator<<(Stream& stream, U8& data)
{
stream.SerializeNumeral(data);
return stream;
}
inline Stream& operator<<(Stream& stream, const U8& data)
{
stream.SerializeNumeral(data);
return stream;
}
inline Stream& operator<<(Stream& stream, U16& data)
{
stream.SerializeNumeral(data);
return stream;
}
inline Stream& operator<<(Stream& stream, const U16& data)
{
stream.SerializeNumeral(data);
return stream;
}
inline Stream& operator<<(Stream& stream, U32& data)
{
stream.SerializeNumeral(data);
return stream;
}
inline Stream& operator<<(Stream& stream, const U32& data)
{
stream.SerializeNumeral(data);
return stream;
}
inline Stream& operator<<(Stream& stream, U64& data)
{
stream.SerializeNumeral(data);
return stream;
}
inline Stream& operator<<(Stream& stream, const U64& data)
{
stream.SerializeNumeral(data);
return stream;
}
inline Stream& operator<<(Stream& stream, float& data)
{
stream.SerializeNumeral(data);
return stream;
}
inline Stream& operator<<(Stream& stream, const float& data)
{
stream.SerializeNumeral(data);
return stream;
}
inline Stream& operator<<(Stream& stream, double& data)
{
stream.SerializeNumeral(data);
return stream;
}
inline Stream& operator<<(Stream& stream, const double& data)
{
stream.SerializeNumeral(data);
return stream;
}
inline Stream& operator<<(Stream& stream, bool& data)
{
stream.SerializeBool(data);
return stream;
}
inline Stream& operator<<(Stream& stream, const bool& data)
{
stream.SerializeBool(data);
return stream;
}
inline Stream& operator<<(Stream& stream, ByteBuffer& data)
{
stream.SerializeBinary(data);
return stream;
}
inline Stream& operator<<(Stream& stream, const ByteBuffer& data)
{
stream.SerializeBinary(data);
return stream;
}
template <typename T> inline Stream& operator<<(Stream& stream, const StreamMember<T>& member)
{
if (stream.SerializeMember(member.GetName()))
{
stream << member.GetMember();
}
return stream;
}
template <typename T> inline Stream& operator<<(Stream& stream, const StreamMemberEnum<T>& member)
{
if (stream.SerializeMember(member.GetName()))
{
if (stream.IsInput())
{
S32 data(0);
stream.SerializeNumeral(data);
member.GetMember() = static_cast<T>(data);
}
else
{
stream.SerializeNumeral(static_cast<S32>(member.GetMember()));
}
}
return stream;
}
inline Stream& operator<<(Stream& stream, const StreamObjectStart& scope)
{
stream.ObjectStart(scope.GetPointer());
return stream;
}
inline Stream& operator<<(Stream& stream, const StreamObjectEnd& scope)
{
stream.ObjectEnd(scope.GetPointer());
return stream;
}
template <typename T> inline Stream& operator<<(Stream& stream, T& object)
{
U8 version(object.GetSerializeVersion());
stream.ObjectStart(&object);
stream.SerializeVersion(version);
object.Serialize(version, stream);
stream.ObjectEnd(&object);
return stream;
}
template <typename T> inline Stream& operator<<(Stream& stream, const T& object)
{
U8 version(object.GetSerializeVersion());
stream.ObjectStart(&object);
stream.SerializeVersion(version);
((T&)object).Serialize(version, stream);
stream.ObjectEnd(&object);
return stream;
}
template <typename T> inline Stream& operator<<(Stream& stream, std::shared_ptr<T>& object)
{
if (stream.IsInput())
{
if (!object)
{
object = std::make_shared<T>();
}
}
else
{
DT_ASSERT(object); // nullptr not supported
}
U8 version(object->GetSerializeVersion());
stream.ObjectStart(object.get());
stream.SerializeVersion(version);
object->Serialize(version, stream);
stream.ObjectEnd(object.get());
return stream;
}
template <typename T> inline Stream& operator<<(Stream& stream, const std::shared_ptr<T>& object)
{
DT_ASSERT(object); // nullptr not supported
U8 version(object->GetSerializeVersion());
stream.ObjectStart(object.get());
stream.SerializeVersion(version);
object->Serialize(version, stream);
stream.ObjectEnd(object.get());
return stream;
}
template <typename T> inline Stream& operator<<(Stream& stream, T* object)
{
U8 version(object ? object->GetSerializeVersion() : 1);
stream.ObjectStart(object);
stream.SerializeVersion(version);
if (object)
{
object->Serialize(version, stream);
}
stream.ObjectEnd(object);
return stream;
}
template <typename T> inline Stream& operator<<(Stream& stream, const T*)
{
// Stream input with pointers is not supported and we do not plan
// on adding this. The function is required to compile because
// streaming is bi-directional.
DT_ASSERT_NOT_IMPLEMENTED();
return stream;
}
DT_CORE_DLL_ENTRY String& operator<<(String& out, const Serializable& object);
}