diff --git a/projects/kiwano/kiwano.vcxproj b/projects/kiwano/kiwano.vcxproj index e1ee8a95..06c49d61 100644 --- a/projects/kiwano/kiwano.vcxproj +++ b/projects/kiwano/kiwano.vcxproj @@ -29,6 +29,7 @@ + @@ -264,4 +265,4 @@ - + \ No newline at end of file diff --git a/projects/kiwano/kiwano.vcxproj.filters b/projects/kiwano/kiwano.vcxproj.filters index 5a06fc89..034a860a 100644 --- a/projects/kiwano/kiwano.vcxproj.filters +++ b/projects/kiwano/kiwano.vcxproj.filters @@ -324,6 +324,9 @@ core + + core + diff --git a/src/kiwano/core/ObjectBase.cpp b/src/kiwano/core/ObjectBase.cpp index 1e8be8e6..9423407c 100644 --- a/src/kiwano/core/ObjectBase.cpp +++ b/src/kiwano/core/ObjectBase.cpp @@ -87,10 +87,16 @@ void ObjectBase::SetName(const String& name) *name_ = name; } -String ObjectBase::DumpObject() +void ObjectBase::DoSerialize(Serializer* serializer) const { - return strings::Format("{ class=\"%s\" id=%d refcount=%d name=\"%s\" }", typeid(*this).name(), GetObjectID(), - GetRefCount(), GetName().c_str()); + (*serializer) << GetName(); +} + +void ObjectBase::DoDeserialize(Deserializer* deserializer) +{ + String name; + (*deserializer) >> name; + SetName(name); } bool ObjectBase::IsTracingLeaks() @@ -113,7 +119,8 @@ void ObjectBase::DumpTracingObjects() KGE_SYS_LOG("-------------------------- All Objects --------------------------"); for (const auto object : tracing_objects) { - KGE_SYS_LOG("%s", object->DumpObject().c_str()); + KGE_SYS_LOG("{ class=\"%s\" id=%d refcount=%d name=\"%s\" }", typeid(*object).name(), object->GetObjectID(), + object->GetRefCount(), object->GetName().c_str()); } KGE_SYS_LOG("------------------------- Total size: %d -------------------------", tracing_objects.size()); } diff --git a/src/kiwano/core/ObjectBase.h b/src/kiwano/core/ObjectBase.h index a9580f16..38f3d653 100644 --- a/src/kiwano/core/ObjectBase.h +++ b/src/kiwano/core/ObjectBase.h @@ -20,6 +20,7 @@ #pragma once #include +#include #include #include #include @@ -32,7 +33,9 @@ KGE_DECLARE_SMART_PTR(ObjectBase); * \~chinese * @brief 基础对象 */ -class KGE_API ObjectBase : public RefCounter +class KGE_API ObjectBase + : public RefCounter + , public Serializable { public: /// \~chinese @@ -67,8 +70,12 @@ public: uint32_t GetObjectID() const; /// \~chinese - /// @brief 序列化对象 - String DumpObject(); + /// @brief 序列化 + void DoSerialize(Serializer* serializer) const override; + + /// \~chinese + /// @brief 反序列化 + void DoDeserialize(Deserializer* deserializer) override; public: /// \~chinese diff --git a/src/kiwano/core/Serializable.h b/src/kiwano/core/Serializable.h new file mode 100644 index 00000000..52aafecd --- /dev/null +++ b/src/kiwano/core/Serializable.h @@ -0,0 +1,415 @@ +// Copyright (c) 2016-2018 Kiwano - Nomango +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#pragma once +#include + +namespace kiwano +{ + +/// \~chinese +/// @brief 序列化器 +struct Serializer +{ + /// \~chinese + /// @brief 写入字节序列 + virtual void WriteBytes(const uint8_t* bytes, size_t size) = 0; + + /// \~chinese + /// @brief 写入字符串 + void WriteValue(const char* str) + { + size_t len = std::char_traits::length(str); + this->WriteValue(len); + this->WriteBytes(reinterpret_cast(str), len); + } + + /// \~chinese + /// @brief 写入字符串 + void WriteValue(const String& str) + { + this->WriteValue(str.c_str()); + } + + /// \~chinese + /// @brief 写入数组 + template + void WriteValue(const Vector<_Ty>& arr) + { + size_t size = arr.size(); + this->WriteValue(size); + for (const auto& v : arr) + { + (*this) << v; + } + } + + /// \~chinese + /// @brief 写入链表 + template + void WriteValue(const List<_Ty>& list) + { + size_t size = list.size(); + this->WriteValue(size); + for (const auto& v : list) + { + (*this) << v; + } + } + + /// \~chinese + /// @brief 写入集合 + template + void WriteValue(const Set<_Ty>& set) + { + size_t size = set.size(); + this->WriteValue(size); + for (const auto& v : set) + { + (*this) << v; + } + } + + /// \~chinese + /// @brief 写入字典 + template + void WriteValue(const Map<_KTy, _Ty>& map) + { + size_t size = map.size(); + this->WriteValue(size); + for (const auto& p : map) + { + (*this) << p.first << p.second; + } + } + + /// \~chinese + /// @brief 写入值 + template + void WriteValue(const _Ty& value) + { + static_assert(std::is_trivial<_Ty>::value, "_Ty must be trivial type."); + + size_t size = sizeof(_Ty) / sizeof(uint8_t); + this->WriteBytes(reinterpret_cast(&value), size); + } + + template + Serializer& operator<<(const _Ty& value) + { + this->WriteValue(value); + return (*this); + } +}; + +/// \~chinese +/// @brief 字节串序列化器 +struct ByteSerializer : public Serializer +{ + ByteSerializer(Vector& bytes) + : bytes_(bytes) + { + } + + void WriteBytes(const uint8_t* bytes, size_t size) override + { + size_t old_size = bytes_.size(); + this->GenerateSize(size); + std::memcpy(&bytes_[old_size], bytes, size); + } + +private: + void GenerateSize(size_t size) + { + size_t old_size = bytes_.size(); + size_t total_size = old_size + size; + if (total_size > bytes_.capacity()) + { + if (total_size < 1024) + { + size_t expected_size = size_t(std::floor(double(old_size) * 0.5)); + bytes_.reserve(old_size + std::max(size, expected_size)); + } + else if (size < old_size * 2) + { + size_t expected_size = size_t(std::floor(double(old_size) * 0.25)); + bytes_.reserve(old_size + std::max(size, expected_size)); + } + else + { + bytes_.reserve(old_size + size); + } + } + bytes_.resize(total_size); + } + + Vector& bytes_; +}; + +/// \~chinese +/// @brief 流序列化器 +struct StreamSerializer : public Serializer +{ + StreamSerializer(std::basic_ostream& stream) + : stream_(stream) + { + } + + void WriteBytes(const uint8_t* bytes, size_t size) override + { + stream_.write(reinterpret_cast(bytes), size); + } + +private: + std::basic_ostream& stream_; +}; + +/// \~chinese +/// @brief 文件序列化器 +struct FileSerializer : public Serializer +{ + FileSerializer(FILE* file) + : file_(file) + { + } + + void WriteBytes(const uint8_t* bytes, size_t size) override + { + std::fwrite(bytes, sizeof(uint8_t), size, file_); + } + +private: + FILE* file_; +}; + +/// \~chinese +/// @brief 反序列化器 +struct Deserializer +{ + /// \~chinese + /// @brief 读取字节序列 + virtual void ReadBytes(uint8_t* bytes, size_t size) = 0; + + /// \~chinese + /// @brief 读取字符串 + void ReadValue(String* str) + { + size_t len = 0; + this->ReadValue(&len); + if (len) + { + str->resize(len); + this->ReadBytes(reinterpret_cast(&(*str)[0]), len); + } + } + + /// \~chinese + /// @brief 读取数组 + template + void ReadValue(Vector<_Ty>* arr) + { + size_t len = 0; + this->ReadValue(&len); + for (size_t i = 0; i < len; ++i) + { + _Ty value; + (*this) >> value; + arr->push_back(value); + } + } + + /// \~chinese + /// @brief 读取链表 + template + void ReadValue(List<_Ty>* list) + { + size_t len = 0; + this->ReadValue(&len); + for (size_t i = 0; i < len; ++i) + { + _Ty value; + (*this) >> value; + list->push_back(value); + } + } + + /// \~chinese + /// @brief 读取集合 + template + void ReadValue(Set<_Ty>* set) + { + size_t len = 0; + this->ReadValue(&len); + for (size_t i = 0; i < len; ++i) + { + _Ty value; + (*this) >> value; + set->insert(value); + } + } + + /// \~chinese + /// @brief 读取字典 + template + void ReadValue(Map<_KTy, _Ty>* map) + { + size_t len = 0; + this->ReadValue(&len); + for (size_t i = 0; i < len; ++i) + { + _KTy key; + _Ty value; + (*this) >> key >> value; + map->insert(std::make_pair(key, value)); + } + } + + /// \~chinese + /// @brief 读取值 + template + void ReadValue(_Ty* value) + { + static_assert(std::is_trivial<_Ty>::value, "_Ty must be trivial type."); + + size_t size = sizeof(_Ty) / sizeof(uint8_t); + this->ReadBytes(reinterpret_cast(value), size); + } + + template + Deserializer& operator>>(_Ty& value) + { + this->ReadValue(&value); + return (*this); + } +}; + +/// \~chinese +/// @brief 字节串反序列化器 +struct ByteDeserializer : public Deserializer +{ + ByteDeserializer(const Vector& bytes) + : bytes_(bytes) + , index_(0) + { + } + + void ReadBytes(uint8_t* bytes, size_t size) override + { + if (index_ + size > bytes_.size()) + throw std::ios_base::failure("ByteDeserializer::ReadBytes"); + + const uint8_t* ptr = reinterpret_cast(&bytes_[index_]); + std::memcpy(bytes, ptr, size); + index_ += size; + } + +private: + size_t index_; + const Vector& bytes_; +}; + +/// \~chinese +/// @brief 流反序列化器 +struct StreamDeserializer : public Deserializer +{ + StreamDeserializer(std::basic_istream& stream) + : stream_(stream) + { + } + + void ReadBytes(uint8_t* bytes, size_t size) override + { + stream_.read(reinterpret_cast(bytes), size); + } + +private: + std::basic_istream& stream_; +}; + +/// \~chinese +/// @brief 文件反序列化器 +struct FileDeserializer : public Deserializer +{ + FileDeserializer(FILE* file) + : file_(file) + { + } + + void ReadBytes(uint8_t* bytes, size_t size) override + { + size_t count = std::fread(bytes, sizeof(uint8_t), size, file_); + if (count < size) + { + throw std::ios_base::failure("FileDeserializer::ReadBytes"); + } + } + +private: + FILE* file_; +}; + +/// \~chinese +/// @brief 可序列化对象 +class Serializable +{ +public: + /// \~chinese + /// @brief 序列化为字符串 + inline Vector Serialize() const + { + Vector result; + ByteSerializer serializer(result); + this->DoSerialize(&serializer); + return result; + } + + /// \~chinese + /// @brief 从字符串反序列化 + inline void Deserialize(const Vector& serialized) + { + ByteDeserializer deserializer(serialized); + this->DoDeserialize(&deserializer); + } + + /// \~chinese + /// @brief 执行序列化 + virtual void DoSerialize(Serializer* serializer) const = 0; + + /// \~chinese + /// @brief 执行反序列化 + virtual void DoDeserialize(Deserializer* deserializer) = 0; +}; + +/// \~chinese +/// @brief 使用序列化克隆对象 +template +void SerializedClone(const _Ty& src, _Ty2& dest) +{ + static_assert(std::is_base_of::value && std::is_base_of::value, + "Serialized object must be serializable."); + + String bytes = src.Serialize(); + if (!bytes.empty()) + { + dest.Deserialize(bytes); + } +} + +} // namespace kiwano