Varint编码
tag与FieldNumber、WireType转换:(field_number << 3) | wire_type
当tag在1-15,tag只需要1个字节表示,最高位第1个bit表示msb且为0,后7个bit:前4个bit表示FieldNumber,后3个bit表示WireType
当tag大于等于16,tag需要多于1个字节表示,低位第1个字节的第1个bit为1,表示还需要读取下一个字节,往后以此类推。
.proto的message的字段的值转化为tag的核心代码:
PROTOBUF_ALWAYS_INLINE static uint8* UnsafeVarint(T value, uint8* ptr) {
static_assert(std::is_unsigned<T>::value,
"Varint serialization must be unsigned");
if (value < 0x80) {
ptr[0] = static_cast<uint8>(value);
return ptr + 1;
}
ptr[0] = static_cast<uint8>(value | 0x80);
value >>= 7;
if (value < 0x80) {
ptr[1] = static_cast<uint8>(value);
return ptr + 2;
}
ptr++;
do {
*ptr = static_cast<uint8>(value | 0x80);
value >>= 7;
++ptr;
} while (PROTOBUF_PREDICT_FALSE(value >= 0x80));
*ptr++ = static_cast<uint8>(value);
return ptr;
}
以0x80判断是否读取下一组,每个7个bit为一组,最高位增加1个bit(若大于0x80,设为1(value如果大于0x80,表示之后的高位的bit还有数据);若小于0x80,设为0)与7个bit,组合成8个bit存入数组,字段的值右移7个字节,若大于0x80,循环判断,若小于0x80,退出循环,value读取完毕。
根据以上逻辑,低位字节先存入数组,所以tag在转化为值时,需要翻转顺序
具体计算过程:
message Test
int32 Value1 = 200;
}
Value1转化为tag:
1、以二进制表示:
FieldNumber:11001000(200),WireType:000(0)
2、(field_number << 3) | wire_type => 11001000000
3、7个bit一组:1100 1000000,大于0x80,添加1个bit并设为1:11000000(192)存为第1个字节,
右移7个bit:0000 0001100,小于0x80,添加1个bit并设为0:00001100(12)存为第2个字节。
所以,tag为192,12
tag转为Value1
1、以二进制表示:
192:11000000
12:00001100
2、翻转高低位字节、去掉每个字节的msb:
0001100 1000000,后3位为000,所以WireType = 0
3、右移3位(Value1转化为tag第2步是左移3位,所以tag转为Value1是右移3位):
00000011001000
所以FieldNumber = 200