diff --git a/include/Nazara/Core/Algorithm.hpp b/include/Nazara/Core/Algorithm.hpp index dee7f1ac0..de5d31041 100644 --- a/include/Nazara/Core/Algorithm.hpp +++ b/include/Nazara/Core/Algorithm.hpp @@ -38,9 +38,6 @@ namespace Nz inline bool HashAppend(AbstractHash* hash, std::string_view v); - template - std::enable_if_t::value, bool> Unserialize(SerializationContext& context, T* value, TypeTag); - // Vertex processing class Joint; struct VertexStruct_XYZ_Normal_UV_Tangent; diff --git a/include/Nazara/Core/BinarySerialization.hpp b/include/Nazara/Core/BinarySerialization.hpp new file mode 100644 index 000000000..e0089030e --- /dev/null +++ b/include/Nazara/Core/BinarySerialization.hpp @@ -0,0 +1,54 @@ +#pragma once + +#include + +namespace Nz +{ + + struct NAZARA_CORE_API BinarySerializationContext final + : public SerializationContext + { + public: + bool PushObject(std::string_view name) override; + bool PopObject() override; + bool PushArray(std::string_view name) override; + bool PopArray() override; + + bool Write(std::string_view name, bool value) override; + bool Write(std::string_view name, Nz::Int8 value) override; + bool Write(std::string_view name, Nz::Int16 value) override; + bool Write(std::string_view name, Nz::Int32 value) override; + bool Write(std::string_view name, Nz::Int64 value) override; + bool Write(std::string_view name, Nz::UInt8 value) override; + bool Write(std::string_view name, Nz::UInt16 value) override; + bool Write(std::string_view name, Nz::UInt32 value) override; + bool Write(std::string_view name, Nz::UInt64 value) override; + bool Write(std::string_view name, float value) override; + bool Write(std::string_view name, double value) override; + bool Write(std::string_view name, const std::string& value) override; + + bool Read(std::string_view name, bool* value) override; + bool Read(std::string_view name, Nz::Int8* value) override; + bool Read(std::string_view name, Nz::Int16* value) override; + bool Read(std::string_view name, Nz::Int32* value) override; + bool Read(std::string_view name, Nz::Int64* value) override; + bool Read(std::string_view name, Nz::UInt8* value) override; + bool Read(std::string_view name, Nz::UInt16* value) override; + bool Read(std::string_view name, Nz::UInt32* value) override; + bool Read(std::string_view name, Nz::UInt64* value) override; + bool Read(std::string_view name, float* value) override; + bool Read(std::string_view name, double* value) override; + bool Read(std::string_view name, std::string* value) override; + + MovablePtr stream; + Endianness endianness = Endianness::BigEndian; //< Default to Big Endian encoding + UInt8 readBitPos = 8; //< 8 means no bit is currently read + UInt8 readByte; //< Undefined value, will be initialized at the first bit read + UInt8 writeBitPos = 8; //< 8 means no bit is currently wrote + UInt8 writeByte; //< Undefined value, will be initialized at the first bit write + + void FlushBits(); + void ResetReadBitPosition(); + void ResetWriteBitPosition(); + }; +} diff --git a/include/Nazara/Core/ByteStream.hpp b/include/Nazara/Core/ByteStream.hpp index ac5095a4f..467857581 100644 --- a/include/Nazara/Core/ByteStream.hpp +++ b/include/Nazara/Core/ByteStream.hpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include namespace Nz @@ -60,7 +60,7 @@ namespace Nz virtual void OnEmptyStream(); std::unique_ptr m_ownedStream; - SerializationContext m_context; + BinarySerializationContext m_context; }; } diff --git a/include/Nazara/Core/ByteStream.inl b/include/Nazara/Core/ByteStream.inl index 65fe62a46..a5348827f 100644 --- a/include/Nazara/Core/ByteStream.inl +++ b/include/Nazara/Core/ByteStream.inl @@ -87,7 +87,7 @@ namespace Nz { m_context.writeBitPos = 8; //< To prevent Serialize to flush bits itself - if (!Serialize(m_context, m_context.writeByte)) + if (!Serialize(m_context, "bytes", m_context.writeByte)) return false; } @@ -167,7 +167,7 @@ namespace Nz if (!m_context.stream) OnEmptyStream(); - if (!Unserialize(m_context, &value)) + if (!Unserialize(m_context, "", &value)) NazaraError("failed to serialize value"); return *this; @@ -188,7 +188,7 @@ namespace Nz if (!m_context.stream) OnEmptyStream(); - if (!Serialize(m_context, value)) + if (!Serialize(m_context, "", value)) NazaraError("failed to serialize value"); return *this; diff --git a/include/Nazara/Core/Color.inl b/include/Nazara/Core/Color.inl index dfc39066c..fba494b20 100644 --- a/include/Nazara/Core/Color.inl +++ b/include/Nazara/Core/Color.inl @@ -711,16 +711,16 @@ namespace Nz */ inline bool Serialize(SerializationContext& context, const Color& color, TypeTag) { - if (!Serialize(context, color.r)) + if (!Serialize(context, "R", color.r)) return false; - if (!Serialize(context, color.g)) + if (!Serialize(context, "G", color.g)) return false; - if (!Serialize(context, color.b)) + if (!Serialize(context, "B", color.b)) return false; - if (!Serialize(context, color.a)) + if (!Serialize(context, "A", color.a)) return false; return true; @@ -735,16 +735,16 @@ namespace Nz */ inline bool Unserialize(SerializationContext& context, Color* color, TypeTag) { - if (!Unserialize(context, &color->r)) + if (!Unserialize(context, "R", &color->r)) return false; - if (!Unserialize(context, &color->g)) + if (!Unserialize(context, "G", &color->g)) return false; - if (!Unserialize(context, &color->b)) + if (!Unserialize(context, "B", &color->b)) return false; - if (!Unserialize(context, &color->a)) + if (!Unserialize(context, "A", &color->a)) return false; return true; diff --git a/include/Nazara/Core/Serialization.hpp b/include/Nazara/Core/Serialization.hpp index ea7ea06b8..2c02c9c85 100644 --- a/include/Nazara/Core/Serialization.hpp +++ b/include/Nazara/Core/Serialization.hpp @@ -13,41 +13,106 @@ #include #include #include +#include #include namespace Nz { + template + concept Numeric = std::is_arithmetic::value; + struct NAZARA_CORE_API SerializationContext { - MovablePtr stream; - Endianness endianness = Endianness::BigEndian; //< Default to Big Endian encoding - UInt8 readBitPos = 8; //< 8 means no bit is currently read - UInt8 readByte; //< Undefined value, will be initialized at the first bit read - UInt8 writeBitPos = 8; //< 8 means no bit is currently wrote - UInt8 writeByte; //< Undefined value, will be initialized at the first bit write + public: + virtual bool PushObject(std::string_view name) = 0; + virtual bool PopObject() = 0; + virtual bool PushArray(std::string_view name) = 0; + virtual bool PopArray() = 0; - void FlushBits(); - inline void ResetReadBitPosition(); - inline void ResetWriteBitPosition(); + virtual bool Write(std::string_view name, bool value) = 0; + virtual bool Write(std::string_view name, Nz::Int8 value) = 0; + virtual bool Write(std::string_view name, Nz::Int16 value) = 0; + virtual bool Write(std::string_view name, Nz::Int32 value) = 0; + virtual bool Write(std::string_view name, Nz::Int64 value) = 0; + virtual bool Write(std::string_view name, Nz::UInt8 value) = 0; + virtual bool Write(std::string_view name, Nz::UInt16 value) = 0; + virtual bool Write(std::string_view name, Nz::UInt32 value) = 0; + virtual bool Write(std::string_view name, Nz::UInt64 value) = 0; + virtual bool Write(std::string_view name, float value) = 0; + virtual bool Write(std::string_view name, double value) = 0; + virtual bool Write(std::string_view name, const std::string& value) = 0; + + virtual bool Read(std::string_view name, bool* value) = 0; + virtual bool Read(std::string_view name, Nz::Int8* value) = 0; + virtual bool Read(std::string_view name, Nz::Int16* value) = 0; + virtual bool Read(std::string_view name, Nz::Int32* value) = 0; + virtual bool Read(std::string_view name, Nz::Int64* value) = 0; + virtual bool Read(std::string_view name, Nz::UInt8* value) = 0; + virtual bool Read(std::string_view name, Nz::UInt16* value) = 0; + virtual bool Read(std::string_view name, Nz::UInt32* value) = 0; + virtual bool Read(std::string_view name, Nz::UInt64* value) = 0; + virtual bool Read(std::string_view name, float* value) = 0; + virtual bool Read(std::string_view name, double* value) = 0; + virtual bool Read(std::string_view name, std::string* value) = 0; }; template - bool Serialize(SerializationContext& context, T&& value); - - inline bool Serialize(SerializationContext& context, bool value, TypeTag); - inline bool Serialize(SerializationContext& context, const std::string& value, TypeTag); + inline bool Serialize(SerializationContext&, T, TypeTag) { return false; } template - std::enable_if_t::value, bool> Serialize(SerializationContext& context, T value, TypeTag); + bool Serialize(SerializationContext& context, std::string_view name, const T& value); template - bool Unserialize(SerializationContext& context, T* value); + inline bool Serialize(SerializationContext& context, std::string_view name, const T& value, TypeTag); - inline bool Unserialize(SerializationContext& context, bool* value, TypeTag); - inline bool Unserialize(SerializationContext& context, std::string* value, TypeTag); + inline bool Serialize(SerializationContext& context, std::string_view name, const bool& value, TypeTag); + inline bool Serialize(SerializationContext& context, std::string_view name, const std::string& value, TypeTag); + + template + bool Serialize(SerializationContext& context, std::string_view name, const T (&values)[N]); + + template + bool Serialize(SerializationContext& context, std::string_view name, const std::array& values); template - std::enable_if_t::value, bool> Unserialize(SerializationContext& context, T* value, TypeTag); + bool Serialize(SerializationContext& context, std::string_view name, const std::vector& values); + + template + bool Serialize(SerializationContext& context, std::string_view name, const Nz::EnumArray& values); + + template + inline bool Serialize(SerializationContext& context, std::string_view name, const T& value, TypeTag); + + + template + inline bool Unserialize(SerializationContext&, T*, TypeTag) { return false; } + + template + inline bool Unserialize(SerializationContext& context, std::string_view name, T* value); + + template + bool Unserialize(SerializationContext& context, std::string_view name, T* value, TypeTag); + + template <> + inline bool Unserialize(SerializationContext& context, std::string_view name, bool* value, TypeTag); + + template <> + inline bool Unserialize(SerializationContext& context, std::string_view name, std::string* value, TypeTag); + + template + bool Unserialize(SerializationContext& context, std::string_view name, T (*values)[N]); + + template + bool Unserialize(SerializationContext& context, std::string_view name, std::array* values); + + template + bool Unserialize(SerializationContext& context, std::string_view name, std::vector* values); + + template + bool Unserialize(SerializationContext& context, std::string_view name, Nz::EnumArray* values); + + template + inline bool Unserialize(SerializationContext& context, std::string_view name, T* value, TypeTag); } #include diff --git a/include/Nazara/Core/Serialization.inl b/include/Nazara/Core/Serialization.inl index a671e9b2d..b41d07089 100644 --- a/include/Nazara/Core/Serialization.inl +++ b/include/Nazara/Core/Serialization.inl @@ -5,31 +5,22 @@ namespace Nz { - /*! - * \brief Reset the current read bit cursor - */ - inline void SerializationContext::ResetReadBitPosition() + template + inline bool Serialize(SerializationContext& context, std::string_view name, const T& value) { - readBitPos = 8; - } - - /*! - * \brief Reset the current read bit cursor - - * \remark This function only reset the cursor position, it doesn't do any writing - if you wish to write all bits and reset bit position, call FlushBits - - \see FlushBits - */ - inline void SerializationContext::ResetWriteBitPosition() - { - writeBitPos = 8; + return Serialize(context, name, value, TypeTag>()); } template - bool Serialize(SerializationContext& context, T&& value) + bool Serialize(SerializationContext& context, std::string_view name, const T& value, TypeTag) { - return Serialize(context, std::forward(value), TypeTag>()); + if (!context.PushObject(name)) + return false; + + if (!Serialize(context, value, TypeTag>())) + return false; + + return context.PopObject(); } /*! @@ -42,21 +33,9 @@ namespace Nz * * \see Serialize, Unserialize */ - inline bool Serialize(SerializationContext& context, bool value, TypeTag) + inline bool Serialize(SerializationContext& context, std::string_view name, const bool& value, TypeTag) { - if (context.writeBitPos == 8) - { - context.writeBitPos = 0; - context.writeByte = 0; - } - - if (value) - context.writeByte |= 1 << context.writeBitPos; - - if (++context.writeBitPos >= 8) - return Serialize(context, context.writeByte, TypeTag()); - else - return true; + return context.Write(name, value); } /*! @@ -67,12 +46,69 @@ namespace Nz * \param context Context for the serialization * \param value String to serialize */ - bool Serialize(SerializationContext& context, const std::string& value, TypeTag) + inline bool Serialize(SerializationContext& context, std::string_view name, const std::string& value, TypeTag) { - if (!Serialize(context, SafeCast(value.size()), TypeTag())) + return context.Write(name, value); + } + + template + bool Serialize(SerializationContext& context, std::string_view name, const T(&values)[N]) + { + if (!context.PushArray(name)) return false; - return context.stream->Write(value.data(), value.size()) == value.size(); + for (size_t i = 0; i < N; ++i) + { + if (!Serialize(context, "", values[i])) + return false; + } + + return context.PopArray(); + } + + template + bool Serialize(SerializationContext& context, std::string_view name, const std::array& values) + { + if (!context.PushArray(name)) + return false; + + for (auto&& value : values) + { + if (!Serialize(context, "", value)) + return false; + } + + return context.PopArray(); + } + + template + bool Serialize(SerializationContext& context, std::string_view name, const std::vector& values) + { + if (!context.PushArray(name)) + return false; + + for (auto&& value : values) + { + if (!Serialize(context, "", value)) + return false; + } + + return context.PopArray(); + } + + template + bool Serialize(SerializationContext& context, std::string_view name, const Nz::EnumArray& values) + { + if (!context.PushArray(name)) + return false; + + for (auto&& value : values) + { + if (!Serialize(context, "", value)) + return false; + } + + return context.PopArray(); } /*! @@ -85,23 +121,29 @@ namespace Nz * * \see Serialize, Unserialize */ - template - std::enable_if_t::value, bool> Serialize(SerializationContext& context, T value, TypeTag) + template + inline bool Serialize(SerializationContext& context, std::string_view name, const T& value, TypeTag) { - // Flush bits in case a writing is in progress - context.FlushBits(); - - if (context.endianness != Endianness::Unknown && context.endianness != PlatformEndianness) - value = ByteSwap(value); - - return context.stream->Write(&value, sizeof(T)) == sizeof(T); + return context.Write(name, value); } template - bool Unserialize(SerializationContext& context, T* value) + inline bool Unserialize(SerializationContext& context, std::string_view name, T* value) { - return Unserialize(context, value, TypeTag()); + return Unserialize(context, name, value, TypeTag>()); + } + + template + bool Unserialize(SerializationContext& context, std::string_view name, T* value, TypeTag) + { + if (!context.PushObject(name)) + return false; + + if (!Unserialize(context, value, TypeTag())) + return false; + + return context.PopObject(); } /*! @@ -114,22 +156,9 @@ namespace Nz * * \see Serialize, Unserialize */ - inline bool Unserialize(SerializationContext& context, bool* value, TypeTag) + inline bool Unserialize(SerializationContext& context, std::string_view name, bool* value, TypeTag) { - if (context.readBitPos == 8) - { - if (!Unserialize(context, &context.readByte, TypeTag())) - return false; - - context.readBitPos = 0; - } - - if (value) - *value = (context.readByte & (1 << context.readBitPos)) != 0; - - context.readBitPos++; - - return true; + return context.Read(name, value); } /*! @@ -139,14 +168,69 @@ namespace Nz * \param context Context of unserialization * \param string std::string to unserialize */ - bool Unserialize(SerializationContext& context, std::string* string, TypeTag) + inline bool Unserialize(SerializationContext& context, std::string_view name, std::string* string, TypeTag) { - UInt32 size; - if (!Unserialize(context, &size, TypeTag())) + return context.Read(name, string); + } + + template + bool Unserialize(SerializationContext& context, std::string_view name, T(*values)[N]) + { + if (!context.PushArray(name)) return false; - string->resize(size); - return context.stream->Read(&(*string)[0], size) == size; + for (size_t i = 0; i < N; ++i) + { + if (!Unserialize(context, "", &(*values[i]))) + return false; + } + + return context.PopArray(); + } + + template + bool Unserialize(SerializationContext& context, std::string_view name, std::array* values) + { + if (!context.PushArray(name)) + return false; + + for (auto&& value : *values) + { + if (!Unserialize(context, "", &value)) + return false; + } + + return context.PopArray(); + } + + template + bool Unserialize(SerializationContext& context, std::string_view name, std::vector* values) + { + if (!context.PushArray(name)) + return false; + + for (auto&& value : *values) + { + if (!Unserialize(context, "", &value)) + return false; + } + + return context.PopArray(); + } + + template + bool Unserialize(SerializationContext& context, std::string_view name, Nz::EnumArray* values) + { + if (!context.PushArray(name)) + return false; + + for (auto&& value : *values) + { + if (!Unserialize(context, "", &value)) + return false; + } + + return context.PopArray(); } /*! @@ -161,22 +245,10 @@ namespace Nz * * \see Serialize, Unserialize */ - template - std::enable_if_t::value, bool> Unserialize(SerializationContext& context, T* value, TypeTag) + template + inline bool Unserialize(SerializationContext& context, std::string_view name, T* value, TypeTag) { - NazaraAssert(value, "Invalid data pointer"); - - context.ResetReadBitPosition(); - - if (context.stream->Read(value, sizeof(T)) == sizeof(T)) - { - if (context.endianness != Endianness::Unknown && context.endianness != PlatformEndianness) - *value = ByteSwap(*value); - - return true; - } - else - return false; + return context.Read(name, value); } } diff --git a/include/Nazara/Core/Time.inl b/include/Nazara/Core/Time.inl index 6fa1892e7..083c7112b 100644 --- a/include/Nazara/Core/Time.inl +++ b/include/Nazara/Core/Time.inl @@ -213,7 +213,7 @@ namespace Nz inline bool Serialize(SerializationContext& context, Time time, TypeTag