CppGuide社区 CppGuide社区
首页
  • 最新谷歌C++风格指南(含C++17/20)
  • C++17详解
  • C++20完全指南
  • C++23快速入门
  • C++语言面试问题集锦
  • 🔥C/C++后端开发常见面试题解析 (opens new window)
  • 网络编程面试题 (opens new window)
  • 网络编程面试题 答案详解 (opens new window)
  • 聊聊WebServer作面试项目那些事儿 (opens new window)
  • 字节跳动面试官现身说 (opens new window)
  • 技术简历指南 (opens new window)
  • 🔥交易系统开发岗位求职与面试指南 (opens new window)
  • 第1章 高频C++11重难点知识解析
  • 第2章 Linux GDB高级调试指南
  • 第3章 C++多线程编程从入门到进阶
  • 第4章 C++网络编程重难点解析
  • 第5章 网络通信故障排查常用命令
  • 第6章 高性能网络通信协议设计精要
  • 第7章 高性能服务结构设计
  • 第8章 Redis网络通信模块源码分析
  • 第9章 后端服务重要模块设计探索
  • 🚀 全部章节.pdf 下载 (opens new window)
  • 源码分析系列

    • leveldb源码分析
    • libevent源码分析
    • Memcached源码分析
    • TeamTalk源码分析
    • 优质源码分享 (opens new window)
    • 🔥远程控制软件gh0st源码分析
  • 从零手写C++项目系列

    • C++游戏编程入门(零基础学C++)
    • 🔥使用C++17从零开发一个调试器 (opens new window)
    • 🔥使用C++20从零构建一个完整的低延迟交易系统 (opens new window)
    • 🔥使用C++从零写一个C语言编译器 (opens new window)
    • 从零用C语言写一个Redis
  • Windows 10系统编程
  • Go语言特性

    • Go开发实用指南
    • Go系统接口编程
    • 高效Go并发编程
    • Go性能调优
    • Go项目架构设计
  • Go项目实战

    • 使用Go从零开发一个数据库
    • 🔥使用Go从零开发一个编译器 (opens new window)
    • 🔥使用Go从零开发一个解释器 (opens new window)
    • 🔥用Go从零写一个编排器(类Kubernetes) (opens new window)
  • Rust编程

    • Rust编程指南
  • 数据库

    • SQL零基础指南
    • MySQL开发与调试指南
  • Linux内核

    • 心中的内核 —— 在阅读内核代码之前先理解内核
    • 🔥Linux 5.x内核开发与调试 完全指南 (opens new window)
    • TCP源码实现超详细注释版.pdf (opens new window)
GitHub (opens new window)
首页
  • 最新谷歌C++风格指南(含C++17/20)
  • C++17详解
  • C++20完全指南
  • C++23快速入门
  • C++语言面试问题集锦
  • 🔥C/C++后端开发常见面试题解析 (opens new window)
  • 网络编程面试题 (opens new window)
  • 网络编程面试题 答案详解 (opens new window)
  • 聊聊WebServer作面试项目那些事儿 (opens new window)
  • 字节跳动面试官现身说 (opens new window)
  • 技术简历指南 (opens new window)
  • 🔥交易系统开发岗位求职与面试指南 (opens new window)
  • 第1章 高频C++11重难点知识解析
  • 第2章 Linux GDB高级调试指南
  • 第3章 C++多线程编程从入门到进阶
  • 第4章 C++网络编程重难点解析
  • 第5章 网络通信故障排查常用命令
  • 第6章 高性能网络通信协议设计精要
  • 第7章 高性能服务结构设计
  • 第8章 Redis网络通信模块源码分析
  • 第9章 后端服务重要模块设计探索
  • 🚀 全部章节.pdf 下载 (opens new window)
  • 源码分析系列

    • leveldb源码分析
    • libevent源码分析
    • Memcached源码分析
    • TeamTalk源码分析
    • 优质源码分享 (opens new window)
    • 🔥远程控制软件gh0st源码分析
  • 从零手写C++项目系列

    • C++游戏编程入门(零基础学C++)
    • 🔥使用C++17从零开发一个调试器 (opens new window)
    • 🔥使用C++20从零构建一个完整的低延迟交易系统 (opens new window)
    • 🔥使用C++从零写一个C语言编译器 (opens new window)
    • 从零用C语言写一个Redis
  • Windows 10系统编程
  • Go语言特性

    • Go开发实用指南
    • Go系统接口编程
    • 高效Go并发编程
    • Go性能调优
    • Go项目架构设计
  • Go项目实战

    • 使用Go从零开发一个数据库
    • 🔥使用Go从零开发一个编译器 (opens new window)
    • 🔥使用Go从零开发一个解释器 (opens new window)
    • 🔥用Go从零写一个编排器(类Kubernetes) (opens new window)
  • Rust编程

    • Rust编程指南
  • 数据库

    • SQL零基础指南
    • MySQL开发与调试指南
  • Linux内核

    • 心中的内核 —— 在阅读内核代码之前先理解内核
    • 🔥Linux 5.x内核开发与调试 完全指南 (opens new window)
    • TCP源码实现超详细注释版.pdf (opens new window)
