redis变长字符串(simple dynamic strings)学习笔记

主要文件

  • sds.h
  • sds.c

结构

1
2
3
4
5
6
7
struct sdshdr {
int len; // buf已占用长度
int free; // buf可使用长度
char buf[]; // 实际数据
};
typedef char *sds;

知识点

flexible array member

  • sds结构一般指向sdshdr->buf,可以通过sds当前地址计算得到sdshdr地址
    1
    2
    const sds s;
    struct sdshdr *hdr = (void*)(s - (sizeof(struct sdssdr)));

接口说明

获取buf的已占用长度

定义

1
static inline size_t sdslen(const sds s);

流程

  • 根据sds当前地址获取sdshdr地址,获取len元素的值

获取buf的可使用长度

定义

1
static inline size_t sdsavail(const sds s);

流程

  • 根据sds当前地址获取sdshdr地址,获取free元素的值

创建一个指定长度的sds,支持初始化

定义

1
sds sdsnewlen(const void *init, size_t initlen);

流程

  • 根据传入的长度创建一个变长字符串,总占用空间为sizeof(struct sdshdr)+initlen+1,再根据需要进行初始化,len设置为initlen,free设置为0

创建一个包含空串的sds

定义

1
sds sdsempty(void);

流程

  • 调用sdsnewlen(“”, 0)

根据指定初始化值创建sds

定义

1
sds sdsnew(const char *init);

流程

  • 调用sdsnewlen(init, initlen),其中initlen为指定初始化值的长度,若初始化值为NULL,则长度为0

复制sds

定义

1
sds sdsdup(const sds s);

流程

  • 调用sdsnewlen(s, sdslen(s))

释放sds

定义

1
void sdsfree(sds s);

流程

  • 若传入的sds为NULL,则直接返回。否则先找到sdshdr的起始地址,然后释放其对应内存

根据buf的实际长度更新sdshdr的属性

定义

1
void sdsupdatelen(sds s);

流程

  • 根据sds计算得到sdshdr的起始地址,计算buf的实际长度,len与free的值对应调整

清除sds的内容,使其只包含\0

定义

1
void sdsclear(sds s);

流程

  • 根据sds计算得到sdshdr的起始地址,len设置为0,free对应增加len的原长度

对sds的buf进行扩展

定义

1
sds sdsMakeRoomFor(sds s, size_t addlen);

流程

  • 若当前free长度超过扩展长度,则无需操作,否则根据新长度与SDS_MAX_PREALLOC的关系决定扩展后的长度,最后更新sds的free元素

释放sds多余的内存

定义

1
sds sdsRemoveFreeSpace(sds s);

流程

  • 根据sds计算得到sdshdr的起始地址,计算出实际所需内存大小,释放其余的内存,并将free元素置0

计算sds占用的总内存大小

定义

1
size_t sdsAllocSize(sds s);

流程

  • 根据sds计算得到sdshdr的起始地址,总长度=buf指针大小+已占用长度+可使用长度+1

sds buf的右端增加/减少指定长度

定义

1
void sdsIncrLen(sds s, int incr);

流程

  • 若指定长度为正,则free可用长度必须不小于该值。变更buf内容,将新长度的结尾设置为\0,同时更新len与free元素

将sds buf扩展至指定长度,扩展部分设置为\0

定义

1
sds sdsgrowzero(sds s, size_t len);

流程

  • 若当前已占用长度不小于传入的指定长度,则无需操作,否则调用sdsMakeRoomFor扩展长度,并将扩展的部分置为\0,同时更新len与free元素

扩展sds长度并拼接字符串

定义

1
sds sdscatlen(sds s, const void *t, size_t len);

流程

  • 调用sdsMakeRoomFor扩展len长度,将t拼接至结尾,同时更新len与free元素

在sds末尾拼接字符串

定义

1
sds sdscat(sds s, const char *t);

流程

  • 调用return sdscatlen(s, t, strlen(t))

