【原創】 Boost序列化自己手寫實現簡易版

設計思路

 

在與多個系統進行網絡交互時,序列化是不可缺少的技術。編寫一個C++語言的序列化實現,是練習運用模板元編程的絕佳案例,理解C++模板是如何"面向編譯期編程"的(業內好像沒有這個說法)。序列化對象處理基礎數據類型和類類型,boost的序列化功能劃分得更細緻,基本支持了C++語言的序列化,但是在業務開發中,支持這兩種已經足夠用了。對於基礎數據類型的序列化,需要合理組織序列化的協議格式;對於類類型的序列化,類是由基礎數據類型組成的,最終轉換爲基礎數據類型的序列化。

代碼思路

 

序列化實現類class CTextSerialize,反序列化實現類class CTextDeserialize;這兩個類都通過業務類的模板函數serialize以傳參的方式分別實現序列化和反序列化。class CTextSerialize中的重載函數serialize分別實現基礎數據類型和類類型的序列化;class CTextDeserialize中的重載函數deserialize分別實現基礎數據類型和類類型的反序列化。這兩個類在處理類類型序列化/反序列化時,都調用了class CAccess的靜態函數serialize。對於容器vector和map這種特殊的類類型,需要單獨實現偏特化的class CAccess。整體代碼設計思路需要結合完整代碼實現細節進行理解。

完整代碼

 

代碼基於C++98進行編寫,採用gcc4.8.5編譯器編譯,測試運行在CentOS7.3環境。

在main函數中,代碼分爲四段:

第一段,採用輸入輸出流操作不同基礎數據類型的變量;

第二段,使用模板判斷變量類型是基礎數據類型還是類類型;

第三段,對基礎數據類型進行序列化和反序列化;

第四段,對類類型進行序列化和反序列化。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

#include <iostream>

#include <sstream>

#include <map>

#include <vector>

#include <stdint.h>

using namespace std;

 

template<typename T>

struct is_class_imp{ //採用boosttype_traits的方式判斷,判斷一個類型是否是一個類類型

typedef char class_type; //一個字節

typedef int32_t non_class_type; //四個字節

template<typename C> static class_type is_class_check(void(C::*)(void)); //類類型匹配到的模板函數

template<typename C> static non_class_type is_class_check(...); //基礎類型匹配到的模板函數

 

static const bool value = (sizeof(is_class_check<T>(0)) == sizeof(class_type)); //value的值在編譯期決定

};

template<>

struct is_class_imp<string>{ //模板特化,string可以作爲基礎類型處理,其實是類類型

static const bool value = false;

};

template<typename T>

struct is_class : is_class_imp<T>{}; //繼承

 

template<bool C_>

struct bool_plt{}; //用於編譯期條件判斷的模板,bool_plt<true>bool_plt<false>

 

template<typename C_, typename F1, typename F2> //C_編譯期的條件,依據條件判斷,動態定義類型F1F2

struct eval_if{};

template<typename F1, typename F2> //模板偏特化,typename C_

struct eval_if<bool_plt<true>, F1, F2>{ //C_編譯期條件爲bool_plt<true>時,定義類型F1

typedef F1 type;

};

template<typename F1, typename F2> //模板偏特化,typename C_

struct eval_if<bool_plt<false>, F1, F2>{ //C_編譯期條件爲bool_plt<false>時,定義類型F2

typedef F2 type;

};

 

template<typename Archive, typename T>

class CAccess //對類類型對象,應該序列化還是反序列化的控制函數

{

public:

static void serialize(Archive& ar, T& t){ //調用類類型對象的serialize函數,序列化還是反序列化由ar參數決定

t.serialize(ar);

}

};

template<typename Archive, typename T>

struct CFreeMarshall{ //序列化結構體類型

static void invoke(Archive& ar, const T& t){

CAccess<Archive, T>::marshall(ar, t);

}

};

template<typename Archive, typename T>

struct CFreeDemarshall{ //反序列化結構體類型

static void invoke(Archive& ar, T& t){

CAccess<Archive, T>::demarshall(ar, t);

}

};

template<typename Archive, typename T>

