首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >sds数据结构分析-redis源码阅读笔记(1)

sds数据结构分析-redis源码阅读笔记(1)

原创
作者头像
evenleo
修改于 2020-11-18 03:44:42
修改于 2020-11-18 03:44:42
4851
举报
文章被收录于专栏:C++的沉思C++的沉思

sds

定义

代码语言:txt
AI代码解释
复制
typedef char *sds;

数据结构:

代码语言:txt
AI代码解释
复制
struct sdshdr {

    // buf 中已占用空间的长度
    int len;

    // buf 中剩余可用空间的长度
    int free;

    // 数据空间
    char buf[];
};

创建对象

代码语言:txt
AI代码解释
复制
sds sdsnew(const char *init) {
    size_t initlen = (init == NULL) ? 0 : strlen(init);
    return sdsnewlen(init, initlen);
}

sds sdsnewlen(const void *init, size_t initlen) {
    struct sdshdr *sh;
    // 根据是否有初始化内容,选择适当的内存分配方式
    // T = O(N)
    if (init) {
        // zmalloc 不初始化所分配的内存
        sh = zmalloc(sizeof(struct sdshdr) + initlen + 1);
    }
    else {
        // zcalloc 将分配的内存全部初始化为 0
        sh = zcalloc(sizeof(struct sdshdr) + initlen + 1);
    }

    // 内存分配失败,返回
    if (sh == NULL) return NULL;
    // 设置初始化长度
    sh->len = initlen;
    // 新 sds 不预留任何空间
    sh->free = 0;
    // 如果有指定初始化内容,将它们复制到 sdshdr 的 buf 中
    // T = O(N)
    if (initlen && init)
        memcpy(sh->buf, init, initlen);
    // 以 \0 结尾
    sh->buf[initlen] = '\0';
    // 返回 buf 部分,而不是整个 sdshdr
    return (char*)sh->buf;
}

获取长度

代码语言:txt
AI代码解释
复制
// 获取字符串长度
static inline size_t sdslen(const sds s) {
    struct sdshdr *sh = (void*)(s - (sizeof(struct sdshdr)));
    return sh->len;
}
// 获取空闲空间长度
static inline size_t sdsavail(const sds s) {
    struct sdshdr *sh = (void*)(s - (sizeof(struct sdshdr)));
    return sh->free;
}

追加字符串

代码语言:txt
AI代码解释
复制
sds sdscatlen(sds s, const void *t, size_t len) {
    struct sdshdr *sh;
    // 原有字符串长度
    size_t curlen = sdslen(s);
    // 扩展 sds 空间
    // T = O(N)
    s = sdsMakeRoomFor(s, len);
    // 内存不足?直接返回
    if (s == NULL) return NULL;
    // 复制 t 中的内容到字符串后部
    // T = O(N)
    sh = (void*)(s - (sizeof(struct sdshdr)));
    memcpy(s + curlen, t, len);
    // 更新属性
    sh->len = curlen + len;
    sh->free = sh->free - len;
    // 添加新结尾符号
    s[curlen + len] = '\0';
    // 返回新 sds
    return s;
}

// 对sds空间进行拓展
sds sdsMakeRoomFor(sds s, size_t addlen) {
    struct sdshdr *sh, *newsh;
    // 获取 s 目前的空余空间长度
    size_t free = sdsavail(s);
    size_t len, newlen;
    // s 目前的空余空间已经足够,无须再进行扩展,直接返回
    if (free >= addlen) return s;
    // 获取 s 目前已占用空间的长度
    len = sdslen(s);
    sh = (void*)(s - (sizeof(struct sdshdr)));
    // s 最少需要的长度
    newlen = (len + addlen);
    // 根据新长度,为 s 分配新空间所需的大小
    if (newlen < SDS_MAX_PREALLOC)
        // 如果新长度小于 SDS_MAX_PREALLOC 
        // 那么为它分配两倍于所需长度的空间
        newlen *= 2;
    else
        // 否则,分配长度为目前长度加上 SDS_MAX_PREALLOC
        newlen += SDS_MAX_PREALLOC;
    // T = O(N)
    newsh = zrealloc(sh, sizeof(struct sdshdr) + newlen + 1);
    // 内存不足,分配失败,返回
    if (newsh == NULL) return NULL;
    // 更新 sds 的空余长度
    newsh->free = newlen - len;
    // 返回 sds
    return newsh->buf;
}

