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