redis源码之动态字符串(sds.h和sds.c)(篇二)

本文详细介绍了Redis源码中sds字符串操作的核心函数,如`sdsMakeRoomFor`用于预留空间,`sdsRemoveFreeSpace`减少多余空间,`sdsIncrLen`调整长度等。这些函数通过预分配策略优化了内存管理,减少了频繁分配的开销。同时,文章还展示了`sdsAllocSize`获取分配大小,`sdsgrowzero`清零扩展,以及拼接和拷贝字符串的相关函数。
摘要由CSDN通过智能技术生成

简介

redis 源码版本:3.05.04

如有理解不对的地方,欢迎各位指出,大家共同交流和学习。

源码学习

sdsMakeRoomFor函数

给一个sds扩充空间以供以后使用(核心函数,后面的函数会经常使用)

sds sdsMakeRoomFor(sds s, size_t addlen) {
    struct sdshdr *sh, *newsh;
    size_t free = sdsavail(s);			//获取的s的剩余空间
    size_t len, newlen;

    if (free >= addlen) return s;		//剩余空间够,则直接返回
    len = sdslen(s);				//空间不够,获取s的长度
    sh = (void*) (s-(sizeof(struct sdshdr)));//获取sds对应结构体的地址
    newlen = (len+addlen);						//计算新追加字符串和原来字符串所占用空间的总长度
    if (newlen < SDS_MAX_PREALLOC)				//如果总长度小于1M,则分配实际字符串所需空间为总长度的2倍
        newlen *= 2;
    else
        newlen += SDS_MAX_PREALLOC;				//如果总长度大于1M,则分配实际字符串所需空间为总长度的基础上增加1M
    newsh = zrealloc(sh, sizeof(struct sdshdr)+newlen+1);//重新申请更大的内存空间
    if (newsh == NULL) return NULL;

    newsh->free = (int)(newlen - len);     //更新剩余大小,即实际字符串所需空间总长度减去字符串的大小                                    WIN_PORT_FIX /* cast (int) */
    return newsh->buf;
}

根据头文件可知,SDS_MAX_PREALLOC是1M空间。

#define SDS_MAX_PREALLOC (1024*1024)

此函数,采用空间换时间的方式,利用预分配策略,较少频繁分配内存。C++中的vector也是采用类似的空间换时间方式。

sdsRemoveFreeSpace函数

根据实际使用长度减少sds的分配内存

sds sdsRemoveFreeSpace(sds s) {
    struct sdshdr *sh;

    sh = (void*) (s-(sizeof(struct sdshdr)));
    sh = (struct sdshdr *)zrealloc(sh, sizeof(struct sdshdr)+sh->len+1);       
    sh->free = 0;//将剩余可用空间置为0
    return sh->buf;

}

sdsAllocSize函数

返回一个sds的分配空间的总长度

//总大小包括指针前的sds头、字符串实际大小、剩余空间以及结束符
size_t sdsAllocSize(sds s) {
    struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
    //见篇一
    return sizeof(*sh)+sh->len+sh->free+1;
}

sdsIncrLen函数

增加一个sds的已经使用的长度

/*要求加完之后不能超过分配的内存长度
此函数用于在用户调用sdsMakeRoomFor()、在当前字符串结束后写入内容并最终需要设置新长度后修复字符串长度。
注意:可以使用负增量来右修剪字符串。*/
void sdsIncrLen(sds s, int incr) {//incr可正可负
  struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
  if (incr >= 0)assert(sh->free >= (unsigned int)incr);
  elseassert(sh->len >= (unsigned int)(-incr));
  sh->len += incr;  //增加sds长度
  sh->free -= incr; //减少字符串末尾的剩余可用空间
  s[sh->len] = '\0';//根据“incr”的字符串结尾。设置空项在。
}

sdsgrowzero函数

将sds增长到指定长度。不属于sds原始长度的字节将设置为零。

sds sdsgrowzero(sds s, size_t len) {
    struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));//通过减去偏移量获取对应的 sdshdr 指针首地址。
    size_t totlen, curlen = sh->len;

    if (len <= curlen) return s;       //如果指定的长度小于当前长度,则不执行任何操作。
    s = sdsMakeRoomFor(s,len-curlen);  //扩充空间
    if (s == NULL) return NULL;
    
    /* 确保添加的区域不包含垃圾数据 */
    sh = (void*)(s-(sizeof(struct sdshdr)));
    memset(s+curlen,0,(len-curlen+1)); //将增加部分内存清零
    totlen = sh->len+sh->free;
    sh->len = (int)len;                                                         
    sh->free = (int)(totlen-sh->len);                                           
    return s;

}

sdscatlen函数

尾部追加数据

/*
s为原始字符串
t为待追加的字符串
len为待追加字符串的长度
*/
sds sdscatlen(sds s, const void *t, size_t len) {
  struct sdshdr *sh;
  size_t curlen = sdslen(s);  //计算字符串已使用空间长度
  s = sdsMakeRoomFor(s,len);  //扩充空间
  if (s == NULL) return NULL;
  sh = (void*) (s-(sizeof(struct sdshdr)));//减去偏移量获取对应的 sdshdr 指针
  memcpy(s+curlen, t, len);
  sh->len = (int)(curlen+len);                       
  sh->free = (int)(sh->free-len);                       
  s[curlen+len] = '\0';
  return s;

}

sdscat函数

拼接字符串

/*
s为原始字符串
t为待拼接的C字符串
*/
sds sdscat(sds s, const char *t) {
  return sdscatlen(s, t, strlen(t));//将指定的t字符串,添加到s字符串尾部
}

sdscatsds函数

拼接字符串(两个sds字符串拼接)

sds sdscatsds(sds s, const sds t) {
  return sdscatlen(s, t, sdslen(t));
}

sdscpylen函数

拷贝字符串

//拷贝t中len个字符到s中
sds sdscpylen(sds s, const char *t, size_t len) {
  struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
  size_t totlen = sh->free+sh->len;//获取s字符串的总长度,包括已使用空间和分配未使用空间,但是不包括结束符‘\0’
  if (totlen < len) {              //如果待拷贝字符长度大于s字符串的总长度,则重新分配空间
​    s = sdsMakeRoomFor(s,len-sh->len);if (s == NULL) return NULL;
​    sh = (void*) (s-(sizeof(struct sdshdr)));
​    totlen = sh->free+sh->len;
  }
  memcpy(s, t, len);
  s[len] = '\0';
  sh->len = (int)len;                            
  sh->free = (int)(totlen-len);                       
  return s;
}

sdscpy函数

拷贝字符串

//拷贝t字符串到s中
sds sdscpy(sds s, const char *t) {
  return sdscpylen(s, t, strlen(t));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值