Redis的簡單動態字串實現

2021-09-06 18:20:40 字數 3960 閱讀 9937

redis 沒有直接使用 c 語言傳統的字串表示(以空字元結尾的字元陣列,以下簡稱 c 字串), 而是自己構建了一種名為簡單動態字串(****** dynamic string,sds)的抽象型別, 並將sds用作 redis 的預設字串表示。

sds簡單動態字串資料結構如下:

1 typedef char *sds;23

struct

sdshdr ;

len記錄字串的長度,free記錄sds還剩餘的空間,buf指向儲存字元的空間。

對應的記憶體空間如下圖:

例如最開始要存放字串「chenrancc」:

一般開始的時候會比初始字串多申請乙個長度的空間放\0,如上圖所示,對應的函式是sdsnewlen

刪除後面的cc字元後:

刪除後面的cc字元後,空出兩個字元空間並不會**,而是用free來記錄。如果要**者兩個空閒的空間,必須重新分配乙個新的sds,做法是將原來的sds通過realloc重新分配成新的sds,對應的函式為sdsremovefreespace。如果要增加sds的空間,也是用同樣的方法通過realloc重新分配乙個新的sds,對應的函式是sdsmakeroomfor

要**sds所在的記憶體空間,可以通過函式sdsfree,它實際呼叫的是free函式。

除了上面提到的函式,sds中還定義了很多其它的函式來方便上層使用:

1 sds sdsnewlen(const

void *init, size_t initlen); //

用長度為initlen的字串建立sds

2 sds sdsempty(void); //

建立乙個長度為0的sds

3 sds sdsnew(const

char *init); //

用null結尾的字串建立sds

4 sds sdsdup(const sds s); //

拷貝乙個sds

5void sdsfree(sds s); //

釋放sds所佔的記憶體空間

6void sdsupdatelen(sds s); //

更新sds中的len為實際的字串長度

7void sdsclear(sds s); //

將sds中的字串為空串

8 sds sdsmakeroomfor(sds s, size_t addlen); //

sds字串所佔空間增加addlen個字元(包括free所佔的字元)

9 sds sdsremovefreespace(sds s); //

去除sds中空閒的空間

10 size_t sdsallocsize(sds s); //

獲取sds實際占用空間的大小

11void sdsincrlen(sds s, int incr); //

sds實際字串的長度增加incr

12 sds sdsgrowzero(sds s, size_t len); //

將sds所佔的空間增加到len,增加的空間都清零

13 sds sdscatlen(sds s, const

void *t, size_t len); //

sds末尾連線乙個長度為len的字串

14 sds sdscat(sds s, const

char *t); //

sds末尾連線乙個以null結尾的字串

15 sds sdscatsds(sds s, const sds t); //

sds末尾連線另乙個sds

16 sds sdscpylen(sds s, const

char *t, size_t len); //

拷貝長度為len的字串到sds中

17 sds sdscpy(sds s, const

char *t); //

拷貝以null結尾的字串到sds中

18 sds sdscatvprintf(sds s, const

char *fmt, va_list ap); //

sds末尾連線乙個由可變引數形成的字串

19 sds sdscatprintf(sds s, const

char *fmt, ...); //

sds末尾連線乙個由可變引數形成的字串

20 sds sdstrim(sds s, const

char *cset); //

去除sds字串的前後字元,這些字元都是在cset中出現過的

21void sdsrange(sds s, int start, int end); //

獲取sds字串的乙個字串,start和end可以為負數,負數表示從後面往前面索引

22void sdstolower(sds s); //

將sds字串中的字元設定為小寫

23void sdstoupper(sds s); //

將sds字串中的字元設定為大寫

24int sdscmp(const sds s1, const sds s2); //

比較兩個字串的大小

25 sds *sdssplitlen(const

char *s, int len, const

char *sep, int seplen, int *count); //

用字串sdp分割乙個sds為多個sds

26void sdsfreesplitres(sds *tokens, int count); //

釋放由函式sdssplitlen返回的sds陣列空間

27 sds sdsfromlonglong(long

long value); //

將long long型別的數字轉化為乙個sds

28 sds sdscatrepr(sds s, const

char *p, size_t len); //

sds末尾連線乙個長度為len的字串,並且將其中的不可列印字元顯示出來

29int is_hex_digit(char c); //

判斷乙個字元釋放為16進製制數字

30int hex_digit_to_int(char c); //

將乙個16進製制數字轉化為整數

31 sds *sdssplitargs(const

char *line, int *argc); //

將一行文字分割成多個引數,每個引數可以用類程式語言 repl格式,如果空格,\n\r\t\0等作為分隔符

32 sds sdsmapchars(sds s, const

char *from, const

char *to, size_t setlen) //

將sds中出現在from中的字元替換為to對應的字元

33 sds sdsjoin(char **argv, int argc, char *sep); //

將多個字串用分割符連線起來組成乙個sds

view code

sds和c++中的vector很類似,唯一不同的是vector在空間不夠的時候可以自動增加2倍的空間。

了解了sds的實現,想想為什麼redis非要自己實現乙個字串,而不是使用c所支援的字串和相關的操作呢?

相比c語言中的字串,sds有如下的好處:

Redis 簡單動態字串

在c語言中,乙個結構體中最後乙個成員的位址減去第乙個成員的位址,就是該結構體的大小 例如 struct sdshdr buf的位址減去len的位址,正好等於sizeof sdshdr 在c 中 char str nihao 是不被允許的,但是c語言中可以,並且可以直接列印str 輸出nihao,和c...

redis簡單動態字串

redis內部使用sds,簡單動態字串,sds是什麼 dynamic t包含字串長度,空間使用率,已使用,未使用等資訊的乙個結構體 sds比c語言字串的優點 獲取字串長度不需要進行遍歷,時間複雜度為o 1 杜絕緩衝區溢位 對sds進行修改的時候,api會先檢查sds的空間是否足夠,如果不需要的話,a...

redis 簡單動態字串

redis沒有直接使用c語言傳統的字串表示,而是自己構建了一種名為簡單動態字串 sds 的抽象型別,並將其作為redis的預設字串表示,即redis中包含字串值的鍵值對在底層都是由sds實現的。每個sds.h sdshdr結構表示乙個sds的值,如下所示 sds遵循c字串以空字元結尾的管理,儲存空字...