简介
redis 源码版本:3.05.04
如有理解不对的地方,欢迎各位指出,大家共同交流和学习。
源码学习
sdstrim函数
移除字符串
/*
从s中移除所有cset中出现的字符
*/
sds sdstrim(sds s, const char *cset) {
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
char *start, *end, *sp, *ep;
size_t len;
sp = start = s; //s是指向sh的buf成员的地址,字符串中的起始地址
ep = end = s+sdslen(s)-1; //end指向字符串的结尾,不是结束符‘\0’
while(sp <= end && strchr(cset, *sp)) sp++; //strchr()函数在字符串中搜索第一次出现某个字符的位置
while(ep > start && strchr(cset, *ep)) ep--;
len = (sp > ep) ? 0 : ((ep-sp)+1); //计算移除后字符串的长度
if (sh->buf != sp) memmove(sh->buf, sp, len);//移动元素到buf头部
sh->buf[len] = '\0';
sh->free = sh->free+(int)(sh->len-len); //更新剩余空间
sh->len = (int)len; //更新使用空间
return s;
}
第5、6行代码的start和end含义如下:
start指向字符串的开头
end指向字符串的结尾,不是结束符‘\0’
假如,用该函数移除"HeAlBIoB"中的字符A和B时,函数调用如下形式:
sdstrim("HeAlBIoB","AB") //结果:Hello
该函数操作原理如下:
从上图可以看出,该函数并没有将A和B移除后的空间回收掉,而是采用更新free值,来记录未使用空间,等待以后使用,从而避免内存的频繁分配。
sdsrange函数
截取指定范围的字符
/*
保留s中从start开始到end结束的字符
*/
void sdsrange(sds s, int start, int end) {
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));//获取首地址
size_t newlen, len = sdslen(s);
if (len == 0) return; //如果字符串长度为0,直接返回
if (start < 0) { //为负值,从后开始计算
start = (int)len+start;
if (start < 0) start = 0;
}
if (end < 0) { //end为负值时处理
end = (int)len+end;
if (end < 0) end = 0;
}
newlen = (start > end) ? 0 : (end-start)+1;//计算新的字符长度
if (newlen != 0) {
if (start >= (signed)len) {
newlen = 0;
} else if (end >= (signed)len) {
end = (int)len-1;
newlen = (start > end) ? 0 : (end-start)+1;
}
} else {
start = 0;
}
if (start && newlen) memmove(sh->buf, sh->buf+start, newlen);//从buf+start位置复制newlen个字符到buf中
//更新属性值
sh->buf[newlen] = 0; //等价'\0'
sh->free = (int)(sh->free+(sh->len-newlen));
sh->len = (int)newlen;
}
字符串下标从0开始,当start为正n时,表示第n+1个字符,当start为负n时,表示倒数第n个字符。
sdscmp函数
比较两个sds字符串是否相同
/*
返回值:小于0:s1小于s2
等于0:相等
大于0:s1大于s2
*/
int sdscmp(const sds s1, const sds s2) {
size_t l1, l2, minlen;
int cmp;
l1 = sdslen(s1); //计算s1字符串已使用空间长度
l2 = sdslen(s2); //计算s2字符串已使用空间长度
minlen = (l1 < l2) ? l1 : l2; //取长度最小的字符
cmp = memcmp(s1,s2,minlen); //比较s1和s2的前minlen个字符 memcmp()为c语言函数
if (cmp == 0) return (int)(l1-l2);
return cmp;
}
sdstolower 函数
将字符串全部转为小写
void sdstolower(sds s) {
int len = (int)sdslen(s), j; //len为字符长度
for (j = 0; j < len; j++) s[j] = tolower(s[j]);//遍历字符进行转换
}
sdstoupper 函数
将字符串全部转为大写
void sdstoupper(sds s) {
int len = (int)sdslen(s), j;
for (j = 0; j < len; j++) s[j] = toupper(s[j]);
}