在sds末尾拼接另一个sds

定义

1
sds sdscatsds(sds s, const sds t);

流程

  • 调用sdscatlen(s, t, sdslen(t))

拷贝字符串至sds,指定对应长度

定义

1
sds sdscpylen(sds s, const char *t, size_t len);

流程

  • 若sds长度不够,则调用sdsMakeRoomFor扩展它的长度。复制字符串至buf之后,对应更新len与free元素

拷贝字符串至sds

定义

1
sds sdscpy(sds s, const char *t);

流程

  • 调用sdscpylen(s, t, strlen(t))

从sds两端删除特定字符

定义

1
sds sdstrim(sds s, const char *cset);

流程

  • 从头部和尾部分别遍历sds buf,获取不满足条件的新头部和尾部的位置,将新头部和尾部的字符复制到buf中,并更新len和free元素

指定头部和尾部的位置截取sds

定义

1
sds sdsrange(sds s, int start, int end);

流程

  • 根据指定的头部和尾部的位置,经过部分边界计算,截取得到新的sds

将sds的字母转换为小写形式

定义

1
void sdstolower(sds s);

流程

  • 遍历sds buf,把字母逐个转换为小写形式

将sds的字母转换为大写形式

定义

1
void sdstoupper(sds s);

流程

  • 遍历sds buf,把字母逐个转换为大写形式

比较两个sds的大小

定义

1
int sdscmp(const sds s1, const sds s2);

流程

  • 获取两个sds对应的sdshdr,从而得到各自的长度,使用memcmp逐个字节比较

将字符串分割成多个sds

定义

1
sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count);

流程

  • 从头至尾扫描sds buf,根据分割串,生成多个对应的sds

释放分隔得到的sds

定义

1
void sdsfreesplitres(sds *tokens, int count);

流程

  • 对tokens指向的sds逐个调用sdsfree释放空间

将long long型整数转换为对应的sds

定义

1
sds sdsfromlonglong(long long value);

流程

  • 使用长度为32的字符串,从value低位至高位逐个获取对应的10进制数字,转换成对应字符存入其中,若value为负,则对应增加负号,最后调用sdsnewlen根据该字符串有效位生成sds

在sds后面拼接repr转换之后的字符串

定义

1
sds sdscatrepr(sds s, const char *p, size_t len);

流程

  • 在sds之后拼接一个双引号,之后按指定长度和字符串进行repr转换和拼接,最后再拼接一个双引号

判断字符是否为16进制相关字符

定义

1
int is_hex_digit(char c);

流程

  • 判断字符是否为0~9或a~f或A~F

将16进制相关字符转换为对应整数值

定义

1
int hex_digit_to_int(char c);

流程

  • 将0~9字符分别转为数字0~9,将a~f或A~F对应转为数字10~15

将命令行参数转换成多个sds

定义

1
sds *sdssplitargs(const char *line, int *argc);

流程

  • 逐个遍历line指向的命令行参数字符串,根据字符串分隔符,同时考虑特殊字符与16进制等情形,得到多个sds

释放命令行参数转换之后得到的sds对应的空间

定义

1
void sdssplitargs_free(sds *argv, int argc);

流程

  • 遍历传入的sds,逐个调用sdsfree释放空间

将sds的字符根据规则替换为别的字符

定义

1
sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen);

流程

  • 遍历sds buf的每个字符,若该字符在集合from中,则对应转换为集合to中的字符

将sds与参数列表按指定格式生成的字符串拼接

定义

1
sds sdscatvprintf(sds s, const char *fmt, va_list ap);

流程

  • 以16为起始长度,根据实际容纳参数列表生成的字符串所需要的长度不断翻倍,最后将调用sdscat进行拼接

将sds与变长参数按指定格式生成的字符串拼接

定义

1
sds sdscatprintf(sds s, const char *fmt, ...);

流程

  • 将变长参数转换为va_list格式,调用sdscatvprintf进行拼接