ProtoBuf之Varint编码

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

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值