Skip to content

Instantly share code, notes, and snippets.

@tianchaijz
Last active August 2, 2019 05:57
Show Gist options
  • Save tianchaijz/b842d158e6518ae44fd96dae439e4bec to your computer and use it in GitHub Desktop.
Save tianchaijz/b842d158e6518ae44fd96dae439e4bec to your computer and use it in GitHub Desktop.

https://blog.csdn.net/g2com/article/details/64904256

比特币客户端所有的序列化函数均在 seriliaze.h 中实现。其中,CDataStream类是数据序列化的核心结构。

CDataStream 拥有一个字符类容器用来存放序列化之后的数据。它结合一个容器类型和一个流(stream)API 以处理数据。

宏 READDATA() 和 WRITEDATA()

#define WRITEDATA(s, obj)   s.write((char*)&(obj), sizeof(obj))
#define READDATA(s, obj)    s.read((char*)&(obj), sizeof(obj))

CDataStream 重载了操作符 <<>>用于序列化和反序列化。

template <typename T>
CDataStream &operator<<(const T &obj) {
    // Serialize to this stream
    ::Serialize(*this, obj, nType, nVersion);
    return (*this);
}

template <typename T>
CDataStream &operator>>(T &obj) {
    // Unserialize from this stream
    ::Unserialize(*this, obj, nType, nVersion);
    return (*this);
}

头文件serialize.h包含了14个重载后的这两个全局函数给14个原始类型(signed和unsigned版本char,short,int,long和long long,以及char,float,double和bool)以及6个重载版本的6个复合类型(string,vector,pair,map,set和CScript)。因此,对于这些类型,你可以简单地使用以下代码来序列化/反序列化数据:

如果没有任何实现的类型符合第二个参数obj,则以下泛型T全局函数将会被调用。

template<typename Stream, typename T>
inline void Serialize(Stream& os, const T& a, long nType, int nVersion=VERSION)
{
    a.Serialize(os, (int)nType, nVersion);
}

对于该泛型版本,类型T应该用于实现一个成员函数和签名T::Serialize(Stream, int, int)。它将通过a.Serialize()被调用。

怎样实现一个类型的序列化

泛型T需要实现以下三个成员函数进行序列化。

unsigned int GetSerializeSize(int nType = 0, int nVersion = VERSION) const;
void Serialize(Stream &s, int nType = 0, int nVersion = VERSION) const;
void Unserialize(Stream &s, int nType = 0, int nVersion = VERSION);

一个宏IMPLEMENT_SERIALIZE(statements)用于定义任意类型的这三个函数的实现。

宏READWRITE()的定义如下

#define READWRITE(obj)      (nSerSize += ::SerReadWrite(s, (obj), nType, nVersion, ser_action))

ser_action是一个对象在三个函数当中均有声明,但为三种不同类型。它在三个函数当中分别为

  • CSerActionGetSerializeSize
  • CSerActionSerialize
  • CSerActionUnserialize
template <typename Stream, typename T>
inline unsigned int SerReadWrite(Stream &s, const T &obj, int nType,
                                 int nVersion,
                                 CSerActionGetSerializeSize ser_action) {
    return ::GetSerializeSize(obj, nType, nVersion);
}

template <typename Stream, typename T>
inline unsigned int SerReadWrite(Stream &s, const T &obj, int nType,
                                 int nVersion, CSerActionSerialize ser_action) {
    ::Serialize(s, obj, nType, nVersion);
    return 0;
}

template <typename Stream, typename T>
inline unsigned int SerReadWrite(Stream &s, T &obj, int nType, int nVersion,
                                 CSerActionUnserialize ser_action) {
    ::Unserialize(s, obj, nType, nVersion);
    return 0;
}

如你所见,函数::SerReadWrite()被重载为三种版本。取决于最后一个参数,它将会调分别用全局函数::GetSerialize(),::Serialize()和::Unserialize()。

Example

#include <iostream>
#include "serialize.h"
using namespace std;
class AClass {
  public:
    AClass(int xin) : x(xin){};
    int x;
    IMPLEMENT_SERIALIZE(READWRITE(this->x);)
} int main() {
    CDataStream astream2;
    AClass aObj(200); // 一个 x 为 200 的 AClass 类型对象
    cout << "aObj=" << aObj.x >> endl;
    asream2 << aObj;

    AClass a2(1); // 另一个 x 为 1 的对象
    astream2 >> a2 cout << "a2=" << a2.x << endl;
    return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment