【原创】自己手写实现Boost序列化简易版

2018-11-26 07:53:22来源:博客园 阅读 ()

新老客户大回馈,云服务器低至5折

设计思路

 

在与多个系统进行网络交互时,序列化是不可缺少的技术。编写一个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

 

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:Ceres配置(vs2013+Win10)

下一篇:逻辑运算符号