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 记住两点就行了:

  1. Slice 不管理内存,它只操作用户提供的字符串,用户需要自己管理该字符串的内存
  2. Slice 不改变所操作字符串的内容

LevelDB(v1.3) 源码阅读之 Slice的更多相关文章

  1. LevelDB(v1.3) 源码阅读之 Arena(内存管理器)

    LevelDB(v1.3) 源码阅读系列使用 LevelDB v1.3 版本的代码,可以通过如下方式下载并切换到 v1.3 版本的代码: $ git clone https://github.com/ ...

  2. kubernetes源码阅读及编译

    kubernetes源码阅读 工欲善其事,必先利其器.在阅读kubernetes源码时,我也先后使用过多个IDE,最终还是停留在IDEA上. 我惯用的是pycharm(IDEA的python IDE版 ...

  3. 【 js 基础 】【 源码学习 】backbone 源码阅读(二)

    最近看完了 backbone.js 的源码,这里对于源码的细节就不再赘述了,大家可以 star 我的源码阅读项目(source-code-study)进行参考交流,有详细的源码注释,以及知识总结,同时 ...

  4. koa源码阅读[2]-koa-router

    koa源码阅读[2]-koa-router 第三篇,有关koa生态中比较重要的一个中间件:koa-router 第一篇:koa源码阅读-0第二篇:koa源码阅读-1-koa与koa-compose k ...

  5. JDK源码阅读(一):Object源码分析

    最近经过某大佬的建议准备阅读一下JDK的源码来提升一下自己 所以开始写JDK源码分析的文章 阅读JDK版本为1.8 目录 Object结构图 构造器 equals 方法 getClass 方法 has ...

  6. 如何进行高效的源码阅读:以Spring Cache扩展为例带你搞清楚

    摘要 日常开发中,需要用到各种各样的框架来实现API.系统的构建.作为程序员,除了会使用框架还必须要了解框架工作的原理.这样可以便于我们排查问题,和自定义的扩展.那么如何去学习框架呢.通常我们通过阅读 ...

  7. Sping学习笔记(一)----Spring源码阅读环境的搭建

    idea搭建spring源码阅读环境 安装gradle Github下载Spring源码 新建学习spring源码的项目 idea搭建spring源码阅读环境 安装gradle 在官网中下载gradl ...

  8. Kubernetes 学习(九)Kubernetes 源码阅读之正式篇------核心组件之 Scheduler

    0. 前言 继续上一篇博客阅读 Kubernetes 源码,参照<k8s 源码阅读>首先学习 Kubernetes 的一些核心组件,首先是 kube-scheduler 本文严重参考原文: ...

  9. go 中 select 源码阅读

    深入了解下 go 中的 select 前言 1.栗子一 2.栗子二 3.栗子三 看下源码实现 1.不存在 case 2.select 中仅存在一个 case 3.select 中存在两个 case,其 ...

随机推荐

  1. SharePoint 2013 Service 状态无法启动,显示“启动中(Starting)”

    Problem 在SharePoint 2013 Central Administration中启动 SharePoint Service(也称为:Service Machine Instance)时 ...

  2. 免费好用的web应用托管平台-续

    上一篇博客给大家推荐了目前处于免费阶段的PAAS平台,可以托管各种应用,大家反响很不错,说明大家还是很需要和认可这个免费托管各种web应用的京东云擎平台.但是很多用户还是很担心未来可能还是会收费,对于 ...

  3. 简单理解ECMAScript2015中的Promise

    ECMAScript6中新增了Promise对象, 所谓Promise对象,即代表着一个还未完成,但将来某时会完成的操作(通常是异步操作).使用Promise对象,我们就可以避免陷入函数层层嵌套的‘回 ...

  4. C语言实现二叉树-04版

    二叉树,通常应当是研究其他一些复杂的数据结构的基础.因此,通常我们应该精通它,而不是了解:当然,可能并不是每个人都认同这种观点,甚至有些人认为理解数据结构就行了!根本没有必要去研究如何实现,因为大多数 ...

  5. EndPoint详解

    EndPoint详解 EndPoint主要用于暴露一些SpringMvc内部运行的信息,通常是通过SpringMvc的请求地址获取相关信息.如/health获取健康检查信息. 简单单元测试 @Test ...

  6. C++Builder RAD Studio XE, UTF-8 String 转换为 char * 字符串的最简单方式, 常用于sqlite3开发

    前段时间突然使用sqlite3开发,中间需要用中文,XE的缺省char*直接使用中文,在sqlite *.db3的数据库表格中显示是乱码,用数据库管理器来浏览等管理时非常不便. 于是决定还是使用utf ...

  7. 高可用性、负载均衡的mysql集群解决方案

    高可用性.负载均衡的mysql集群解决方案 一.mysql的市场占有率 二.mysql为什么受到如此的欢迎 三.mysql数据库系统的优缺点 四.网络服务器的需求 五.什么是mysql的集群 六.什么 ...

  8. Jquery EasyUI封装简化操作

    //confirm function Confirm(msg, control) { $.messager.confirm('确认', msg, function (r) { if (r) { eva ...

  9. Socket原理与编程基础(转)

    一.Socket简介 Socket是进程通讯的一种方式,即调用这个网络库的一些API函数实现分布在不同主机的相关进程之间的数据交换. 几个定义: (1)IP地址:即依照TCP/IP协议分配给本地主机的 ...

  10. IPv6正则表达式

    斯蒂芬·瑞恩写了一个非常有用的正则表达式,可用于匹配任何一个合法的IPv6地址.以下为正则表达式的代码: ^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|: ...