1、sds格式api
sds header定義:函數
1 struct sdshdr { 2 unsigned int len; 3 unsigned int free; 4 char buf[]; 5 };
sizeof(struct sdshdr)= 2*sizeof(unsigned int), char buf[]等價於char buf[0], 僅對編譯器有效,並不實際佔用存儲。優化
其中len是使用的長度,free是剩餘的長度,再加上一個C語言中的'\0'結束符spa
sizeof(buf) = len + free + 1, 格式以下:指針
2、sds基本操做code
一、建立sds對象對象
1 sds sdsnewlen(const void *init, size_t initlen) { 2 struct sdshdr *sh; 3 4 if (init) { 5 sh = zmalloc(sizeof(struct sdshdr)+initlen+1); 6 } else { 7 sh = zcalloc(sizeof(struct sdshdr)+initlen+1); 8 } 9 if (sh == NULL) return NULL; 10 sh->len = initlen; 11 sh->free = 0; 12 if (initlen && init) 13 memcpy(sh->buf, init, initlen); 14 sh->buf[initlen] = '\0'; 15 return (char*)sh->buf; 16 } 17 18 /* Create a new sds string starting from a null terminated C string. */ 19 sds sdsnew(const char *init) { 20 size_t initlen = (init == NULL) ? 0 : strlen(init); 21 return sdsnewlen(init, initlen); 22 }
sdsnew根據輸入C字符串init,建立新的sds對象,typedef char *sds; sds即char *類型。blog
sds s = sdsnew("abc");
當執行上面這行代碼,會在堆內存上面開闢一段連續的空間,具體的空間大小是11個字節的空間。
最前面4個字節存的是len ,也就是sds的長度
其次4個字節存的是free,剩餘的空間。
最後纔是 3個纔是存的是咱們實際的char的信息
也就是每建立一個sds,都會執行上面的操做,都會申請額外的8個字節才存len和free信息。
既然是一段連續的空間,那麼只要已知一個指針,那麼就能拿出struct結構裏面的任何數據。
仍是用上面那個例子
sds s = sdsnew("abc");
這個時候s實際上存的是buf首個char數據的地址。也就是說向前 移8個字節就能到struct sdshdr的len的地址(準確的說是int len的首地址)。8個字節恰好就是struct sdshdr佔的空間字節的大小。
因此下面這個是成立的內存
static inline size_t sdslen(const sds s) { struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));//把buf的首地址向前移動8個,也是到了len return sh->len; }
s - (sizeof(struct sdshdr)) 表示將指針向前移動到 struct sdshdr 的起點,從而得出一個指向 sdshdr 結構的指針: 字符串
sds中函數比較簡單,這裏不作一一介紹,感興趣能夠直接閱讀sds.c中的源碼。
3、sds特色
一、能夠經過O(1)獲取字符串長度,直接返回sds->len便可,C字符串用strlen須要O(N)
二、杜絕緩衝區溢出。一樣由於 sds已經記錄長度信息
三、空間預分配和惰性空間釋放
sds中空間預分配相關函數:
1 sds sdsMakeRoomFor(sds s, size_t addlen) { 2 struct sdshdr *sh, *newsh; 3 size_t free = sdsavail(s); 4 size_t len, newlen; 5 6 if (free >= addlen) return s; // 須要增長的長度小於free,直接返回,避免了頻繁內存申請 7 len = sdslen(s); 8 sh = (void*) (s-(sizeof(struct sdshdr))); 9 newlen = (len+addlen); 10 if (newlen < SDS_MAX_PREALLOC) // 總長度(len+addlen)小於SDS_MAX_PREALLOC(1MB), 新申請長度擴大爲2*newlen 11 newlen *= 2; 12 else 13 newlen += SDS_MAX_PREALLOC; // 不然,只比需求量增長1MB 14 newsh = zrealloc(sh, sizeof(struct sdshdr)+newlen+1); 15 if (newsh == NULL) return NULL; 16 17 newsh->free = newlen - len; 18 return newsh->buf; 19 }
惰性空間釋放用於優化字符串的縮短操做,不用每次縮短都釋放內存,僅修改free和len的大小便可。
例如使用sdstrim操做刪除sds中的的特定字符,最終只要修改free/len大小,不涉及free操做。
真正須要釋放sds中的free空間,能夠調用:
1 sds sdsRemoveFreeSpace(sds s) { 2 struct sdshdr *sh; 3 4 sh = (void*) (s-(sizeof(struct sdshdr))); 5 sh = zrealloc(sh, sizeof(struct sdshdr)+sh->len+1); 6 sh->free = 0; 7 return sh->buf; 8 }
經過realloc來從新分配一塊不包含free的空間,原空間realloc會自動釋放。
四、sds主要api信息