字符串(sds.h/sds.c)¶
为了方便计算字符串的长度、 以及提高字符串的拼接效率, 作者实现了自己的字符串结构sdshdr, 是二进制安全的, 并在后面自动添加0。
数据结构¶
typedef char *sds;
struct sdshdr {
// 记录 buf 数组中已使用字节的数量
// 等于 SDS 所保存字符串的长度
int len;
// 记录 buf 数组中未使用字节的数量
int free;
// 字节数组,用于保存字符串
char buf[];
};
那么一个sds字符串实际申请的内存为: sizeof(sdshdr)+len+free+1, free新申请空间的时候为0, 拼接字符串的时候free就不为0。
技巧¶
- 在函数sdsnewlen中,根据是否需要初始化使用zmalloc和zcalloc两个不同函数。
- 计算字符串长度的时候,直接使用函数sdslen,不需要调用strlen。
3. 需要扩展free的空间时,
需要调用函数sdsMakeRoomFor,
该函数空间分配策略比较有意思,
如果free>=addlen,直接返回。
否则判断free+addlen是否小于SDS_MAX_PREALLOC这个宏,
如果小于,那么这次就分配2*(free+addlen)的空间,
这样每次多分配一陪的空间;
否则就分配free+addlen+SDS_MAX_PREALLOC的空间。
这样可以控制最大多分配多少的空间,
以至于不要浪费太多空间。例如:
sds old=sdsnew("test one");
sds new=sdscat(old,"test");
此时有12的空余空间,
如果再次调用``sdscat(new,”test”)``,
那么就不需要分配空间。
4. 在函数sdscatvprintf中, 空间申请是以16,32,64..这样增长的, 无处不透露提高性能。
5. 在函数sdscmp中, 调用memcmp, 性能要比strcmp好, 而且还是二进制安全的。
6. 在函数sdssplitlen中, 默认分配的数组为5, 然后按照2的倍数进行增长, 这样做法,有点浪费空间,但是加快速度,不要每分割出来一个字符串就要申请空间。 比较的时候把seplen为1分出来, 也是加快字符串比较速度的考虑, 大部分时候应该是seplen为1。