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. [游戏模版15] Win32 飞机射击

    >_<:Only give you the code,try to understand it! >_<:picture resource #include <windo ...

  2. Backbone Collection——数据模型集合

    如果将一个Model对象比喻成数据库中的一条记录,那么Collection就是一张数据表.它表示为一个模型集合类,用于存储和管理一系列相同类型的模型对象. 1.创建集合集合用于组织和管理多个模型,但它 ...

  3. Qt之Dialog\widget\ mainwindow的区别和布局管理器 & 分裂器的区别

    1.Dialog\widget\ mainwindow的区别 注意mainwindow和widget的区别,mainwindow都工具栏和菜单栏 Dialog and mainwinodws 都是继承 ...

  4. paip.字符串操作uapi java php python总结..

    paip.字符串操作uapi java php python总结.. java and php 相互转换.. import strUtil>>>  requiry(strUtil.p ...

  5. HTML5骨骼动画Demo | 使用min2d、createjs、pixi播放spine动画

    Spine做骨骼动画是比较流行的,使用起来可能相对复杂,但功能毕竟强大,所以市场占有率较大. 在unity.cocos2d.starling中使用spine已经很成熟了,而HTML5这一块可能刚刚起步 ...

  6. Memcached常规应用与分布式部署方案

    1.Memcached常规应用 $mc = new Memcache(); $mc->conncet('127.0.0.1', 11211); $sql = sprintf("SELE ...

  7. svchost占用内存达1-2G的问题

    win7 64位,前一段时间老是如此,很烦,重装,还是有这个问题. 服务中禁用superfect服务,关闭后继续出现1G以上的内存占用,下载svchost viewer检查,发现: 关闭windows ...

  8. 深入学习golang(2)—channel

    Channel 1. 概述 “网络,并发”是Go语言的两大feature.Go语言号称“互联网的C语言”,与使用传统的C语言相比,写一个Server所使用的代码更少,也更简单.写一个Server除了网 ...

  9. Java线程与Linux内核线程的映射关系[转]

    Linux从内核2.6开始使用NPTL (Native POSIX Thread Library)支持,但这时线程本质上还轻量级进程. Java里的线程是由JVM来管理的,它如何对应到操作系统的线程是 ...

  10. linux下redis设置密码登录

    redis设置密码访问 你的redis在真是环境中不可以谁想访问就可以访问,所以必须要设置密码 设置密码的流程如下: vim  /etc/redis.conf #requirepass foobare ...