Varint

什么是Varint
Varint 是一种紧凑的表示数字的方法。它用一个或多个字节来表示一个数字,值越小的数字使用越少的字节数。这能减少用来表示数字的字节数。

比如对于 int32 类型的数字,一般需要 4 个 byte 来表示。但是采用 Varint,对于很小的 int32 类型的数字,则可以用 1 个 byte 来表示。当然凡事都有好的也有不好的一面,采用 Varint 表示法,大的数字则需要 5 个 byte 来表示。从统计的角度来说,一般不会所有的消息中的数字都是大数,因此大多数情况下,采用 Varint 后,可以用更少的字节数来表示数字信息。下面就详细介绍一下 Varint。

Varint 中的每个 byte 的最高位 bit 有特殊的含义,如果该位为 1,表示后续的 byte 也是该数字的一部分,如果该位为 0,则结束。其他的 7 个 bit 都用来表示数字。因此小于 128 的数字都可以用一个 byte 表示。大于 128 的数字,比如 300,会用两个字节来表示:1010 1100 0000 0010

下图演示了 Google Protocol Buffer 如何解析两个 bytes。注意到最终计算前将两个 byte 的位置相互交换过一次,这是因为 Google Protocol Buffer 字节序采用 little-endian 的方式。

Varint 编码

从描述上看,Varint与Utf-8编码有些类似,是变长编码。

Varint的实现分析
看懂上面的例子应该不难,下面来看看LevelDB中是如何实现的,位置是util\coding.cc

// 计算编码后的长度是几个字节
int VarintLength(uint64_t v) {
  int len = 1;
  while (v >= 128) {
    v >>= 7;
    len++;
  }
  return len;
}

// 将一个32位无符号int进行编码保存到dst指向的空间
char* EncodeVarint32(char* dst, uint32_t v) {
  // Operate on characters as unsigneds
  unsigned char* ptr = reinterpret_cast<unsigned char*>(dst);
  static const int B = 128;
  if (v < (1<<7)) {
    *(ptr++) = v; 
  } else if (v < (1<<14)) {
    *(ptr++) = v | B; 
    *(ptr++) = v>>7; 
  } else if (v < (1<<21)) {
    *(ptr++) = v | B;
    *(ptr++) = (v>>7) | B;
    *(ptr++) = v>>14;
  } else if (v < (1<<28)) {
    *(ptr++) = v | B;
    *(ptr++) = (v>>7) | B;
    *(ptr++) = (v>>14) | B;
    *(ptr++) = v>>21;
  } else {
    *(ptr++) = v | B;
    *(ptr++) = (v>>7) | B;
    *(ptr++) = (v>>14) | B;
    *(ptr++) = (v>>21) | B;
    *(ptr++) = v>>28;
  }
  return reinterpret_cast<char*>(ptr);
}

没看源码时自己写的代码是一个循环,看了源码才发现自己还是too young too simple, naive

分析这个分支发生了什么:

if (v < (1<<14)) {
    *(ptr++) = v | B; 
    *(ptr++) = v>>7; 
}
其中v是uint32_t, B是int 值为128, ptr是一个指向unsiged char类型的指针变量。 
if是判断v是否需要两个字节表示。如果是就进入该分支进行处理。 
首先要清楚,如果一个表达式中既有无符号数又有int时(有符号数), 那么int值将会转换为无符号数。(见C++ Primer 第五版 P34) 
那么对于v | B, B将转换成uint32_t, 那么 v | B 就等价于: 
v | 00000000 00000000 00000000 10000000 
结果记为m , m就是将v的第8位置1后的值。(因为肯定会有后续字节,所以第八位肯定是1.) 
然后计算*(ptr++) = v | B, 即 *(ptr++) = m。 
由于*ptr为unsigned char类型,而m为uint32_t, 这时会发生截断。*ptr即为m的最后8位。

原文链接:https://blog.csdn.net/huntinux/article/details/51690665

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/463329.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu 17.10安装Qt 5.10环境与Qt Creator 4.5开发工具(转自linux公社)

