代码自动生成工具(二)-miniproto的c++库实现

来源:互联网 发布:免费淘宝客软件 编辑:程序博客网 时间:2024/06/05 08:40

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


本项目暂命名miniproto1.0。

有限的兼容protobuf的语法规则 和 编码规则。包括protobuf2.0和3.0的编码规则。

实现proto结构的序列化、反序列化功能。

代码生成工具,需要boost库支持(主要用了spirit库做文本解析),本人用的是boost.1.64.0。

生成后的代码,仅需要miniproto自身提供的lib(对应c++)、dll(对应c#)、jar(对应java),不需要其他第三方库。

完整项目下载地址(vs工程编译请选择release/win32)

Github项目地址


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


前文介绍了miniproto,这里介绍其c++库的实现


1、Zigzag编码

一个正负数转换的算法,可以将负数映射成正数,并且使得转换后的数字利于压缩

0 --> 0

-1 --> 1

1 --> 2

-2 -->  3

2 --> 4

对应代码实现:

uint32 ProtoTool::Zigzag(int32 value){uint32 res = (value << 1) ^ (value >> 31);return res;}uint64 ProtoTool::Zigzag(int64 value){uint64 res = (value << 1) ^ (value >> 63);return res;}int32 ProtoTool::DeZigzag(uint32 value){int32 res = (value >> 1) ^ -((*(int32 *)(&value)) & 1);return res;}int64 ProtoTool::DeZigzag(uint64 value){int64 res = (value >> 1) ^ -((*(int64 *)(&value)) & 1);return res;}

2、Varint编码

对数字进行压缩的算法

一个int 或者 longlong,占用4/8个字节,但是里面实际存的值,往往并不是真的用满4/8字节,大部分情况下高位都是0。

那么对于这种高位上的无用的0,就可以想办法给他省略掉。

varint对数字,从低位向高位,每7位为1截,第8位存后续高位还有没有值,有则标1,没有则标0。

这样对于:

0 ~ 2^7 的数字,需要1字节存储

0 ~ 2^14 的数字,需要2字节存储

0 ~ 2^21 的数字,需要3字节存储

0 ~ 2^28 的数字,需要4字节存储

0 ~ 2^35 的数字,需要5字节存储

0 ~ 2^42 的数字,需要6字节存储

0 ~ 2^49 的数字,需要7字节存储

0 ~ 2^56 的数字,需要8字节存储

0 ~ 2^63 的数字,需要9字节存储

0 ~ 2^64 的数字,需要10字节存储

可以看出,当数字很大的时候,才会多浪费1-2个字节。而当数字比较小的时候,节省的字节还是比较可观的。

对应代码实现:

byte_size ProtoTool::NumberCode(uint32 value, byte *buf){byte_size bytes = 0;byte temp = 0;while (true){temp = (byte)(value & 0x7f);if ((value >>= 7) != 0){buf[bytes++] = temp | 0x80;}else{buf[bytes++] = temp;break;}};return bytes;}byte_size ProtoTool::NumberCode(uint64 value, byte *buf){byte_size bytes = 0;byte temp = 0;while (true){temp = (byte)(value & 0x7f);if ((value >>= 7) != 0){buf[bytes++] = temp | 0x80;}else{buf[bytes++] = temp;break;}};return bytes;}byte_size ProtoTool::NumberDecode(uint32& value, const byte *buf){byte_size bytes = 0;value = 0;while (true){byte temp = buf[bytes];value = value | ((((uint32)temp) & 0x7f) << (7 * bytes));if ((temp & 0x80) != 0){bytes++;}else{bytes++;break;}}return bytes;}byte_size ProtoTool::NumberDecode(uint64& value, const byte *buf){byte_size bytes = 0;value = 0;while (true){byte temp = buf[bytes];value = value | ((((uint64)temp) & 0x7f) << (7 * bytes));if ((temp & 0x80) != 0){bytes++;}else{bytes++;break;}}return bytes;}

3、ProtoTool

编解码工具类,该工具类针对不同数据类型,给出一系列的编解码功能实现。

下面给出代码,对照代码做出注释说明。具体实现就不贴了,可以去下载完整项目。

// proto字段编/解码工具类,所有编/解码接口均提供 byte* 和 stream& 两种重载class ProtoTool{public:// Zigzag 编/解码static uint32 Zigzag(int32 value);static uint64 Zigzag(int64 value);static int32 DeZigzag(uint32 value);static int64 DeZigzag(uint64 value);// Varint/fixed32/fixed64 编/解码static byte_size NumberByteSize(uint32 value);static byte_size NumberByteSize(uint64 value);static byte_size NumberByteSize(float value);static byte_size NumberByteSize(double value);static byte_size NumberCode(uint32 value, byte *buf);static byte_size NumberCode(uint64 value, byte *buf);static byte_size NumberCode(float value, byte *buf);static byte_size NumberCode(double value, byte *buf);static byte_size NumberDecode(uint32& value, const byte *buf);static byte_size NumberDecode(uint64& value, const byte *buf);static byte_size NumberDecode(float& value, const byte *buf);static byte_size NumberDecode(double& value, const byte *buf);static byte_size NumberCode(uint32 value, std::ostream& buf);static byte_size NumberCode(uint64 value, std::ostream& buf);static byte_size NumberCode(float value, std::ostream& buf);static byte_size NumberCode(double value, std::ostream& buf);static byte_size NumberDecode(uint32& value, std::istream& buf);static byte_size NumberDecode(uint64& value, std::istream& buf);static byte_size NumberDecode(float& value, std::istream& buf);static byte_size NumberDecode(double& value, std::istream& buf);// proto key编/解码,即对 (字段Tag << 3 + 字段WiteType) 做varint编/解码static byte_size KeyByteSize(unsigned int num, unsigned int type);static byte_size KeyCode(unsigned int num, unsigned int type, byte *buf);static byte_size KeyDecode(unsigned int& num, unsigned int& type, const byte *buf);static byte_size KeyCode(unsigned int num, unsigned int type, std::ostream& buf);static byte_size KeyDecode(unsigned int& num, unsigned int& type, std::istream& buf);// 未知字段解码// 如果出现未定义的tag字段时,对该字段的编解码// 如果出现不支持的WiteType,抛UnknownWireTypeExceptionstatic byte_size UnknownDecode(unsigned int type, const byte *buf);static byte_size UnknownDecode(unsigned int type, std::istream& buf);// 基本数据类型的成员字段编/解码// bool成员static byte_size BoolByteSize(bool value);static byte_size BoolCode(bool value, byte *buf);static byte_size BoolDecode(bool& value, const byte *buf);static byte_size BoolCode(bool value, std::ostream& buf);static byte_size BoolDecode(bool& value, std::istream& buf);// int32成员static byte_size Int32ByteSize(int32 value);static byte_size Int32Code(int32 value, byte *buf);static byte_size Int32Decode(int32& value, const byte *buf);static byte_size Int32Code(int32 value, std::ostream& buf);static byte_size Int32Decode(int32& value, std::istream& buf);// sint32成员static byte_size SInt32ByteSize(int32 value);static byte_size SInt32Code(int32 value, byte *buf);static byte_size SInt32Decode(int32& value, const byte *buf);static byte_size SInt32Code(int32 value, std::ostream& buf);static byte_size SInt32Decode(int32& value, std::istream& buf);// uint32成员static byte_size UInt32ByteSize(uint32 value);static byte_size UInt32Code(uint32 value, byte *buf);static byte_size UInt32Decode(uint32& value, const byte *buf);static byte_size UInt32Code(uint32 value, std::ostream& buf);static byte_size UInt32Decode(uint32& value, std::istream& buf);// int64成员static byte_size Int64ByteSize(int64 value);static byte_size Int64Code(int64 value, byte *buf);static byte_size Int64Decode(int64& value, const byte *buf);static byte_size Int64Code(int64 value, std::ostream& buf);static byte_size Int64Decode(int64& value, std::istream& buf);// sint64成员static byte_size SInt64ByteSize(int64 value);static byte_size SInt64Code(int64 value, byte *buf);static byte_size SInt64Decode(int64& value, const byte *buf);static byte_size SInt64Code(int64 value, std::ostream& buf);static byte_size SInt64Decode(int64& value, std::istream& buf);// uint64成员static byte_size UInt64ByteSize(uint64 value);static byte_size UInt64Code(uint64 value, byte *buf);static byte_size UInt64Decode(uint64& value, const byte *buf);static byte_size UInt64Code(uint64 value, std::ostream& buf);static byte_size UInt64Decode(uint64& value, std::istream& buf);// 自定义enum成员template <typename E> static byte_size EnumByteSize(E value);template <typename E> static byte_size EnumCode(E value, byte *buf);template <typename E> static byte_size EnumDecode(E& value, const byte *buf);template <typename E> static byte_size EnumCode(E value, std::ostream& buf);template <typename E> static byte_size EnumDecode(E& value, std::istream& buf);// float成员static byte_size FloatByteSize(float value);static byte_size FloatCode(float value, byte *buf);static byte_size FloatDecode(float& value, const byte *buf);static byte_size FloatCode(float value, std::ostream& buf);static byte_size FloatDecode(float& value, std::istream& buf);// double成员static byte_size DoubleByteSize(double value);static byte_size DoubleCode(double value, byte *buf);static byte_size DoubleDecode(double& value, const byte *buf);static byte_size DoubleCode(double value, std::ostream& buf);static byte_size DoubleDecode(double& value, std::istream& buf);// std::base_string成员template <template<typename> class A = std::allocator> static byte_size StringByteSize(const String<A>& value);template <template<typename> class A = std::allocator> static byte_size StringCode(const String<A>& value, byte *buf);template <template<typename> class A = std::allocator> static byte_size StringDecode(String<A>& value, const byte *buf);template <template<typename> class A = std::allocator> static byte_size StringCode(const String<A>& value, std::ostream& buf);template <template<typename> class A = std::allocator> static byte_size StringDecode(String<A>& value, std::istream& buf);// 自定义message成员template <typename M>static byte_size MessageByteSize(const M& value);template <typename M> static byte_size MessageCode(const M& value, byte *buf);template <typename M> static byte_size MessageDecode(M& value, const byte *buf);template <typename M> static byte_size MessageCode(const M& value, std::ostream& buf);template <typename M> static byte_size MessageDecode(M& value, std::istream& buf);// 容器类字段,对每个元素的编/解码// 由于int32/sint32(均对应int),int64/sint64(均对应long long)的数据类型是一致的// 但编/解码逻辑是不一致的,sint32/sint64需要Zigzag后再Varint// 因此,如果仅仅是这样的接口:byte_size EntryCode(const T& value, byte *buf)// 模板参数T,对于int32/sint32,int64/sint64,模板展开后是同样的代码// 因此需要额外参数类型对其进行区分,重载// 因此对每种数据类型,定义了其对应的重载参数类型type// 这个type没有什么实际逻辑功能,仅用于让编译器可以区分不同的函数重载// 使得不同的EntryCode/Decode去调用上面实现的具体的某种数据类型的XXXCode/Decodetemplate <class T> static byte_size EntryByteSize(const T& value, ProtoBool type);template <class T> static byte_size EntryByteSize(const T& value, ProtoInt32 type);template <class T> static byte_size EntryByteSize(const T& value, ProtoSInt32 type);template <class T> static byte_size EntryByteSize(const T& value, ProtoUInt32 type);template <class T> static byte_size EntryByteSize(const T& value, ProtoInt64 type);template <class T> static byte_size EntryByteSize(const T& value, ProtoSInt64 type);template <class T> static byte_size EntryByteSize(const T& value, ProtoUInt64 type);template <class T> static byte_size EntryByteSize(const T& value, ProtoEnum type);template <class T> static byte_size EntryByteSize(const T& value, ProtoFloat type);template <class T> static byte_size EntryByteSize(const T& value, ProtoDouble type);template <class T> static byte_size EntryByteSize(const T& value, ProtoString type);template <class T> static byte_size EntryByteSize(const T& value, ProtoMessage type);template <class T> static byte_size EntryCode(const T& value, byte *buf, ProtoBool type);template <class T> static byte_size EntryCode(const T& value, byte *buf, ProtoInt32 type);template <class T> static byte_size EntryCode(const T& value, byte *buf, ProtoSInt32 type);template <class T> static byte_size EntryCode(const T& value, byte *buf, ProtoUInt32 type);template <class T> static byte_size EntryCode(const T& value, byte *buf, ProtoInt64 type);template <class T> static byte_size EntryCode(const T& value, byte *buf, ProtoSInt64 type);template <class T> static byte_size EntryCode(const T& value, byte *buf, ProtoUInt64 type);template <class T> static byte_size EntryCode(const T& value, byte *buf, ProtoEnum type);template <class T> static byte_size EntryCode(const T& value, byte *buf, ProtoFloat type);template <class T> static byte_size EntryCode(const T& value, byte *buf, ProtoDouble type);template <class T> static byte_size EntryCode(const T& value, byte *buf, ProtoString type);template <class T> static byte_size EntryCode(const T& value, byte *buf, ProtoMessage type);template <class T> static byte_size EntryDecode(T& value, const byte *buf, ProtoBool type);template <class T> static byte_size EntryDecode(T& value, const byte *buf, ProtoInt32 type);template <class T> static byte_size EntryDecode(T& value, const byte *buf, ProtoSInt32 type);template <class T> static byte_size EntryDecode(T& value, const byte *buf, ProtoUInt32 type);template <class T> static byte_size EntryDecode(T& value, const byte *buf, ProtoInt64 type);template <class T> static byte_size EntryDecode(T& value, const byte *buf, ProtoSInt64 type);template <class T> static byte_size EntryDecode(T& value, const byte *buf, ProtoUInt64 type);template <class T> static byte_size EntryDecode(T& value, const byte *buf, ProtoEnum type);template <class T> static byte_size EntryDecode(T& value, const byte *buf, ProtoFloat type);template <class T> static byte_size EntryDecode(T& value, const byte *buf, ProtoDouble type);template <class T> static byte_size EntryDecode(T& value, const byte *buf, ProtoString type);template <class T> static byte_size EntryDecode(T& value, const byte *buf, ProtoMessage type);template <class T> static byte_size EntryCode(const T& value, std::ostream& buf, ProtoBool type);template <class T> static byte_size EntryCode(const T& value, std::ostream& buf, ProtoInt32 type);template <class T> static byte_size EntryCode(const T& value, std::ostream& buf, ProtoSInt32 type);template <class T> static byte_size EntryCode(const T& value, std::ostream& buf, ProtoUInt32 type);template <class T> static byte_size EntryCode(const T& value, std::ostream& buf, ProtoInt64 type);template <class T> static byte_size EntryCode(const T& value, std::ostream& buf, ProtoSInt64 type);template <class T> static byte_size EntryCode(const T& value, std::ostream& buf, ProtoUInt64 type);template <class T> static byte_size EntryCode(const T& value, std::ostream& buf, ProtoEnum type);template <class T> static byte_size EntryCode(const T& value, std::ostream& buf, ProtoFloat type);template <class T> static byte_size EntryCode(const T& value, std::ostream& buf, ProtoDouble type);template <class T> static byte_size EntryCode(const T& value, std::ostream& buf, ProtoString type);template <class T> static byte_size EntryCode(const T& value, std::ostream& buf, ProtoMessage type);template <class T> static byte_size EntryDecode(T& value, std::istream& buf, ProtoBool type);template <class T> static byte_size EntryDecode(T& value, std::istream& buf, ProtoInt32 type);template <class T> static byte_size EntryDecode(T& value, std::istream& buf, ProtoSInt32 type);template <class T> static byte_size EntryDecode(T& value, std::istream& buf, ProtoUInt32 type);template <class T> static byte_size EntryDecode(T& value, std::istream& buf, ProtoInt64 type);template <class T> static byte_size EntryDecode(T& value, std::istream& buf, ProtoSInt64 type);template <class T> static byte_size EntryDecode(T& value, std::istream& buf, ProtoUInt64 type);template <class T> static byte_size EntryDecode(T& value, std::istream& buf, ProtoEnum type);template <class T> static byte_size EntryDecode(T& value, std::istream& buf, ProtoFloat type);template <class T> static byte_size EntryDecode(T& value, std::istream& buf, ProtoDouble type);template <class T> static byte_size EntryDecode(T& value, std::istream& buf, ProtoString type);template <class T> static byte_size EntryDecode(T& value, std::istream& buf, ProtoMessage type);// std::vector元素的编解码// 内部调用EntryCode/Decodetemplate <class T, class P> static byte_size ArrayEntryByteSize(const T& value, P type);template <class T, class P> static byte_size ArrayEntryCode(const T& value, byte *buf, P type);template <class T, class P> static byte_size ArrayEntryDecode(T& value, const byte *buf, P type);template <class T, class P> static byte_size ArrayEntryCode(const T& value, std::ostream& buf, P type);template <class T, class P> static byte_size ArrayEntryDecode(T& value, std::istream& buf, P type);// std::vector编解码// 调用ArrayEntryCode/Decodetemplate <class T, template<typename> class A, class P> static byte_size ArrayByteSizeWithoutLength(const Array<T, A>& values, P type);template <class T, template<typename> class A, class P> static byte_size ArrayByteSize(const Array<T, A>& values, P type);template <class T, template<typename> class A, class P> static byte_size ArrayCode(const Array<T, A>& values, byte *buf, P type);template <class T, template<typename> class A, class P> static byte_size ArrayDecode(Array<T, A>& values, const byte *buf, P type);template <class T, template<typename> class A, class P> static byte_size ArrayCode(const Array<T, A>& values, std::ostream& buf, P type);template <class T, template<typename> class A, class P> static byte_size ArrayDecode(Array<T, A>& values, std::istream& buf, P type);// std::set元素的编解码// 调用EntryCode/Decodetemplate <class T, class P> static byte_size SetEntryByteSize(const T& value, P type);template <class T, class P> static byte_size SetEntryCode(const T& value, byte *buf, P type);template <class T, class P> static byte_size SetEntryDecode(T& value, const byte *buf, P type);template <class T, class P> static byte_size SetEntryCode(const T& value, std::ostream& buf, P type);template <class T, class P> static byte_size SetEntryDecode(T& value, std::istream& buf, P type);// std::set编解码// 调用SetEntryCode/Decodetemplate <class T, template<typename> class A, class P> static byte_size SetByteSizeWithoutLength(const Set<T, A>& values, P type);template <class T, template<typename> class A, class P> static byte_size SetByteSize(const Set<T, A>& values, P type);template <class T, template<typename> class A, class P> static byte_size SetCode(const Set<T, A>& values, byte *buf, P type);template <class T, template<typename> class A, class P> static byte_size SetDecode(Set<T, A>& values, const byte *buf, P type);template <class T, template<typename> class A, class P> static byte_size SetCode(const Set<T, A>& values, std::ostream& buf, P type);template <class T, template<typename> class A, class P> static byte_size SetDecode(Set<T, A>& values, std::istream& buf, P type);// std::map键值对的编解码// 调用EntryCode/Decodetemplate <class K, class V, class KP, class VP> static byte_size MapEntryByteSizeWithoutLength(const K& key, const V& value, KP keyType, VP valueType);template <class K, class V, class KP, class VP> static byte_size MapEntryByteSize(const K& key, const V& value, KP keyType, VP valueType);template <class K, class V, class KP, class VP> static byte_size MapEntryCode(const K& key, const V& value, byte *buf, KP keyType, VP valueType);template <class K, class V, class KP, class VP> static byte_size MapEntryDecode(K& key, V& value, const byte *buf, KP keyType, VP valueType);template <class K, class V, class KP, class VP> static byte_size MapEntryCode(const K& key, const V& value, std::ostream& buf, KP keyType, VP valueType);template <class K, class V, class KP, class VP> static byte_size MapEntryDecode(K& key, V& value, std::istream& buf, KP keyType, VP valueType);// std::map编解码// 调用MapEntryCode/Decodetemplate <class K, class V, template<typename> class A, class KP, class VP> static byte_size MapByteSizeWithoutLength(const Map<K, V, A>& values, KP keyType, VP valueType);template <class K, class V, template<typename> class A, class KP, class VP> static byte_size MapByteSize(const Map<K, V, A>& values, KP keyType, VP valueType);template <class K, class V, template<typename> class A, class KP, class VP> static byte_size MapCode(const Map<K, V, A>& values, byte *buf, KP keyType, VP valueType);template <class K, class V, template<typename> class A, class KP, class VP> static byte_size MapDecode(Map<K, V, A>& values, const byte *buf, KP keyType, VP valueType);template <class K, class V, template<typename> class A, class KP, class VP> static byte_size MapCode(const Map<K, V, A>& values, std::ostream& buf, KP keyType, VP valueType);template <class K, class V, template<typename> class A, class KP, class VP> static byte_size MapDecode(Map<K, V, A>& values, std::istream& buf, KP keyType, VP valueType);};

4、ProtoBase

所有自定义message的基类,规范message接口,实现多态

提供序列化/反序列化 到 内存/流 的接口, 提供clear/release接口

对应代码:

// 所有自定义message的基类class ProtoBase{public:ProtoBase();virtual ~ProtoBase();public:virtual byte_size ByteSize() const = 0;virtual byte_size Code(byte *buf, byte_size size) const = 0;virtual byte_size Decode(const byte *buf, byte_size size) = 0;virtual byte_size Code(std::ostream& buf, byte_size size) const = 0;virtual byte_size Decode(std::istream& buf, byte_size size) = 0;public:virtual void Clear() = 0;virtual void Release() = 0;public:bool SerializeToArray(byte *buf, byte_size size) const;bool ParseFromArray(const byte *buf, byte_size size);bool SerializeToStream(std::ostream& buf, byte_size size) const;bool ParseFromStream(std::istream& buf, byte_size size);};

5、ProtoBitMap

采用模板实现的一个位图类,用于message中标记字段是否设置了值。

位图长度作为模板参数,没有使用stl的bitset,因为我只需要很简单的标记功能就可以。

对应代码:

template <uint32 N>class ProtoBitMap{public:ProtoBitMap();ProtoBitMap(const ProtoBitMap<N>& other);~ProtoBitMap();ProtoBitMap<N>& operator=(const ProtoBitMap<N>& other);public:void SetBit(uint32 index);void ClearBit(uint32 index);bool HasBit(uint32 index) const;public:void Clear();private:byte m_Bits[(N != 0) ? ((N - 1) / 8 + 1) : 1];};


阅读全文
0 0
原创粉丝点击