GitHub (opens new window)
  • leveldb源码分析1
  • leveldb源码分析2
    • leveldb源码分析3
    • leveldb源码分析4
    • leveldb源码分析5
    • leveldb源码分析6
    • leveldb源码分析7
    • leveldb源码分析8
    • leveldb源码分析9
    • leveldb源码分析10
    • leveldb源码分析11
    • leveldb源码分析12
    • leveldb源码分析13
    • leveldb源码分析14
    • leveldb源码分析15
    • leveldb源码分析16
    • leveldb源码分析17
    • leveldb源码分析18
    • leveldb源码分析19
    • leveldb源码分析20
    • leveldb源码分析21
    • leveldb源码分析22
    • leveldb源码分析
    zhangxf
    2023-04-02
    目录

    leveldb源码分析2

    # leveldb源码分析2

    本系列《leveldb源码分析》共有22篇文章,这是第二篇。

    # 3.Int Coding

    轻松一刻,前面约定中讲过Leveldb使用了很多VarInt型编码,典型的如后面将涉及到的各种key。其中的编码、解码函数分为VarInt和FixedInt两种。int32和int64操作都是类似的。

    # 3.1 Eecode

    首先是FixedInt编码,直接上代码,很简单明了。

    void EncodeFixed32(char* buf, uint32_t value)
    {
      if (port::kLittleEndian) {
        memcpy(buf, &value,sizeof(value));
      } else {
        buf[0] = value & 0xff;
        buf[1] = (value >> 8)& 0xff;
        buf[2] = (value >> 16)& 0xff;
        buf[3] = (value >> 24)& 0xff;
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    下面是VarInt编码,int32和int64格式,代码如下,有效位是7bit的,因此把uint32按7bit分割,对unsigned char赋值时,超出0xFF会自动截断,因此直接*(ptr++) = v|B即可,不需要再把(v|B)与0xFF作&操作。

    char* EncodeVarint32(char* dst, uint32_t v)
    {
      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);
    }
    
    // 对于uint64,直接循环
    char* EncodeVarint64(char* dst, uint64_t v) {
      static const int B = 128;
      unsigned char* ptr =reinterpret_cast<unsigned char*>(dst);
      while (v >= B) {
        *(ptr++) = (v & (B-1)) |B;
        v >>= 7;
      }
      *(ptr++) =static_cast<unsigned char>(v);
      returnreinterpret_cast<char*>(ptr);
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39

    # 3.2 Decode

    Fixed Int的Decode,操作,代码:

    inline uint32_t DecodeFixed32(const char* ptr)
    {
      if (port::kLittleEndian) {
        uint32_t result;
        // gcc optimizes this to a plain load
        memcpy(&result, ptr,sizeof(result));
        return result;
      } else {
        return((static_cast<uint32_t>(static_cast<unsigned char>(ptr[0])))
            |(static_cast<uint32_t>(static_cast<unsigned char>(ptr[1])) <<8)
            | (static_cast<uint32_t>(static_cast<unsignedchar>(ptr[2])) << 16)
            |(static_cast<uint32_t>(static_cast<unsigned char>(ptr[3])) <<24));
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    再来看看VarInt的解码,很简单,依次读取1byte,直到最高位为0的byte结束,取低7bit,作(<<7)移位操作组合成Int。看代码:

    const char* GetVarint32Ptr(const char* p,
                               const char* limit, 
                               uint32_t* value)
    {
      if (p < limit) {
        uint32_t result =*(reinterpret_cast<const unsigned char*>(p));
        if ((result & 128) == 0) {
          *value = result;
          return p + 1;
        }
      }
      return GetVarint32PtrFallback(p,limit, value);
    }
    
    const char* GetVarint32PtrFallback(const char* p,
                                       const char* limit,
                                       uint32_t* value)
    {
      uint32_t result = 0;
      for (uint32_t shift = 0; shift<= 28 && p < limit; shift += 7) {
        uint32_t byte =*(reinterpret_cast<const unsigned char*>(p));
        p++;
        if (byte & 128) { // More bytes are present
          result |= ((byte & 127)<< shift);
        } else {
          result |= (byte <<shift);
          *value = result;
          returnreinterpret_cast<const char*>(p);
        }
      }
      return NULL;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    编辑 (opens new window)
    上次更新: 2023/12/11, 22:32:09
    leveldb源码分析1
    leveldb源码分析3

    ← leveldb源码分析1 leveldb源码分析3→

    最近更新
    01
    第二章 关键字static及其不同用法
    03-27
    02
    第一章 auto与类型推导
    03-27
    03
    第四章 Lambda函数
    03-27
    更多文章>
    Copyright © 2024-2025 沪ICP备2023015129号 张小方 版权所有
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式