记录下在Ubuntu 17.10搭建Qt环境与安装Qt Creator开发工具的过程。机器装的Linux是Ubuntu 17.10&#xff0c;16.04与17.04的应该也相同。Qt 5.10和Qt 3D Studio发布 http://www.linuxidc.com/Linux/2017-12/149267.htm 1&#xff0c;Qt安装 1.1 下载Qt 这里提供Qt Creator的下…

服务器USB启动故障一例

前几日&#xff0c;本公司一台prop平台服务器&#xff08;hp 380G5服务器&#xff09;接上key&#xff08;usb口&#xff09;后&#xff0c;出现重启不能启动现象&#xff0c;进入服务器bios设置启动项为硬盘启动也不行&#xff0c;之后仔细查看服务器usb控制选项&#xff1a;可…

C#基础(201)--常量枚举

本文知识点&#xff1a; 1.掌握常量的定义和使用方法 2.理解枚举的作用和特点 3.掌握枚举的使用方法 1.1.常量的定义语法 const 数据类型 常量名称 值&#xff1b; 1.2.常见错误 1.3常量的使用时机 经常使用并且值不变的变量&#xff0c;可以定义为常量 2.1枚举的作用及其…

自定义EL函数解决JSTL标签不足之处——按字节长度截取字符串

题外话&#xff1a;做过大型网站前台的Web开发程序员最头疼的事情就是前台首页的布局&#xff0c;这其中最最头疼的就是标题字符的截取的问题&#xff0c;虽然有fn:substring&#xff0c;但表现率以及对中文的支持均不够完善&#xff0c;其实最终还是归结为客户要求太高了&…

进程之父子进程的关系

转载&#xff1a;https://blog.csdn.net/qq_28840229/article/details/79844763 fork之后&#xff1a; 父子相同处: 全局变量、.data、.text、栈、堆、环境变量、用户ID、宿主目录、进程工作目录、信号处理方式... 父子不同处: 1.进程ID 2.fork返回值 3.父进程ID 4.进…

C语言快速排序算法