sds和C字符串的区别

  • 常数复杂度获取字符串长度
  • 杜绝缓冲区溢出
  • 减少修改字符串时带来的内存重分配次数
  • 二进制安全
  • 兼容部分C字符串函

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
1 条评论
热度
最新
请问如何获取代码和数据
请问如何获取代码和数据
回复回复点赞举报
推荐阅读
深浅拷贝
1.Object.assign 此方法是es6新推出来的方法,目的是将所有可枚举属性的值从一个或多个源对象分配到目标对象 Object.assign(目标对象, 源对象)该方法参数可以有一个,或者是对个
conanma
2021/10/28
4910
JavaScript中的浅拷贝与深拷贝
JS中有两种数据类型,值类型和引用类型,当我们需要把一个变量赋给另一个变量时,对于值类型很简单:
蒋鹏飞
2020/10/15
7930
JavaScript中的浅拷贝与深拷贝
JavaScript的深浅拷贝
在JavaScript中,拷贝一个对象是一项非常常见的操作,常用的方法包括深拷贝和浅拷贝。但是,不同的拷贝方法会产生不同的效果和影响,因此深入了解和掌握深浅拷贝的概念和实现方法是非常重要的。
泽霖
2023/11/29
1830
简简单单在 JavaScript 中克隆对象
JavaScript 的原始数据类型(例如number、string、null,undefined 和 boolean)是不可变的,这意味着一旦创建,它们的值就无法更改。但是对象和数组是可变的,允许在创建后修改其值。实际上,这意味着基元是通过值传递的,而对象和数组是通过引用传递的。考虑以下例子:
疯狂的技术宅
2020/04/24
6850
简简单单在 JavaScript 中克隆对象
深浅拷贝
Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象
hss
2022/02/25
3240
JavaScript 深拷贝和浅拷贝
在 JavaScript 引用数据类型中,变量保存的是一个指向堆内存的指针,当需要访问引用类型(如对象,数组等)的值时,首先从栈中获得该对象的地址指针,然后再从堆内存中取得所需的数据。
李振
2021/11/26
3270
JS 深拷贝与浅拷贝
其实在工作写代码和面试中,会经常碰到这两个概念:深拷贝,浅拷贝。但今天的重点是深拷贝。
Umbrella1024
2021/02/18
2.2K0
JavaScript中浅拷贝和深拷贝的区别和实现
要理解 JavaScript中浅拷贝和深拷贝的区别,首先要明白JavaScript的数据类型。JavaScript有两种数据类型,基础数据类型和引用数据类型。
Javanx
2019/09/05
6680
JavaScript中浅拷贝和深拷贝的区别和实现
JavaScript专题之深浅拷贝
如果是数组,我们可以利用数组的一些方法比如:slice、concat 返回一个新数组的特性来实现拷贝。
疯狂的技术宅
2019/03/28
4260
JavaScript专题之深浅拷贝
JavaScript中浅拷贝和深拷贝的区别和实现
要理解 JavaScript中浅拷贝和深拷贝的区别,首先要明白JavaScript的数据类型
tianyawhl
2019/04/04
5580
JavaScript中浅拷贝和深拷贝的区别和实现
分享 4 种 JS 深拷贝的方法
浅拷贝是创建一个新对象,这个对象有着原始对象属性值的拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的是内存地址 。
前端达人
2022/06/09
12.8K0
深拷贝 和 浅拷贝 的区别 ?
含义:假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,拿人手短,如果B没变,那就是深拷贝,自食其力。
青梅煮码
2023/01/16
4420
JS实现深浅拷贝
1.实现浅拷贝 // 1. ...实现 let copy1 = {...{x:1}} // 2. Object.assign实现 let copy2 = Object.assign({}, {x:1}) 2. 实现深拷贝 // 1. JOSN.stringify()/JSON.parse() let obj = {a: 1, b: {x: 3}} JSON.parse(JSON.stringify(obj)) // 2. 递归拷贝 function deepClone(obj) { let cop
TimothyJia
2019/11/12
2.2K0
完美解决JavaScript的深浅拷贝
"拷贝"一直都是面试的热门考题。看似简单,实则难住不少面试者,回答的马马虎虎,模棱两可。抽出时间好好分析总结一下"拷贝",让这个难题彻底消失。
小丑同学
2020/09/20
5270
《现代Javascript高级教程》JavaScript深拷贝与浅拷贝
在JavaScript中,对象的拷贝是一项常见的操作。浅拷贝和深拷贝是两种常用的拷贝方式。浅拷贝只复制对象的引用,而深拷贝创建了一个全新的对象,包含与原始对象相同的值和结构。深拷贝和浅拷贝各有适用的场景和注意事项。本文将详细介绍如何实现一个完整而优雅的深拷贝函数,处理循环引用和特殊类型,优化性能,并探讨深拷贝和浅拷贝的应用场景、注意事项和相关属性。
linwu
2023/07/27
6870
搞定 JS 深浅拷贝
一个基本的深拷贝就这样完成了,这里可以用 while 替代 for...in ,因为 while 比 for...in 遍历的速度快,现在就来实现一个迭代器
小鑫
2022/04/24
8160
JavaScript - 浅拷贝和深拷贝
注: JSON.stringify()转换对象过程中,undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成null(出现在数组中时)。函数、undefined 被单独转换时,会返回 undefined。
愤怒的小鸟
2020/12/14
6520
深入理解JavaScript中的堆与栈 、浅拷贝与深拷贝
学了这么长时间的JavaScript想必大家对浅拷贝和深拷贝还不太熟悉吧,今天在项目中既然用到了,早晚也要理清一下思路了,在了解之前,我们还是先从JavaScript的数据类型存放的位置 堆栈开始说起吧!
青梅煮码
2023/03/02
2590
更简洁的深拷贝实现思路
深度克隆(深拷贝)一直都是初、中级前端面试中经常被问到的题目,网上介绍的实现方式也都各有千秋,大体可以概括为三种方式:
前端达人
2022/04/18
6730
更简洁的深拷贝实现思路
再说深拷贝对象的研坑
浅拷贝:只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。 深拷贝:会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。
张炳
2020/05/11
5540
相关推荐
深浅拷贝
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档