struct CFreeInvoke{ //序列化和反序列化統一調用模版函數,在編譯期決定調用其一

static void invoke(Archive& ar, T& t){

typedef typename eval_if<typename Archive::is_marshall, //假如ar對象是序列化對象

CFreeMarshall<Archive, T>, //定義序列化類型

CFreeDemarshall<Archive, T> >::type typex; //否則定義反序列化類型

typex::invoke(ar, t); //調用序列化或反序列化函數,在編譯期動態判斷決定

}

};

 

template<typename Archive, typename T>

class CAccess<Archive, vector<T> > //模板偏特化,實現vector容器的序列化和反序列化

{

public:

static void serialize(Archive& ar, vector<T>& t) //調用序列化或反序列化函數,在編譯期動態判斷決定

{

CFreeInvoke<Archive, vector<T> >::invoke(ar, t);

}

static void marshall(Archive& ar, const vector<T>& t) //序列化

{

int len = t.size();

ar << len << " ";

for (int i = 0; i < len; i++)

{

ar << t[i] << " ";

}

}

static void demarshall(Archive& ar, vector<T>& t) //反序列化

{

int len = 0;

ar >> len;

t.clear();

for (int i = 0; i < len; i++)

{

T tmp;

ar >> tmp;

t.push_back(tmp);

}

}

};

 

template<typename Archive, typename K, typename V>

class CAccess<Archive, map<K,V> > //模板偏特化,實現map容器的序列化和反序列化

{

public:

static void serialize(Archive& ar, map<K,V>& t) //調用序列化或反序列化函數,在編譯期動態判斷決定

{

CFreeInvoke<Archive, map<K,V> >::invoke(ar, t);

}

static void marshall(Archive& ar, const map<K,V>& t) //序列化

{

int len = t.size();

ar << len << " ";

typename map<K,V>::const_iterator iter;

for (iter = t.begin(); iter != t.end(); ++iter)

ar << iter->first << " " << iter->second << " ";

}

static void demarshall(Archive& ar, map<K,V>& t) //反序列化

{

int len = 0;

ar >> len;

t.clear();

for (int i = 0; i < len; i++)

{

K key;

V val;

ar >> key >> val;

t[key] = val;

}

}

};

 

class CTextSerialize //序列化和協議實現類

{

public:

typedef bool_plt<true> is_marshall; //該類定義爲序列化類

typedef bool_plt<false> is_demarshall;

CTextSerialize(ostream& o):os(o){}

 

template<typename T>

void serialize(const T& t, bool_plt<false>& b) //基礎類型序列化模板函數

{

os << t << " ";

}

template<typename T>

void serialize(const T& t, bool_plt<true>& b) //類類型序列化模板函數

{

CAccess<CTextSerialize, T>::serialize(*this, const_cast<T&>(t));

}

template<typename T>

CTextSerialize& operator<<(const T& t)

{

bool_plt<is_class<T>::value> type; //type在編譯期確定,T是否是類類型

serialize(t, type);

return *this;

}

 

template<typename T>

CTextSerialize& operator&(const T& t)

{

bool_plt<is_class<T>::value> type; //type在編譯期確定,T是否是類類型

serialize(t, type);

return *this;

}

private:

ostream& os;

};

 

class CTextDeserialize //反序列化和協議實現類

{

public:

typedef bool_plt<false> is_marshall;

typedef bool_plt<true> is_demarshall; //該類定義爲反序列化類

CTextDeserialize(istream& i):is(i){}

 

template<typename T>

void deserialize(T& t, bool_plt<false>& b) //基礎類型反序列化模板函數

{

is >> t;

}

template<typename T>

void deserialize(T& t, bool_plt<true>& b) //類類型反序列化模板函數

{

CAccess<CTextDeserialize, T>::serialize(*this, t);

}

template<typename T>

CTextDeserialize& operator>>(T& t)

{

bool_plt<is_class<T>::value> type; //type在編譯期確定,T是否是類類型

deserialize(t, type);

return *this;

}

 

template<typename T>

CTextDeserialize& operator&(T& t)

{

bool_plt<is_class<T>::value> type; //type在編譯期確定,T是否是類類型

deserialize(t, type);

return *this;

}

private:

istream& is;

};

 

enum EName{};

struct SData{};

 

class CData //支持序列化和反序列化的類實現

