| 
 | 
	
 
 
  sds和adlist一样,是redis的基础数据结构之一,是其为自身实现的字符串类型。A C dynamic strings library 
  sds.h 
 
 
 
 1 #ifndef __SDS_H 
 2 #define __SDS_H 
 3  
 4 #define SDS_MAX_PREALLOC (1024*1024)       //字符串最大的预分配长度是1M 
 5  
 6 #include  
 7 #include  
 8  
 9 typedef char *sds;          //sds本身被typedef为char*,是后续绝大部分函数的参数(之一) 
10  
11 struct sdshdr { 
12     int len; 
13     int free; 
14     char buf[]; 
15 };      //字符串的数据结构,记录了字符串长度、空闲字节,以及指向实际存储数据buf的指针 
16  
17 static inline size_t sdslen(const sds s) { 
18     struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr))); 
19     return sh->len; 
20 }       //尽管在不考虑typedef的前提下,但从函数参数来看,非引用/指针类型,但毕竟底层实现是char*,因此作者也将所有函数内不改变的参数标记为了const 
           //传的参数指向实际字符串,因此需要先取得数据结构头的位置,然后返回字符串长度; 
21  
22 static inline size_t sdsavail(const sds s) { 
23     struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr))); 
24     return sh->free; 
25 }       //同上,返回的是空闲字节数 
26  
27 sds sdsnewlen(const void *init, size_t initlen); 
28 sds sdsnew(const char *init); 
29 sds sdsempty(); //三个初始化函数 
30 size_t sdslen(const sds s);    //上述内联函数的函数声明 
31 sds sdsdup(const sds s);       //字符串复制函数 
32 void sdsfree(sds s);            
33 size_t sdsavail(sds s); 
34 sds sdsgrowzero(sds s, size_t len); 
35 sds sdscatlen(sds s, void *t, size_t len); 
36 sds sdscat(sds s, char *t); 
37 sds sdscatsds(sds s, sds t); 
38 sds sdscpylen(sds s, char *t, size_t len); 
39 sds sdscpy(sds s, char *t); 
40  
41 sds sdscatvprintf(sds s, const char *fmt, va_list ap); 
42 #ifdef __GNUC__ 
43 sds sdscatprintf(sds s, const char *fmt, ...) 
44     __attribute__((format(printf, 2, 3))); 
45 #else 
46 sds sdscatprintf(sds s, const char *fmt, ...); 
47 #endif     //为啥这么写,没看懂。。非重点,暂且略过 
48  
49 sds sdstrim(sds s, const char *cset); 
50 sds sdsrange(sds s, int start, int end); 
51 void sdsupdatelen(sds s); 
52 void sdsclear(sds s); 
53 int sdscmp(sds s1, sds s2); 
54 sds *sdssplitlen(char *s, int len, char *sep, int seplen, int *count); 
55 void sdsfreesplitres(sds *tokens, int count); 
56 void sdstolower(sds s); 
57 void sdstoupper(sds s); 
58 sds sdsfromlonglong(long long value); 
59 sds sdscatrepr(sds s, char *p, size_t len); 
60 sds *sdssplitargs(char *line, int *argc); 
61  
62 #endif 
对libc的string.h库熟悉的同学,根据上述函数名也大概能猜出来函数的作用,就不一一写了,具体参见sds.c的实现部分。 
  sds.c 
 
 
 
