add Serializable types
This commit is contained in:
parent
6a10575860
commit
92a845a23a
|
|
@ -29,6 +29,7 @@
|
||||||
<ClInclude Include="..\..\src\kiwano\core\Json.h" />
|
<ClInclude Include="..\..\src\kiwano\core\Json.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\core\Keys.h" />
|
<ClInclude Include="..\..\src\kiwano\core\Keys.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\core\Library.h" />
|
<ClInclude Include="..\..\src\kiwano\core\Library.h" />
|
||||||
|
<ClInclude Include="..\..\src\kiwano\core\Serializable.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\core\Singleton.h" />
|
<ClInclude Include="..\..\src\kiwano\core\Singleton.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\core\String.h" />
|
<ClInclude Include="..\..\src\kiwano\core\String.h" />
|
||||||
<ClInclude Include="..\..\src\kiwano\core\Time.h" />
|
<ClInclude Include="..\..\src\kiwano\core\Time.h" />
|
||||||
|
|
@ -264,4 +265,4 @@
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
@ -324,6 +324,9 @@
|
||||||
<ClInclude Include="..\..\src\kiwano\core\Cloneable.h">
|
<ClInclude Include="..\..\src\kiwano\core\Cloneable.h">
|
||||||
<Filter>core</Filter>
|
<Filter>core</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\kiwano\core\Serializable.h">
|
||||||
|
<Filter>core</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\..\src\kiwano\2d\Canvas.cpp">
|
<ClCompile Include="..\..\src\kiwano\2d\Canvas.cpp">
|
||||||
|
|
|
||||||
|
|
@ -87,10 +87,16 @@ void ObjectBase::SetName(const String& name)
|
||||||
*name_ = 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(),
|
(*serializer) << GetName();
|
||||||
GetRefCount(), GetName().c_str());
|
}
|
||||||
|
|
||||||
|
void ObjectBase::DoDeserialize(Deserializer* deserializer)
|
||||||
|
{
|
||||||
|
String name;
|
||||||
|
(*deserializer) >> name;
|
||||||
|
SetName(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ObjectBase::IsTracingLeaks()
|
bool ObjectBase::IsTracingLeaks()
|
||||||
|
|
@ -113,7 +119,8 @@ void ObjectBase::DumpTracingObjects()
|
||||||
KGE_SYS_LOG("-------------------------- All Objects --------------------------");
|
KGE_SYS_LOG("-------------------------- All Objects --------------------------");
|
||||||
for (const auto object : tracing_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());
|
KGE_SYS_LOG("------------------------- Total size: %d -------------------------", tracing_objects.size());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <kiwano/core/Common.h>
|
#include <kiwano/core/Common.h>
|
||||||
|
#include <kiwano/core/Serializable.h>
|
||||||
#include <kiwano/core/RefCounter.h>
|
#include <kiwano/core/RefCounter.h>
|
||||||
#include <kiwano/core/SmartPtr.hpp>
|
#include <kiwano/core/SmartPtr.hpp>
|
||||||
#include <kiwano/macros.h>
|
#include <kiwano/macros.h>
|
||||||
|
|
@ -32,7 +33,9 @@ KGE_DECLARE_SMART_PTR(ObjectBase);
|
||||||
* \~chinese
|
* \~chinese
|
||||||
* @brief 基础对象
|
* @brief 基础对象
|
||||||
*/
|
*/
|
||||||
class KGE_API ObjectBase : public RefCounter
|
class KGE_API ObjectBase
|
||||||
|
: public RefCounter
|
||||||
|
, public Serializable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
|
|
@ -67,8 +70,12 @@ public:
|
||||||
uint32_t GetObjectID() const;
|
uint32_t GetObjectID() const;
|
||||||
|
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
/// @brief 序列化对象
|
/// @brief ÐòÁл¯
|
||||||
String DumpObject();
|
void DoSerialize(Serializer* serializer) const override;
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief ·´ÐòÁл¯
|
||||||
|
void DoDeserialize(Deserializer* deserializer) override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// \~chinese
|
/// \~chinese
|
||||||
|
|
|
||||||
|
|
@ -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 <kiwano/core/Common.h>
|
||||||
|
|
||||||
|
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<char>::length(str);
|
||||||
|
this->WriteValue(len);
|
||||||
|
this->WriteBytes(reinterpret_cast<const uint8_t*>(str), len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 写入字符串
|
||||||
|
void WriteValue(const String& str)
|
||||||
|
{
|
||||||
|
this->WriteValue(str.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 写入数组
|
||||||
|
template <typename _Ty>
|
||||||
|
void WriteValue(const Vector<_Ty>& arr)
|
||||||
|
{
|
||||||
|
size_t size = arr.size();
|
||||||
|
this->WriteValue(size);
|
||||||
|
for (const auto& v : arr)
|
||||||
|
{
|
||||||
|
(*this) << v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 写入链表
|
||||||
|
template <typename _Ty>
|
||||||
|
void WriteValue(const List<_Ty>& list)
|
||||||
|
{
|
||||||
|
size_t size = list.size();
|
||||||
|
this->WriteValue(size);
|
||||||
|
for (const auto& v : list)
|
||||||
|
{
|
||||||
|
(*this) << v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 写入集合
|
||||||
|
template <typename _Ty>
|
||||||
|
void WriteValue(const Set<_Ty>& set)
|
||||||
|
{
|
||||||
|
size_t size = set.size();
|
||||||
|
this->WriteValue(size);
|
||||||
|
for (const auto& v : set)
|
||||||
|
{
|
||||||
|
(*this) << v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 写入字典
|
||||||
|
template <typename _KTy, typename _Ty>
|
||||||
|
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 <typename _Ty>
|
||||||
|
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<const uint8_t*>(&value), size);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename _Ty>
|
||||||
|
Serializer& operator<<(const _Ty& value)
|
||||||
|
{
|
||||||
|
this->WriteValue(value);
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 字节串序列化器
|
||||||
|
struct ByteSerializer : public Serializer
|
||||||
|
{
|
||||||
|
ByteSerializer(Vector<uint8_t>& 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<uint8_t>& bytes_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 流序列化器
|
||||||
|
struct StreamSerializer : public Serializer
|
||||||
|
{
|
||||||
|
StreamSerializer(std::basic_ostream<char>& stream)
|
||||||
|
: stream_(stream)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteBytes(const uint8_t* bytes, size_t size) override
|
||||||
|
{
|
||||||
|
stream_.write(reinterpret_cast<const char*>(bytes), size);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::basic_ostream<char>& 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<uint8_t*>(&(*str)[0]), len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 读取数组
|
||||||
|
template <typename _Ty>
|
||||||
|
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 <typename _Ty>
|
||||||
|
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 <typename _Ty>
|
||||||
|
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 <typename _KTy, typename _Ty>
|
||||||
|
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 <typename _Ty>
|
||||||
|
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<uint8_t*>(value), size);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename _Ty>
|
||||||
|
Deserializer& operator>>(_Ty& value)
|
||||||
|
{
|
||||||
|
this->ReadValue(&value);
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 字节串反序列化器
|
||||||
|
struct ByteDeserializer : public Deserializer
|
||||||
|
{
|
||||||
|
ByteDeserializer(const Vector<uint8_t>& 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<const uint8_t*>(&bytes_[index_]);
|
||||||
|
std::memcpy(bytes, ptr, size);
|
||||||
|
index_ += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t index_;
|
||||||
|
const Vector<uint8_t>& bytes_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 流反序列化器
|
||||||
|
struct StreamDeserializer : public Deserializer
|
||||||
|
{
|
||||||
|
StreamDeserializer(std::basic_istream<char>& stream)
|
||||||
|
: stream_(stream)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReadBytes(uint8_t* bytes, size_t size) override
|
||||||
|
{
|
||||||
|
stream_.read(reinterpret_cast<char*>(bytes), size);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::basic_istream<char>& 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<uint8_t> Serialize() const
|
||||||
|
{
|
||||||
|
Vector<uint8_t> result;
|
||||||
|
ByteSerializer serializer(result);
|
||||||
|
this->DoSerialize(&serializer);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \~chinese
|
||||||
|
/// @brief 从字符串反序列化
|
||||||
|
inline void Deserialize(const Vector<uint8_t>& 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 <typename _Ty, typename _Ty2>
|
||||||
|
void SerializedClone(const _Ty& src, _Ty2& dest)
|
||||||
|
{
|
||||||
|
static_assert(std::is_base_of<Serializable, _Ty>::value && std::is_base_of<Serializable, _Ty2>::value,
|
||||||
|
"Serialized object must be serializable.");
|
||||||
|
|
||||||
|
String bytes = src.Serialize();
|
||||||
|
if (!bytes.empty())
|
||||||
|
{
|
||||||
|
dest.Deserialize(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace kiwano
|
||||||
Loading…
Reference in New Issue