{

private: //待序列化的成員變量

uint32_t ver;

int i;

bool b;

long l;

double d;

string s;

vector<string> vecStr;

map<int, string> mapInfo;

 

public:

CData():ver(0),i(0),b(false),l(0),d(0){} //數據初始化

void init(uint32_t ver, int i, bool b, long l, double d, string s, string arr[], int len)

{

this->ver = ver;

this->i = i;

this->b = b;

this->l = l;

this->d = d;

this->s = s;

this->vecStr.assign(arr, arr + len);

for (int j = 0; j < len; j++)

mapInfo[j] = arr[j];

}

template<typename Archive> //模板多態,Archive可以實現多種序列化協議

Archive& serialize(Archive& ar) //序列化和反序列化都調用這個模板函數

{

ar & ver;

ar & i;

ar & b;

ar & l;

ar & d;

ar & s;

ar & vecStr;

ar & mapInfo;

 

return ar;

}

 

string tostr(void) //便於類對象打印輸出

{

stringstream ss;

ss << " ver " << ver

<< " int:" << i << " bool:" << (true==b ? "true" : "false")

<< " long:" << l << " double:" << d << " string:" << s;

int len = vecStr.size();

ss << " vector:" << len << " ";

for (int j = 0; j < len; j++) ss << vecStr[j] << " ";

ss << " map:" << len << " ";

for (int j = 0; j < len; j++) ss << j << " " << mapInfo[j] << " ";

 

return ss.str();

}

};

 

int main(void)

{

{//將數據存入流中,將數據從流中取出;空格做爲數據分隔符,簡單的數據存儲格式

stringstream ss;

 

int a = 1;

double b = 2.1;

string c = "abc";

ss << a << " " << b << " " << c;

int A = 0;

double B = 0;

string C;

ss >> A >> B >> C;

 

cout << ss.str() << endl;

cout << A << " " << B << " " << C << endl << endl;

}

 

{//使用模板方式,在編譯期判斷數據類型,是否是類類型

cout << is_class<int>::value << endl;//該代碼塊都是基礎數據類型

cout << is_class<double>::value << endl;

cout << is_class<EName>::value << endl;

cout << is_class<string>::value << endl;

 

cout << is_class<CData>::value << endl;//該代碼塊都是類類型

cout << is_class<SData>::value << endl;

cout << is_class<vector<int> >::value << endl << endl;

}

 

{//序列化和反序列化基礎數據類型

int a = 1;

double b = 2.1;

string c = "abc";

 

std::ostringstream os;

CTextSerialize oSer(os);

oSer << a << b << c;

cout << a << " " << b << " " << c << endl;

 

int A = 0;

double B = 0;

string C;

 

std::istringstream is(os.str());

CTextDeserialize iDeser(is);

iDeser >> A >> B >> C;

cout << A << " " << B << " " << C << endl << endl;

}

 

{//序列化和反序列化類類型

string arr[] = {"3a", "2b", "1c"};

int len = sizeof(arr)/sizeof(arr[0]);//C++內存佈局與C語言兼容

CData oData;

oData.init(0, 11, true, 222, 3.30, "string", arr, len);

 

std::ostringstream os;

CTextSerialize oSer(os);

oSer << oData;

cout << "oData:" << oData.tostr() << endl;

 

CData iData;

std::istringstream is(os.str());

CTextDeserialize iDeser(is);

iDeser >> iData;

cout << "iData:" << iData.tostr() << endl;

}

 

return 0;

}

注:代碼沒有達到產品級別的質量。

代碼編譯後,運行結果:

1 2.1 abc

1 2.1 abc

 

0

0

0

0

1

1

1

 

1 2.1 abc

1 2.1 abc

 

oData: ver 0 int:11 bool:true long:222 double:3.3 string:string vector:3 3a 2b 1c map:3 0 3a 1 2b 2 1c

iData: ver 0 int:11 bool:true long:222 double:3.3 string:string vector:3 3a 2b 1c map:3 0 3a 1 2b 2 1c

 

參考文獻

 

[1] Boost序列化官網,https://www.boost.org/doc/libs/1_68_0/libs/serialization/doc/index.html

[2] Boost 1.67.0源代碼,https://www.boost.org/users/history/version_1_67_0.html

[3] 維基百科,https://en.wikipedia.org/wiki/Serialization

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章