1. 程式人生 > >【原創】自己手寫實現Boost序列化簡易版

【原創】自己手寫實現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;

}

 

<