protocol buffer中repeated和map类型的动态解析
更新日期:
在之前的博客里简单介绍了protocol buffer的动态解析方法,对于不同的类型调用消息的Reflection中对应的方法进行读取,对于一个field如下处理:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15switch (field->cpp_type()) {
#define HANDLE_TYPE(UPPERCASE, FUNCASE)\
case google::protobuf::FieldDescriptor::CPPTYPE_##UPPERCASE :\
val = reflection->Get##FUNCASE(*message, field);\
break
HANDLE_TYPE( INT32, Int32);
HANDLE_TYPE( INT64, Int64);
HANDLE_TYPE(UINT32, UInt32);
HANDLE_TYPE(UINT64, UInt64);
HANDLE_TYPE(DOUBLE, Double);
HANDLE_TYPE( FLOAT, Float);
HANDLE_TYPE( BOOL, Bool);
HANDLE_TYPE( ENUM, EnumValue);
#undef HANDLE_TYPE
上面的宏定义摘抄于protocol buffer源代码。
可见对于每种类型protocol buffer中都有对应的解析函数,特别的对应string有reflection->GetString,对应Message有reflection->GetMessage,但对于repeated和map类型的成员就不能这么简单的处理了。
repeated
在protocol buffer中repeated的编码方式是与普通类型不同的(string,Message类型直接依次独立编码repeated内容,其他类型先编码tag,再编码repeated.size,最后依次编码repeated内容,具体编码方式在后面博客中仔细分析),所以对于repeated类型要用另外的解析函数来读取。
1 | int count = reflection->FieldSize(*message, field); |
map
在protocol buffer3.0版本中增加了map类型,和C++stl中的map作用类似,但是从编码方式上你会看出它完完全全的是个repeated类型,而且是个存储Message成员的repeated类型,直接看map在protocol buffer3.0中的定义方式就一目了然了:
1 | // Proto3 maps are represented on the wire as a message with |
可见在编码和解码中map完全是一种特别的repeated类型(map_entry来标识),只是在使用方式上有区别而已,所以要对其进行动态解析就直接调用对应于repeated的方法就可以了。
1 | int count = reflection->FieldSize(*message, field);//field即map字段对应的field |
protocol buffer中map的实现方式还是比较巧妙的,完全借用了repeated类型来实现,某种方面来讲也实现了和protocol buffer低版本的兼容,明白了它在protocol buffer内容的表现方式就很容易理解它了。