redis源码解析(二)动态字符串sds基本功能函数

迷南。 2022-05-10 10:06 265阅读 0赞

1. 简介

  本文继上文基础上,分析动态字符串的功能函数,位于sds.c。由于函数较多,本篇介绍实现动态变化的基本增删新建释放函数。

2. 源码分析

  sdsHdrSize()函数用于返回sdshdr的大小,主要使用sizeof()函数实现。

  1. /*返回sdshdr大小,主要使用sizeof()函数*/
  2. static inline int sdsHdrSize(char type) {
  3. switch(type&SDS_TYPE_MASK) {
  4. case SDS_TYPE_5:
  5. return sizeof(struct sdshdr5);
  6. case SDS_TYPE_8:
  7. return sizeof(struct sdshdr8);
  8. case SDS_TYPE_16:
  9. return sizeof(struct sdshdr16);
  10. case SDS_TYPE_32:
  11. return sizeof(struct sdshdr32);
  12. case SDS_TYPE_64:
  13. return sizeof(struct sdshdr64);
  14. }
  15. return 0;
  16. }

  sdsReqType()根据size返回sdsHdr类型

  1. /*根据size返回sds的类型*/
  2. static inline char sdsReqType(size_t string_size) {
  3. if (string_size < 1<<5)
  4. return SDS_TYPE_5;
  5. if (string_size < 1<<8)
  6. return SDS_TYPE_8;
  7. if (string_size < 1<<16)
  8. return SDS_TYPE_16;
  9. #if (LONG_MAX == LLONG_MAX)
  10. if (string_size < 1ll<<32)
  11. return SDS_TYPE_32;
  12. #endif
  13. return SDS_TYPE_64;
  14. }

  sdsnewlen()函数创建新的sds动态数组

  1. /* 初始化函数 * Create a new sds string with the content specified by the 'init' pointer * and 'initlen'. * If NULL is used for 'init' the string is initialized with zero bytes. * * The string is always null-termined (all the sds strings are, always) so * even if you create an sds string with: * * mystring = sdsnewlen("abc",3); * * You can print the string with printf() as there is an implicit \0 at the * end of the string. However the string is binary safe and can contain * \0 characters in the middle, as the length is stored in the sds header. */
  2. sds sdsnewlen(const void *init, size_t initlen) {
  3. void *sh;
  4. sds s;
  5. /*根据initlen返回type*/
  6. char type = sdsReqType(initlen);
  7. /* Empty strings are usually created in order to append. Use type 8 * since type 5 is not good at this. */
  8. if (type == SDS_TYPE_5 && initlen == 0) type = SDS_TYPE_8;
  9. /*hdrlen赋值为sds的size*/
  10. int hdrlen = sdsHdrSize(type);
  11. unsigned char *fp; /* flags pointer. */
  12. /*分配空间*/
  13. sh = s_malloc(hdrlen+initlen+1);
  14. if (!init)
  15. memset(sh, 0, hdrlen+initlen+1);
  16. /*错误返回*/
  17. if (sh == NULL) return NULL;
  18. /*s指向数据,fp为首指针前一位,指向flag,存储type*/
  19. s = (char*)sh+hdrlen;
  20. fp = ((unsigned char*)s)-1;
  21. switch(type) {
  22. case SDS_TYPE_5: {
  23. *fp = type | (initlen << SDS_TYPE_BITS);
  24. break;
  25. }
  26. case SDS_TYPE_8: {
  27. SDS_HDR_VAR(8,s);
  28. sh->len = initlen;
  29. sh->alloc = initlen;
  30. *fp = type;
  31. break;
  32. }
  33. case SDS_TYPE_16: {
  34. SDS_HDR_VAR(16,s);
  35. sh->len = initlen;
  36. sh->alloc = initlen;
  37. *fp = type;
  38. break;
  39. }
  40. case SDS_TYPE_32: {
  41. SDS_HDR_VAR(32,s);
  42. sh->len = initlen;
  43. sh->alloc = initlen;
  44. *fp = type;
  45. break;
  46. }
  47. case SDS_TYPE_64: {
  48. SDS_HDR_VAR(64,s);
  49. sh->len = initlen;
  50. sh->alloc = initlen;
  51. *fp = type;
  52. break;
  53. }
  54. }
  55. if (initlen && init)
  56. memcpy(s, init, initlen);
  57. s[initlen] = '\0';
  58. return s;
  59. }

  sdsempty()函数利用sdsnewlen创建空sds动态数组

  1. /* 创建空sds * Create an empty (zero length) sds string. Even in this case the string * always has an implicit null term. */
  2. sds sdsempty(void) {
  3. return sdsnewlen("",0);
  4. }

  sdsnew()利用sdsnewlen()创建sds动态数组

  1. /* 创建新sds * Create a new sds string starting from a null terminated C string. */
  2. sds sdsnew(const char *init) {
  3. size_t initlen = (init == NULL) ? 0 : strlen(init);
  4. return sdsnewlen(init, initlen);
  5. }

  sdsdup()函数使用sdsnewlen()复制已有的sds

  1. /* 复制sds * Duplicate an sds string. */
  2. sds sdsdup(const sds s) {
  3. return sdsnewlen(s, sdslen(s));
  4. }

  sdsfree()函数释放sds的空间

  1. /* 释放sds * Free an sds string. No operation is performed if 's' is NULL. */
  2. void sdsfree(sds s) {
  3. if (s == NULL) return;
  4. s_free((char*)s-sdsHdrSize(s[-1]));
  5. }

  sdsupdatelen()函数更新sdsHdr的长度

  1. /* 当sds数据变化后,调用该函数更新sds长度 * Set the sds string length to the length as obtained with strlen(), so * considering as content only up to the first null term character. * * This function is useful when the sds string is hacked manually in some * way, like in the following example: * * s = sdsnew("foobar"); * s[2] = '\0'; * sdsupdatelen(s); * printf("%d\n", sdslen(s)); * * The output will be "2", but if we comment out the call to sdsupdatelen() * the output will be "6" as the string was modified but the logical length * remains 6 bytes. */
  2. void sdsupdatelen(sds s) {
  3. size_t reallen = strlen(s);
  4. sdssetlen(s, reallen);
  5. }

  sdsclear()函数将sds长度和内容置零

  1. /* 清空sds * Modify an sds string in-place to make it empty (zero length). * However all the existing buffer is not discarded but set as free space * so that next append operations will not require allocations up to the * number of bytes previously available. */
  2. void sdsclear(sds s) {
  3. sdssetlen(s, 0);
  4. s[0] = '\0';
  5. }

  动态字符串之扩容:sdsMakeRoomFor()函数。根据增加的addlen来调整sdsHdr的类型。

  1. /* sds扩容 * Enlarge the free space at the end of the sds string so that the caller * is sure that after calling this function can overwrite up to addlen * bytes after the end of the string, plus one more byte for nul term. * * Note: this does not change the *length* of the sds string as returned * by sdslen(), but only the free buffer space we have. */
  2. sds sdsMakeRoomFor(sds s, size_t addlen) {
  3. void *sh, *newsh;
  4. size_t avail = sdsavail(s);
  5. size_t len, newlen;
  6. char type, oldtype = s[-1] & SDS_TYPE_MASK;
  7. int hdrlen;
  8. /* 可用空间够大,则不扩容了 * Return ASAP if there is enough space left. */
  9. if (avail >= addlen) return s;
  10. len = sdslen(s);
  11. sh = (char*)s-sdsHdrSize(oldtype);
  12. newlen = (len+addlen);
  13. /*这里的翻倍规则和动态数组vector是一样的:便于下次扩容*/
  14. if (newlen < SDS_MAX_PREALLOC)
  15. newlen *= 2;
  16. else
  17. newlen += SDS_MAX_PREALLOC;
  18. type = sdsReqType(newlen);
  19. /* 不适用type 5 * Don't use type 5: the user is appending to the string and type 5 is * not able to remember empty space, so sdsMakeRoomFor() must be called * at every appending operation. */
  20. if (type == SDS_TYPE_5) type = SDS_TYPE_8;
  21. hdrlen = sdsHdrSize(type);
  22. if (oldtype==type) {
  23. newsh = s_realloc(sh, hdrlen+newlen+1);
  24. if (newsh == NULL) return NULL;
  25. s = (char*)newsh+hdrlen;
  26. } else {
  27. /* 头部size变化了 * Since the header size changes, need to move the string forward, * and can't use realloc */
  28. newsh = s_malloc(hdrlen+newlen+1);
  29. if (newsh == NULL) return NULL;
  30. memcpy((char*)newsh+hdrlen, s, len+1);
  31. s_free(sh);
  32. s = (char*)newsh+hdrlen;
  33. s[-1] = type;
  34. sdssetlen(s, len);
  35. }
  36. sdssetalloc(s, newlen);
  37. return s;
  38. }

  压缩空间的函数sdsRemoveFreeSpace(),功能和扩展空间相反。

  1. /* 用于节省空间,和扩容相反 * Reallocate the sds string so that it has no free space at the end. The * contained string remains not altered, but next concatenation operations * will require a reallocation. * * After the call, the passed sds string is no longer valid and all the * references must be substituted with the new pointer returned by the call. */
  2. sds sdsRemoveFreeSpace(sds s) {
  3. void *sh, *newsh;
  4. char type, oldtype = s[-1] & SDS_TYPE_MASK;
  5. int hdrlen, oldhdrlen = sdsHdrSize(oldtype);
  6. size_t len = sdslen(s);
  7. sh = (char*)s-oldhdrlen;
  8. /* Check what would be the minimum SDS header that is just good enough to * fit this string. */
  9. type = sdsReqType(len);
  10. hdrlen = sdsHdrSize(type);
  11. /* If the type is the same, or at least a large enough type is still * required, we just realloc(), letting the allocator to do the copy * only if really needed. Otherwise if the change is huge, we manually * reallocate the string to use the different header type. */
  12. if (oldtype==type || type > SDS_TYPE_8) {
  13. newsh = s_realloc(sh, oldhdrlen+len+1);
  14. if (newsh == NULL) return NULL;
  15. s = (char*)newsh+oldhdrlen;
  16. } else {
  17. newsh = s_malloc(hdrlen+len+1);
  18. if (newsh == NULL) return NULL;
  19. memcpy((char*)newsh+hdrlen, s, len+1);
  20. s_free(sh);
  21. s = (char*)newsh+hdrlen;
  22. s[-1] = type;
  23. sdssetlen(s, len);
  24. }
  25. sdssetalloc(s, len);
  26. return s;
  27. }

  sdsAllocSize()函数返回sds的总大小

  1. /* 返回sds对应的总大小 * Return the total size of the allocation of the specifed sds string, * including: * 1) The sds header before the pointer. * 2) The string. * 3) The free buffer at the end if any. * 4) The implicit null term. */
  2. size_t sdsAllocSize(sds s) {
  3. size_t alloc = sdsalloc(s);
  4. return sdsHdrSize(s[-1])+alloc+1;
  5. }

  sdsAllocPtr()函数返回sds位置的指针

  1. /* Return the pointer of the actual SDS allocation (normally SDS strings * are referenced by the start of the string buffer). */
  2. void *sdsAllocPtr(sds s) {
  3. return (void*) (s-sdsHdrSize(s[-1]));
  4. }

  sdsIncrLen()函数:增加sds的长度,减少剩余空间的大小

  1. /* 增加sds长度,并减少剩余空间大小 * Increment the sds length and decrements the left free space at the * end of the string according to 'incr'. Also set the null term * in the new end of the string. * * This function is used in order to fix the string length after the * user calls sdsMakeRoomFor(), writes something after the end of * the current string, and finally needs to set the new length. * * Note: it is possible to use a negative increment in order to * right-trim the string. * * Usage example: * * Using sdsIncrLen() and sdsMakeRoomFor() it is possible to mount the * following schema, to cat bytes coming from the kernel to the end of an * sds string without copying into an intermediate buffer: * * oldlen = sdslen(s); * s = sdsMakeRoomFor(s, BUFFER_SIZE); * nread = read(fd, s+oldlen, BUFFER_SIZE); * ... check for nread <= 0 and handle it ... * sdsIncrLen(s, nread); */
  2. void sdsIncrLen(sds s, ssize_t incr) {
  3. unsigned char flags = s[-1];
  4. size_t len;
  5. switch(flags&SDS_TYPE_MASK) {
  6. case SDS_TYPE_5: {
  7. unsigned char *fp = ((unsigned char*)s)-1;
  8. unsigned char oldlen = SDS_TYPE_5_LEN(flags);
  9. assert((incr > 0 && oldlen+incr < 32) || (incr < 0 && oldlen >= (unsigned int)(-incr)));
  10. *fp = SDS_TYPE_5 | ((oldlen+incr) << SDS_TYPE_BITS);
  11. len = oldlen+incr;
  12. break;
  13. }
  14. case SDS_TYPE_8: {
  15. SDS_HDR_VAR(8,s);
  16. assert((incr >= 0 && sh->alloc-sh->len >= incr) || (incr < 0 && sh->len >= (unsigned int)(-incr)));
  17. len = (sh->len += incr);
  18. break;
  19. }
  20. case SDS_TYPE_16: {
  21. SDS_HDR_VAR(16,s);
  22. assert((incr >= 0 && sh->alloc-sh->len >= incr) || (incr < 0 && sh->len >= (unsigned int)(-incr)));
  23. len = (sh->len += incr);
  24. break;
  25. }
  26. case SDS_TYPE_32: {
  27. SDS_HDR_VAR(32,s);
  28. assert((incr >= 0 && sh->alloc-sh->len >= (unsigned int)incr) || (incr < 0 && sh->len >= (unsigned int)(-incr)));
  29. len = (sh->len += incr);
  30. break;
  31. }
  32. case SDS_TYPE_64: {
  33. SDS_HDR_VAR(64,s);
  34. assert((incr >= 0 && sh->alloc-sh->len >= (uint64_t)incr) || (incr < 0 && sh->len >= (uint64_t)(-incr)));
  35. len = (sh->len += incr);
  36. break;
  37. }
  38. default: len = 0; /* Just to avoid compilation warnings. */
  39. }
  40. s[len] = '\0';
  41. }

  sdsgrowzero()函数将sds增长len,正常的部分填充0.

  1. /* 将sds增长至某值,增长部分填充0 * Grow the sds to have the specified length. Bytes that were not part of * the original length of the sds will be set to zero. * * if the specified length is smaller than the current length, no operation * is performed. */
  2. sds sdsgrowzero(sds s, size_t len) {
  3. size_t curlen = sdslen(s);
  4. if (len <= curlen) return s;
  5. s = sdsMakeRoomFor(s,len-curlen);
  6. if (s == NULL) return NULL;
  7. /* Make sure added region doesn't contain garbage */
  8. memset(s+curlen,0,(len-curlen+1)); /* also set trailing \0 byte */
  9. sdssetlen(s, len);
  10. return s;
  11. }

  sdscatlen()函数将字符串t增加在sds之后。

  1. /* Append the specified binary-safe string pointed by 't' of 'len' bytes to the * end of the specified sds string 's'. * * After the call, the passed sds string is no longer valid and all the * references must be substituted with the new pointer returned by the call. */
  2. sds sdscatlen(sds s, const void *t, size_t len) {
  3. size_t curlen = sdslen(s);
  4. s = sdsMakeRoomFor(s,len);
  5. if (s == NULL) return NULL;
  6. memcpy(s+curlen, t, len);
  7. sdssetlen(s, curlen+len);
  8. s[curlen+len] = '\0';
  9. return s;
  10. }

  sdscat()函数和上面函数的区别在于不输入长度len,而使用strlen获取长度

  1. /* 在sds之后增加一个字符串t * Append the specified null termianted C string to the sds string 's'. * * After the call, the passed sds string is no longer valid and all the * references must be substituted with the new pointer returned by the call. */
  2. sds sdscat(sds s, const char *t) {
  3. return sdscatlen(s, t, strlen(t));
  4. }

  sdscatsds()函数在已有的sds之后加上另一个sds

  1. /* 在已有的sds之后添加另一个sds * Append the specified sds 't' to the existing sds 's'. * * After the call, the modified sds string is no longer valid and all the * references must be substituted with the new pointer returned by the call. */
  2. sds sdscatsds(sds s, const sds t) {
  3. return sdscatlen(s, t, sdslen(t));
  4. }

  sdscpylen()使用t代替已有的s

  1. /* 将已有的s内容用t代替 * Destructively modify the sds string 's' to hold the specified binary * safe string pointed by 't' of length 'len' bytes. */
  2. sds sdscpylen(sds s, const char *t, size_t len) {
  3. if (sdsalloc(s) < len) {
  4. s = sdsMakeRoomFor(s,len-sdslen(s));
  5. if (s == NULL) return NULL;
  6. }
  7. memcpy(s, t, len);
  8. s[len] = '\0';
  9. sdssetlen(s, len);
  10. return s;
  11. }

  sdscpy()函数和上面函数的区别在于不需要输入len,使用strlen获取

  1. /* 使用自动获取长度的方式,将s内容用以NULL结尾的字符串t代替 * Like sdscpylen() but 't' must be a null-termined string so that the length * of the string is obtained with strlen(). */
  2. sds sdscpy(sds s, const char *t) {
  3. return sdscpylen(s, t, strlen(t));
  4. }

  sdsll2str()函数将一个long long整数转换为字符串s

  1. /* 将一个long long整数转换为字符串s * Helper for sdscatlonglong() doing the actual number -> string * conversion. 's' must point to a string with room for at least * SDS_LLSTR_SIZE bytes. * * The function returns the length of the null-terminated string * representation stored at 's'. */
  2. #define SDS_LLSTR_SIZE 21
  3. int sdsll2str(char *s, long long value) {
  4. char *p, aux;
  5. unsigned long long v;
  6. size_t l;
  7. /* 每次获取最低位,因此存储的是逆序的 * Generate the string representation, this method produces * an reversed string. **/
  8. v = (value < 0) ? -value : value;
  9. p = s;
  10. do {
  11. *p++ = '0'+(v%10);
  12. v /= 10;
  13. } while(v);
  14. if (value < 0) *p++ = '-';
  15. /* Compute length and add null term. */
  16. l = p-s;
  17. *p = '\0';
  18. /* Reverse the string. */
  19. p--;
  20. while(s < p) {
  21. aux = *s;
  22. *s = *p;
  23. *p = aux;
  24. s++;
  25. p--;
  26. }
  27. return l;
  28. }

  和上面类似,只是类型为unsigned

  1. /* 和上面类似,只是类型为unsigned * Identical sdsll2str(), but for unsigned long long type. */
  2. int sdsull2str(char *s, unsigned long long v) {
  3. char *p, aux;
  4. size_t l;
  5. /* Generate the string representation, this method produces * an reversed string. */
  6. p = s;
  7. do {
  8. *p++ = '0'+(v%10);
  9. v /= 10;
  10. } while(v);
  11. /* Compute length and add null term. */
  12. l = p-s;
  13. *p = '\0';
  14. /* Reverse the string. */
  15. p--;
  16. while(s < p) {
  17. aux = *s;
  18. *s = *p;
  19. *p = aux;
  20. s++;
  21. p--;
  22. }
  23. return l;
  24. }

  从long long类型创建一个sds

  1. /* 从long long类型创建一个sds * Create an sds string from a long long value. It is much faster than: * * sdscatprintf(sdsempty(),"%lld\n", value); */
  2. sds sdsfromlonglong(long long value) {
  3. char buf[SDS_LLSTR_SIZE];
  4. int len = sdsll2str(buf,value);
  5. return sdsnewlen(buf,len);
  6. }

  

发表评论

表情:
评论列表 (有 0 条评论,265人围观)

还没有评论,来说两句吧...

相关阅读