741 lines
21 KiB
C++
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);
|
|
|
|
}
|