看似很长,但绝大部分代码都很通俗易懂,大家不要恐惧。 
  1 #define SDS_ABORT_ON_OOM     //在内存不够时的默认动作是终止进程(abort) 
  2  
  3 #include  
  4 #include  
  5 #include  
  6 #include  
  7 #include "sds.h" 
  8 #include "zmalloc.h"     //同样用na个简单封装的内存分配库 
  9  
 10 static void sdsOomAbort(void) { 
 11     fprintf(stderr,"SDS: Out Of Memory (SDS_ABORT_ON_OOM defined)\n"); 
 12     abort();  
 13 }                        //abort前作的唯一的善后工作是告诉大家自己是由于在SDS时内存不够挂掉的 
 14  
 15 sds sdsnewlen(const void *init, size_t initlen) { 
 16     struct sdshdr *sh; 
 17  
 18     sh = zmalloc(sizeof(struct sdshdr)+initlen+1); //所分配的长度是头的长度sizeof(struct sdshdr)+字符串长度initlen+‘\0’的一个字节 
                                                       //注意这里的sizeof(struct sdshdr)长度为8,剩下的都直接存在了sh->buf上 
 19 #ifdef SDS_ABORT_ON_OOM 
 20     if (sh == NULL) sdsOomAbort();  
 21 #else 
 22     if (sh == NULL) return NULL;  //如果没有定义SDS_ABORT_ON_OOM,简单的返回NULL 
 23 #endif 
 24     sh->len = initlen; 
 25     sh->free = 0;                 //创建字符串时free的长度是0 
 26     if (initlen) { 
 27         if (init) memcpy(sh->buf, init, initlen);   //若参数init不等于NULL,则拷贝initlen长度给sh->buf 
 28         else memset(sh->buf,0,initlen);             //否则这块缓冲区被赋值为0 
 29     } 
 30     sh->buf[initlen] = '\0';       //用'\0'为字符串结尾 
 31     return (char*)sh->buf;         //返回的是实际字符串的指针 
 32 } 
 33  
 34 sds sdsempty(void) { 
 35     return sdsnewlen("",0);         //注意""字符串常量并不代表空,但0表示空了     
 36 } 
 37  
 38 sds sdsnew(const char *init) { 
 39     size_t initlen = (init == NULL) ? 0 : strlen(init); 
 40     return sdsnewlen(init, initlen); 
 41 } 
 42  
 43 sds sdsdup(const sds s) { 
 44     return sdsnewlen(s, sdslen(s)); 
 45 }                                    //dup复制函数也是调用newlen实现的 
 46  
 47 void sdsfree(sds s) { 
 48     if (s == NULL) return; 
 49     zfree(s-sizeof(struct sdshdr)); 
 50 }                                    //释放链接要先找到sds的header 
 51  
 52 void sdsupdatelen(sds s) { 
 53     struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr))); 
 54     int reallen = strlen(s); 
 55     sh->free += (sh->len-reallen); 
 56     sh->len = reallen; 
 57 }                                    //更新长度是更新header的len和free两个字段 
 58  
 59 void sdsclear(sds s) { 
 60     struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr))); 
 61     sh->free += sh->len; 
 62     sh->len = 0; 
 63     sh->buf[0] = '\0'; 
 64 }                                     //将所有的len都给free,但并未释放内存空间 
 65  
 66 static sds sdsMakeRoomFor(sds s, size_t addlen) { 
 67     struct sdshdr *sh, *newsh; 
 68     size_t free = sdsavail(s); 
 69     size_t len, newlen; 
 70  
 71     if (free >= addlen) return s;         //如果剩余空间仍足够,则直接将传进来的参数s返回 
 72     len = sdslen(s); 
 73     sh = (void*) (s-(sizeof(struct sdshdr))); 
 74     newlen = (len+addlen); 
 75     if (newlen < SDS_MAX_PREALLOC) 
 76         newlen *= 2; 
 77     else 
 78         newlen += SDS_MAX_PREALLOC;        //在为newlen增加了addlen这么长的空余空间的同时,也在这次操作中额外申请了内存空间,当newlen小于系统定义的单次最大分配内存时,额外分配的长度是newlen,负责多分配SDS_MAX_PREALLOC这么大的空间。熟悉std::vector实现的同学对这种分配机制一定似曾相识。这里基于这样一种假设,这次make room的sds,也很有可能在不久的将来再次make room,所以预先分配了空间 
 79     newsh = zrealloc(sh, sizeof(struct sdshdr)+newlen+1);  //realloc保证原来分配空间的数据会拷贝过去,但执行此操作后,sh指针就失效了 
 80 #ifdef SDS_ABORT_ON_OOM 
 81     if (newsh == NULL) sdsOomAbort(); 
 82 #else 
 83     if (newsh == NULL) return NULL; 
 84 #endif 
 85  
 86     newsh->free = newlen - len; 
 87     return newsh->buf; 
 88 } 
 89  
 90 /* Grow the sds to have the specified length. Bytes that were not part of 
 91  * the original length of the sds will be set to zero. */ 
 92 sds sdsgrowzero(sds s, size_t len) {   //len是一个to 参数,表示增长到 
 93     struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr))); 
 94     size_t totlen, curlen = sh->len; 
 95  
 96     if (len = '0' && c = 'a' && c = 'A' && c  0) 
618  
619         sdsfree(y); 
620         sdsfree(x); 
621         x = sdsnew("bar"); 
622         y = sdsnew("bar"); 
623         test_cond("sdscmp(bar,bar)", sdscmp(x,y) == 0) 
624  
625         sdsfree(y); 
626         sdsfree(x); 
627         x = sdsnew("aar"); 
628         y = sdsnew("bar"); 
629         test_cond("sdscmp(bar,bar)", sdscmp(x,y) < 0) 
630     } 
631     test_report() 
632 } 
633 #endif |   
 
 
 
 |