416 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			C
		
	
	
	
		
		
			
		
	
	
			416 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			C
		
	
	
	
|  | // 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 <20><><EFBFBD>л<EFBFBD><D0BB><EFBFBD>
 | |||
|  | struct Serializer | |||
|  | { | |||
|  |     /// \~chinese
 | |||
|  |     /// @brief д<><D0B4><EFBFBD>ֽ<EFBFBD><D6BD><EFBFBD><EFBFBD><EFBFBD>
 | |||
|  |     virtual void WriteBytes(const uint8_t* bytes, size_t size) = 0; | |||
|  | 
 | |||
|  |     /// \~chinese
 | |||
|  |     /// @brief д<><D0B4><EFBFBD>ַ<EFBFBD><D6B7><EFBFBD>
 | |||
|  |     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 д<><D0B4><EFBFBD>ַ<EFBFBD><D6B7><EFBFBD>
 | |||
|  |     void WriteValue(const String& str) | |||
|  |     { | |||
|  |         this->WriteValue(str.c_str()); | |||
|  |     } | |||
|  | 
 | |||
|  |     /// \~chinese
 | |||
|  |     /// @brief д<><D0B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
 | |||
|  |     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 д<><D0B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
 | |||
|  |     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 д<>뼯<EFBFBD><EBBCAF>
 | |||
|  |     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 д<><D0B4><EFBFBD>ֵ<EFBFBD>
 | |||
|  |     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 д<><D0B4>ֵ
 | |||
|  |     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 <20>ֽڴ<D6BD><DAB4><EFBFBD><EFBFBD>л<EFBFBD><D0BB><EFBFBD>
 | |||
|  | 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 <20><><EFBFBD><EFBFBD><EFBFBD>л<EFBFBD><D0BB><EFBFBD>
 | |||
|  | 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 <20>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD>л<EFBFBD><D0BB><EFBFBD>
 | |||
|  | 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 <20><><EFBFBD><EFBFBD><EFBFBD>л<EFBFBD><D0BB><EFBFBD>
 | |||
|  | struct Deserializer | |||
|  | { | |||
|  |     /// \~chinese
 | |||
|  |     /// @brief <20><>ȡ<EFBFBD>ֽ<EFBFBD><D6BD><EFBFBD><EFBFBD><EFBFBD>
 | |||
|  |     virtual void ReadBytes(uint8_t* bytes, size_t size) = 0; | |||
|  | 
 | |||
|  |     /// \~chinese
 | |||
|  |     /// @brief <20><>ȡ<EFBFBD>ַ<EFBFBD><D6B7><EFBFBD>
 | |||
|  |     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 <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>
 | |||
|  |     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 <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>
 | |||
|  |     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 <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>
 | |||
|  |     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 <20><>ȡ<EFBFBD>ֵ<EFBFBD>
 | |||
|  |     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 <20><>ȡֵ
 | |||
|  |     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 <20>ֽڴ<D6BD><DAB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>л<EFBFBD><D0BB><EFBFBD>
 | |||
|  | 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 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>л<EFBFBD><D0BB><EFBFBD>
 | |||
|  | 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 <20>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>л<EFBFBD><D0BB><EFBFBD>
 | |||
|  | 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 <20><><EFBFBD><EFBFBD><EFBFBD>л<EFBFBD><D0BB><EFBFBD><EFBFBD><EFBFBD>
 | |||
|  | class Serializable | |||
|  | { | |||
|  | public: | |||
|  |     /// \~chinese
 | |||
|  |     /// @brief <20><><EFBFBD>л<EFBFBD>Ϊ<EFBFBD>ַ<EFBFBD><D6B7><EFBFBD>
 | |||
|  |     inline Vector<uint8_t> Serialize() const | |||
|  |     { | |||
|  |         Vector<uint8_t>  result; | |||
|  |         ByteSerializer serializer(result); | |||
|  |         this->DoSerialize(&serializer); | |||
|  |         return result; | |||
|  |     } | |||
|  | 
 | |||
|  |     /// \~chinese
 | |||
|  |     /// @brief <20><><EFBFBD>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>л<EFBFBD>
 | |||
|  |     inline void Deserialize(const Vector<uint8_t>& serialized) | |||
|  |     { | |||
|  |         ByteDeserializer deserializer(serialized); | |||
|  |         this->DoDeserialize(&deserializer); | |||
|  |     } | |||
|  | 
 | |||
|  |     /// \~chinese
 | |||
|  |     /// @brief ִ<><D6B4><EFBFBD><EFBFBD><EFBFBD>л<EFBFBD>
 | |||
|  |     virtual void DoSerialize(Serializer* serializer) const = 0; | |||
|  | 
 | |||
|  |     /// \~chinese
 | |||
|  |     /// @brief ִ<>з<EFBFBD><D0B7><EFBFBD><EFBFBD>л<EFBFBD>
 | |||
|  |     virtual void DoDeserialize(Deserializer* deserializer) = 0; | |||
|  | }; | |||
|  | 
 | |||
|  | /// \~chinese
 | |||
|  | /// @brief ʹ<><CAB9><EFBFBD><EFBFBD><EFBFBD>л<EFBFBD><D0BB><EFBFBD>¡<EFBFBD><C2A1><EFBFBD><EFBFBD>
 | |||
|  | 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
 |