只用2000行代码实现google protocol buffer c++版的功能

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

     google protocol buffer (下面简称gpb)功能强大,应用广泛,但在实际应用中,gpb需要写.proto脚本文件,需要依赖.lib库,还需要为每个消息体生成一大堆难以阅读的C++代码。有时候想看一下消息体有哪些字段,需要找原始的.proto文件来查看,很不方便。于是我用了不到2000行代码实现了一个轻量级C++版gpb,命名为:LightPb。LightPb有以下特点:

   1、不需要.proto文件和.lib库,只需要包含一个头文件LightPb.h。

   2、兼容bpb大部份功能,序列化后生成的二进制文件与gpb一至。

   3、可扩展repeated [packed=true]功能,使得该选项可以应用于消息体和string。

   4、定义消息体的语法与gpb相似,简单易学。

   5、性能比gpb更优。

     

   下面是一个使用LightPb的例子:

   1、首先在一个testLight.h文件中定义一个结构体SubPbC:

struct SubPbC
{
 PB_BEGIN()
 REQUIRED(int, m_int32, 2);
 REQUIRED_S(int, m_sint32, 3);
 REQUIRED(std::string, m_str, 4);
 PB_END()
};

      该结构体包含三个字段,结构体字段的需要用REQUIRED或OPTIONAL以及REPEATED三个宏中之一来定义。含义与gpb中的required、optional、repeated是一样的。这些宏有三个参数,分别是字段类型、字段名、和标签。与之对应的proto消息体是:(本例子中不需要定义该消息体,只是用以说明SubPbC对应的proto结构体)

message SubPb
{
   required int32            m_int32 = 2;
   required sint32           m_sint32 = 3;
   required string           m_str = 4;
}

 

对C++程序员来说,上面的结构体定义和下面的结构体定义是一样的:

struct SubPbC
{ 
 int m_int32;
 int m_sint32;
 std::string m_str; 
 std::string SerializeAsString(); //序列化函数
 bool ParseFromArray(const void* pData, int size); //反序列化函数 
};

 

2 在.cpp文件使用该结构体 

#include "LightPb.h" //LightPb项目的头文件
#include "testLight.h" //应用层定义的消息体
void main()
{
 SubPbC obj;
 obj.m_int32 = 10; //像普通结构体一样赋值
 obj.m_sint32 = -10;
 obj.m_str = "ok LightPb";
 //序列化
 std::string str = obj.SerializeAsString();
 //反序列化
 SubPbC obj2;
 if (obj2.ParseFromArray(str.data(), str.length()) == false)
 {
  printf("test fail!\n");
 }
 return;
}

就这么简单!

一个和googe pb性能比较的例子:

http://www.oschina.net/code/snippet_2504104_51823

 

LightPb.h文件定义如下:

 
/***************************************************************************************************
转载请注明出处,作者联系方式:[email protected]
V 1.0  
Date:2015-10-28
*****************************************************************************************************/
#ifndef __BCL_LIGHT_PB_H__
#define __BCL_LIGHT_PB_H__
#include 
#include 
#include 
#include 
typedef int int32;
typedef unsigned int uint32;
typedef long long int64;
typedef unsigned long long uint64;
typedef std::string string;
typedef std::string bytes;
typedef int sint32;
typedef long long sint64;
typedef unsigned int fixed32;
typedef unsigned long long fixed64;
typedef  int sfixed32;
typedef  long long sfixed64;
typedef char int8;
typedef unsigned char uint8;
//#define USE_REPEATED_PACKED_EXTEND  //如果使用repeated packd=true扩展,请定义该宏
#ifndef _FIELD_DEF_
#define _FIELD_DEF_
template 
struct Int2Type
{
 enum { Value = size };
};
#define INT2TYPE(size) Int2Type()
#define ARRAY(type,size) std::array
#define FIELD_INDEX_BEGIN() enum {INDEX_BEGIN=__COUNTER__,};
#define FIELD_INDEX_END()   enum {INDEX_END=__COUNTER__,Size=INDEX_END-INDEX_BEGIN-1,};
#define AUTO_INDEX() (__COUNTER__-INDEX_BEGIN)
#define FIELD_BEGIN() FIELD_INDEX_BEGIN()
#define FIELD_END() FIELD_INDEX_END()
#define FIELD(type,name) FIELD_INDEX(AUTO_INDEX(),type,name)
#define FIELD_INDEX(index,type,name)  DEF_VALUE(type,name) GET_VALUE(index,type,name) GET_NAME(index,name)
#define DEF_VALUE(type,name) type name; 
#define GET_VALUE(index,type,name) type & getValue(Int2Type){return name;} const type & getValue(Int2Type) const {return name;}
#define GET_NAME(index,name) const char* getName(Int2Type) const { return #name;}
template
struct THaveLeghtField
{
 template
 static char __is_field_struct(...);
 template
 static int __is_field_struct(typename type::traits_type *);
 template
 static int __is_field_struct(Int2Type *);
 enum { Value = (sizeof(__is_field_struct(0)) == sizeof(int)) };
};
#endif
#define PB_INDEX(index,type,label,pbro,pbtype) std::array getLabelObject(Int2Type); Int2Type getIndex(Int2Type

转载于:https://my.oschina.net/u/2504104/blog/524370

你可能感兴趣的:(只用2000行代码实现google protocol buffer c++版的功能)