LevelDB(v1.3) 源码阅读之 Slice
LevelDB(v1.3) 源码阅读系列使用 LevelDB v1.3 版本的代码,可以通过如下方式下载并切换到 v1.3 版本的代码:
$ git clone https://github.com/google/leveldb.git
$ cd leveldb
$ git checkout -b v1.3 v1.3
本文涉及的代码文件为:
include/slice.h
1. Slice 简介
LevelDB Slice 对经常使用的字符串进行了简单的封装,它自己不管理内存,仅仅提供对已有字符串的简单操作:这就是不使用 std::string 的原因:避免不必要的内存拷贝。因此,Slice 要求用户:
The user of a Slice must ensure that the slice is not used after the corresponding external storage has been deallocated.
我们需要时刻牢记:Slice 不负责管理内存,它只操作已有的字符串,这些字符串的内存由用户自己管理,还有一点,Slice 不能修改所操作的字符串
本文是 LevelDB(v1.3) 源码阅读系列第一篇文章,并且 Slice 也比较简单,所以这篇文章我会写的尽量详细,以后的文章我会更加注重设计,代码我不会像这篇文章一样贴的那么多
2. Slice 对外提供的接口
2.1. 构造函数
Slice() : data_(""), size_(0) { }
Slice(const char* d, size_t n) : data_(d), size_(n) { }
Slice(const std::string& s) : data_(s.data()), size_(s.size()) { }
Slice(const char* s) : data_(s), size_(strlen(s)) { }
第一个是默认构造函数,它会初始化一个空的 slice 出来,这个 slice 的长度为 0
第二个构造函数要求提供一个 char* 和 size_t 的参数分别来初始化 slice 的两个成员变量
第三个构造函数的参数是一个 string 类型的字符串
第四个构造函数的参数是一个 C 语言类型的字符串,该字符串以 '\0' 结尾,并且用 strlen(s) 来初始化 slice 的长度
通过构造函数我们很清晰的看到:Slice 不对它所操作的字符串进行拷贝复制,仅安排一个指针指向该字符串,并用一个整型变量记录该字符串的长度。事实上,Slice 仅仅只有他们两个成员变量:
const char* data_;
size_t size_;
注意到 data_ 的底层 const 修饰: Slice 不能修改所操作的字符串。
还需要注意的是,Slice 将拷贝构造函数和拷贝赋值函数声明为私有的,也就直接造成了 Slice 对象之间不可以直接的拷贝赋值。实际上也没有这样的必要和使用场景,Slice 仅仅是一个对字符串操作的函数集合,用户根本没必要拷贝两个工具集合。
2.2. 运算符重载
Slice 重载了三个运算符:[]、== 和 !=,[] 是 Slice 的成员函数,== 和 != 是对标准函数的重载,他们的代码如下:
char operator[](size_t n) const {
assert(n < size());
return data_[n];
}
inline bool operator==(const Slice& x, const Slice& y) {
return ((x.size() == y.size()) && (memcmp(x.data(), y.data(), x.size()) == 0));
}
inline bool operator!=(const Slice& x, const Slice& y) {
return !(x == y);
}
因为 Slice 不能修改其操作的字符串,[] 的重载函数返回的是该位置字符的一个拷贝而不是引用,不能通过 slice[i] = 'a' 的方式来改变 slice 第 i 个字节的内容
对于 == 和 !=:两个 Slice 相等指的是是他们的长度相等,并且所有的字节也相等(一个代码 tip:if 短路,先判断两个字符串的长度,再判断内容)
2.3. 常规函数
const char* data() const { return data_; }
size_t size() const { return size_; }
bool empty() const { return size_ == 0; }
void clear() { data_ = ""; size_ = 0; }
std::string ToString() const { return std::string(data_, size_); }
void remove_prefix(size_t n) {
assert(n <= size());
data_ += n;
size_ -= n;
}
inline int Slice::compare(const Slice& b) const {
const size_t min_len = (size_ < b.size_) ? size_ : b.size_;
int r = memcmp(data_, b.data_, min_len);
if (r == 0) {
if (size_ < b.size_) r = -1;
else if (size_ > b.size_) r = +1;
}
return r;
}
bool starts_with(const Slice& x) const {
return ((size_ >= x.size_) && (memcmp(data_, x.data_, x.size_) == 0));
}
这几个函数都比较简单:
- data() 和 size() 类似于 string 的 data() 和 size(),直接返回成员变量
- empty() 用来判断 Slice 中是否有字符串,这是通过判断 size 是否为 0 来实现的
- clear() 直接让当前这个 Slice 指向一个空字符串,并设置 size 为 0,再次印证:Slice 不负责内存的管理
- ToString() 就直接调用 string 的构造函数生成一个 string 对象,并把这个对象拷贝给调用者
- starts_with(),两个 Slice a 和 b,a.start_with(b) 判断 b 是否是 a 的一个前缀
- compare(),比较两个 Slice a 和 b 的大小,a.compare(b) 判断的是 a 是否小于 b,采用字典序比较大小
3. 总结
关于 Slice 记住两点就行了:
- Slice 不管理内存,它只操作用户提供的字符串,用户需要自己管理该字符串的内存
- Slice 不改变所操作字符串的内容
LevelDB(v1.3) 源码阅读之 Slice的更多相关文章
- LevelDB(v1.3) 源码阅读之 Arena(内存管理器)
LevelDB(v1.3) 源码阅读系列使用 LevelDB v1.3 版本的代码,可以通过如下方式下载并切换到 v1.3 版本的代码: $ git clone https://github.com/ ...
- kubernetes源码阅读及编译
kubernetes源码阅读 工欲善其事,必先利其器.在阅读kubernetes源码时,我也先后使用过多个IDE,最终还是停留在IDEA上. 我惯用的是pycharm(IDEA的python IDE版 ...
- 【 js 基础 】【 源码学习 】backbone 源码阅读(二)
最近看完了 backbone.js 的源码,这里对于源码的细节就不再赘述了,大家可以 star 我的源码阅读项目(source-code-study)进行参考交流,有详细的源码注释,以及知识总结,同时 ...
- koa源码阅读[2]-koa-router
koa源码阅读[2]-koa-router 第三篇,有关koa生态中比较重要的一个中间件:koa-router 第一篇:koa源码阅读-0第二篇:koa源码阅读-1-koa与koa-compose k ...
- JDK源码阅读(一):Object源码分析
最近经过某大佬的建议准备阅读一下JDK的源码来提升一下自己 所以开始写JDK源码分析的文章 阅读JDK版本为1.8 目录 Object结构图 构造器 equals 方法 getClass 方法 has ...
- 如何进行高效的源码阅读:以Spring Cache扩展为例带你搞清楚
摘要 日常开发中,需要用到各种各样的框架来实现API.系统的构建.作为程序员,除了会使用框架还必须要了解框架工作的原理.这样可以便于我们排查问题,和自定义的扩展.那么如何去学习框架呢.通常我们通过阅读 ...
- Sping学习笔记(一)----Spring源码阅读环境的搭建
idea搭建spring源码阅读环境 安装gradle Github下载Spring源码 新建学习spring源码的项目 idea搭建spring源码阅读环境 安装gradle 在官网中下载gradl ...
- Kubernetes 学习(九)Kubernetes 源码阅读之正式篇------核心组件之 Scheduler
0. 前言 继续上一篇博客阅读 Kubernetes 源码,参照<k8s 源码阅读>首先学习 Kubernetes 的一些核心组件,首先是 kube-scheduler 本文严重参考原文: ...
- go 中 select 源码阅读
深入了解下 go 中的 select 前言 1.栗子一 2.栗子二 3.栗子三 看下源码实现 1.不存在 case 2.select 中仅存在一个 case 3.select 中存在两个 case,其 ...
随机推荐
- Nhibernate基础使用教程以及简易封装
1.Nhibernate简介 NHibernate是一个面向.NET环境的对象/关系数据库映射工具.对象/关系数据库映射(object/relational mapping,ORM)这个术语表示一种技 ...
- Nodejs学习笔记(九)--- 与Redis的交互(mranney/node_redis)入门
目录 简介和安装 redis简介 redis安装 redis运行 node_redis安装 连接到redis服务器redis.createClient() 认证 client.auth(passwor ...
- [jQuery学习系列二 ]2-JQuery学习二-数组操作
前言 上一篇内容 已经对于Jquery 有了一些认识, 包括Jquery的选择器和DOM对象, 那么这一篇继续来看下Jquery中很实用的Jquery对于数组的操作. Jquery中对数组的操作大致有 ...
- duilib进阶教程 -- 改进窗口拖动 (12)
现在大家应该都知道caption="0,0,0,32",是指示标题栏区了吧,如果想要整个窗口都能拖动呢? 那直接把高度改成和窗口一样不就得了~O(∩_∩)O~ 嗯,这样是可以,比如 ...
- 关于eclispe保存代码自动格式化的设置
最近在项目开发,上级要求所有开发人员,代码必须格式和(Ctrl+Shift+F),但是还是会偶尔忘记格式化,今天看了有一种保存之后eclipse可以自动格式代码的设置 1.请大家在eclipse设置下 ...
- windows必备,命令行工具cmder
下载cmder并安装! 64位可下,亲测: http://www.wmzhe.com/soft-31133.html 创建文件夹并进入文件夹命令: mkdir web-server && ...
- HTML、XHTML XML和DHTML的区别
XML与HTML的设计区别是:XML是用来存储数据的,重在数据本身.而HTML是用来定义数据的,重在数据的显示模式 XHTML(The Extensible HyperText Markup Lang ...
- ffmpeg mp3 to m3u8
ffmpeg -i Sunshine.mp3 -c:a libmp3lame -b:a 128k -map 0:0 -f segment -segment_time 10 -segment_list ...
- Hello Kraken.js!
前言 kraken.js 由paypal 公司开源的一个用于快速开发基于Express.js框架应用的快速开发工具, 因为kraken 并没有在Express.js基础上更改多少东西,只是在原来的 ...
- Putty & Ctrl+s 的魔咒
Long long ago“ 某些旧的”哑终端“会在发送过来的数据太多,显示速度跟不上时发送一个Ctrl+s让对方等一下,然后再准备好继续显示时发送一个Ctrl+q.Putty“兼容”了这个特性.也有 ...