void sort(int *a, int left, int right) {if(left > right)/*如果左边索引大于或者等于右边的索引就代表已经整理完成一个组了*/{return ;}int i left;int j right;int key a[left];while(i < j) /*控制在当组内寻找一遍*/{while(i &l…

unbuntu使用经典界面

为什么80%的码农都做不了架构师&#xff1f;>>> 昨天升级到UBUNTU 11.04, 发现新的Unity界面很不适应&#xff0c;于是将其恢复到旧式经典界面&#xff0c;具体操作模式方法如下&#xff1a; 在已经登录的状态下&#xff0c;选择 [注销]然后在重新登录的时候&#…

学习:深入浅出之正则表达式(转)

本文是Jan Goyvaerts为RegexBuddy写的教程的译文&#xff0c;版权归原作者所有&#xff0c;欢迎转载。但是为了尊重原作者和译者的劳动&#xff0c;请注明出处&#xff01;谢谢&#xff01; 1. 什么是正则表达式 基本说来&#xff0c;正则表达式是一种用来描述一定数量文本…

C语言判断计算机存储是大端还是小端

计算机的一个int型数据是用多个字节表示的&#xff0c;如果在内存中存放时标称该数据的地址中存放的是数据的最低字节&#xff0c;就叫小端机&#xff0c;反之把高字节存放在标称地址中的则称为大端机。所以可以定义一个int变量&#xff0c;将其地址强制为char *型地址&#xf…

服务器开发中网络数据分析与故障排查经验漫谈

转载大牛的文章&#xff1a; https://mp.weixin.qq.com/s/6ZmiKUz4ZQvwLXkzzBrFcg

每天干的啥?(2019.3)

【本年目标】 【本月目标】【本月总结】 【3月每日记录】 去洗照片24张9寸&#xff0c;研究手机root&#xff08;y66不支持啊&#xff09;&#xff0c;下午党学习照相、看完第4课blake《用户数据ugame》、研究轮滑gif、晚上钢琴首次调律。 去妈妈那吃饭&#xff0c;学钢琴、佰洲…

【Andorid X 项目笔记】禁用ListView的Fling功能(1)

前言新的项目正在紧张开发中&#xff0c;初步估计2个月时间开发完成第一版&#xff0c;我负责Android端开发&#xff0c;由于不便过早公布&#xff0c;本系列将命名为“X项目笔记”&#xff0c;并于项目结束后最终公布名称。本系列主要记录与分享"X项目"中遇到的问题…

C语言题目地图上有m个城市,序号依次为1,2,3....m,刚开始你在1,若每次只能从当前城市去往当前序号加1或者加3的城市,要到达m城市(m3),有多少种走法

地图上有m个城市&#xff0c;序号依次为1,2,3....m&#xff0c;刚开始你在1&#xff0c;若每次只能从当前城市去往当前序号加1或者加3的城市&#xff0c;要到达m城市&#xff08;m>3&#xff09;,有多少种走法 要想到达m&#xff0c;则前一个应该是m - 1或者m -3&#xff1b…

Java IO/NIO教程

Java IO教程 http://tutorials.jenkov.com/java-io/index.html Java NIO教程 英文版&#xff1a; http://tutorials.jenkov.com/java-nio/index.html 中文版: Java NIO概述Java NIO ChannelJava NIO BufferJava NIO Scatter / GatherJava NIO 通道之间的数据传输Java NIO Selec…

SQL Server 数据库管理常用的SQL和T-SQL语句

--按姓氏笔画排序:SELECT*FROM TableName ORDERBY CustomerName COLLATE Chinese_PRC_Stroke_ci_as--数据库加密:SELECT encrypt(原始密码)SELECT pwdencrypt(原始密码)SELECT pwdcompare(原始密码,加密后密码)1--相同&#xff1b;否则不相同 encrypt(原始密码)SELECT pwdencry…

什么是一致性Hash算法?

原文链接&#xff1a;https://blog.csdn.net/bntX2jSQfEHy7/article/details/7954936 最近有小伙伴跑过来问什么是Hash一致性算法&#xff0c;说面试的时候被问到了&#xff0c;因为不了解&#xff0c;所以就没有回答上&#xff0c;问我有没有相应的学习资料推荐&#xff0c;当…

ZEN CART 在LINUX系统下设置邮箱方法---用GMAIL设置,方法选择SMTPAUTH

电子邮件发送方式smtpauth 电子邮件换行LF 使用HTML格式发送电子邮件true 发送电子邮件true电子邮件存档false 电子邮件出错信息false 用于显示的店主邮件地址salemulberrydiscountstore.com发件人邮件地址salemulberrydiscountstore.com 电子邮件必须从现有域名发送No 管理员电…

c++入门基础知识

命名空间刚开始接触c&#xff0c;我们会发现与C语言相比不光头文件有所不同&#xff0c;还会发现using namespce std&#xff1b;这句话&#xff0c;其实这就是c的命名空间。 (1) 概念命名空间是为了防止名字冲突提供更加可控的机制。命名空间分割了全局命名空间&#xff0c;其…

读书笔记之《得未曾有》

作者 安妮宝贝&#xff0c;2014年笔名改为“庆山” 感想 第一次读庆山的作品&#xff0c;可以书名来总结的一下&#xff0c;得未曾有——获得了一种未曾有过得感受。 一、感受作者 高晓松老师的节目里说过一句话&#xff0c;写作需要长时间的观察人性、需要极强的观察能力。庆山…

数据库索引的实现原理

转载&#xff1a;https://blog.csdn.net/kennyrose/article/details/7532032 强烈建议参阅链接&#xff1a;http://www.linezing.com/blog/?p798#nav-1 说白了&#xff0c;索引问题就是一个查找问题。。。 数据库索引&#xff0c;是数据库管理系统中一个排序的数据结构&…