zoukankan      html  css  js  c++  java
  • redis源码学习_简单动态字符串

    SDS相比传统C语言的字符串有以下好处:

    (1)空间预分配和惰性释放,这就可以减少内存重新分配的次数

    (2)O(1)的时间复杂度获取字符串的长度

    (3)二进制安全

    主要总结一下sds.c和sds.h中的关键函数

    1、sdsmapchars

     1 /* Modify the string substituting all the occurrences of the set of
     2  * characters specified in the 'from' string to the corresponding character
     3  * in the 'to' array.
     4  *
     5  * 将字符串 s 中,
     6  * 所有在 from 中出现的字符,替换成 to 中的字符
     7  *
     8  * For instance: sdsmapchars(mystring, "ho", "01", 2)
     9  * will have the effect of turning the string "hello" into "0ell1".
    10  *
    11  * 比如调用 sdsmapchars(mystring, "ho", "01", 2)
    12  * 就会将 "hello" 转换为 "0ell1"
    13  *
    14  * The function returns the sds string pointer, that is always the same
    15  * as the input pointer since no resize is needed. 
    16  * 因为无须对 sds 进行大小调整,
    17  * 所以返回的 sds 输入的 sds 一样
    18  *
    19  * T = O(N^2)
    20  */
    21 sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen) {
    22     size_t j, i, l = sdslen(s);
    23 
    24     // 遍历输入字符串
    25     for (j = 0; j < l; j++) {
    26         // 遍历映射
    27         for (i = 0; i < setlen; i++) {
    28             // 替换字符串
    29             if (s[j] == from[i]) {
    30                 s[j] = to[i];
    31                 break;
    32             }
    33         }
    34     }
    35     return s;
    36 }

    2、sdstrim

    /*
     * 对 sds 左右两端进行修剪,清除其中 cset 指定的所有字符
     *
     * 比如 sdsstrim(xxyyabcyyxy, "xy") 将返回 "abc"
     *
     * 复杂性:
     *  T = O(M*N),M 为 SDS 长度, N 为 cset 长度。
     */
    /* Remove the part of the string from left and from right composed just of
     * contiguous characters found in 'cset', that is a null terminted C string.
     *
     * 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.
     *
     * Example:
     *
     * s = sdsnew("AA...AA.a.aa.aHelloWorld     :::");
     * s = sdstrim(s,"A. :");
     * printf("%s
    ", s);
     *
     * Output will be just "Hello World".
     */
    
    /*
    惰性空间释放
    
    惰性空间释放用于优化 SDS 的字符串缩短操作: 当 SDS 的 API 需要缩短 SDS 保存的字符串时,
    程序并不立即使用内存重分配来回收缩短后多出来的字节, 
    而是使用 free 属性将这些字节的数量记录起来, 并等待将来使用。
    
    举个例子, sdstrim 函数接受一个 SDS 和一个 C 字符串作为参数,
    从 SDS 左右两端分别移除所有在 C 字符串中出现过的字符。
    */
    //把释放的字符串字节数添加到free中,凭借free和len就可以有效管理空间
    
    //接受一个 SDS 和一个 C 字符串作为参数, 从 SDS 左右两端分别移除所有在 C 字符串中出现过的字符。
    
    sds sdstrim(sds s, const char *cset) {
        struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
        char *start, *end, *sp, *ep;
        size_t len;
    
        // 设置和记录指针
        sp = start = s;
        ep = end = s+sdslen(s)-1;
    
        // 修剪, T = O(N^2)
        /***
         * 函数原型:extern char *strchr(char *str,char character)
         * 参数说明:str为一个字符串的指针,character为一个待查找字符。
         * 所在库名:#include <string.h>
           * 函数功能:从字符串str中寻找字符character第一次出现的位置。
           * 返回说明:返回指向第一次出现字符character位置的指针,如果没找到则返回NULL。
         * 其它说明:还有一种格式char *strchr( const char *string, int c ),这里字符串是以int型给出的。
         *
         * cset是我们要在首尾trim的字符串 在原始字符串里面的首尾分别取一个字符判断是否在cset中
         * 双指针操作去找到最后有效的首尾指针的地址
         ***/
        while(sp <= end && strchr(cset, *sp)) sp++;
        while(ep > start && strchr(cset, *ep)) ep--;
    
        // 计算 trim 完毕之后剩余的字符串长度
        len = (sp > ep) ? 0 : ((ep-sp)+1);
        
        // 如果有需要,前移字符串内容
        // T = O(N)
        if (sh->buf != sp) memmove(sh->buf, sp, len);
    
        // 添加终结符
        sh->buf[len] = '';
    
        // 更新属性
        sh->free = sh->free+(sh->len-len);
        sh->len = len;
    
        // 返回修剪后的 sds
        return s;
    }

    3、sdsll2str

     1 int sdsll2str(char *s, long long value) {
     2     char *p, aux;
     3     unsigned long long v;
     4     size_t l;
     5 
     6     /* Generate the string representation, this method produces
     7      * 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 
    16     /* Compute length and add null term. */
    17     l = p-s;
    18     *p = '';
    19 
    20     /* Reverse the string. */
    21     p--;
    22     while(s < p) {
    23         aux = *s;
    24         *s = *p;
    25         *p = aux;
    26         s++;
    27         p--;
    28     }
    29     return l;
    30 }

    4、sdssplitlen

     1 /* Split 's' with separator in 'sep'. An array
     2  * of sds strings is returned. *count will be set
     3  * by reference to the number of tokens returned.
     4  *
     5  * 使用分隔符 sep 对 s 进行分割,返回一个 sds 字符串的数组。
     6  * *count 会被设置为返回数组元素的数量。
     7  *
     8  * On out of memory, zero length string, zero length
     9  * separator, NULL is returned.
    10  *
    11  * 如果出现内存不足、字符串长度为 0 或分隔符长度为 0
    12  * 的情况,返回 NULL
    13  *
    14  * Note that 'sep' is able to split a string using
    15  * a multi-character separator. For example
    16  * sdssplit("foo_-_bar","_-_"); will return two
    17  * elements "foo" and "bar".
    18  *
    19  * 注意分隔符可以的是包含多个字符的字符串
    20  *
    21  * This version of the function is binary-safe but
    22  * requires length arguments. sdssplit() is just the
    23  * same function but for zero-terminated strings.
    24  *
    25  * 这个函数接受 len 参数,因此它是二进制安全的。
    26  * (文档中提到的 sdssplit() 已废弃)
    27  *
    28  * T = O(N^2)
    29  */
    30 sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count) {
    31     int elements = 0, slots = 5, start = 0, j;
    32     sds *tokens;
    33 
    34     if (seplen < 1 || len < 0) return NULL;
    35 
    36     tokens = zmalloc(sizeof(sds)*slots);
    37     if (tokens == NULL) return NULL;
    38 
    39     if (len == 0) {
    40         *count = 0;
    41         return tokens;
    42     }
    43     
    44     // T = O(N^2)
    45     for (j = 0; j < (len-(seplen-1)); j++) {
    46         /* make sure there is room for the next element and the final one */
    47         if (slots < elements+2) {
    48             sds *newtokens;
    49 
    50             slots *= 2;
    51             newtokens = zrealloc(tokens,sizeof(sds)*slots);
    52             if (newtokens == NULL) goto cleanup;
    53             tokens = newtokens;
    54         }
    55         /* search the separator */
    56         // T = O(N)
    57         if ((seplen == 1 && *(s+j) == sep[0]) || (memcmp(s+j,sep,seplen) == 0)) {
    58             tokens[elements] = sdsnewlen(s+start,j-start);
    59             if (tokens[elements] == NULL) goto cleanup;
    60             elements++;
    61             start = j+seplen;
    62             j = j+seplen-1; /* skip the separator */
    63         }
    64     }
    65     /* Add the final element. We are sure there is room in the tokens array. */
    66     tokens[elements] = sdsnewlen(s+start,len-start);
    67     if (tokens[elements] == NULL) goto cleanup;
    68     elements++;
    69     *count = elements;
    70     return tokens;
    71 
    72 cleanup:
    73     {
    74         int i;
    75         for (i = 0; i < elements; i++) sdsfree(tokens[i]);
    76         zfree(tokens);
    77         *count = 0;
    78         return NULL;
    79     }
    80 }
  • 相关阅读:
    我爱Java系列之---【SpringBoot打成war包部署】
    279. Perfect Squares
    矩阵dfs--走回路
    112. Path Sum
    542. 01 Matrix
    106. Construct Binary Tree from Inorder and Postorder Traversal
    105. Construct Binary Tree from Preorder and Inorder Traversal
    Invert Binary Tree
    563 Binary Tree Tilt
    145 Binary Tree Postorder Traversal
  • 原文地址:https://www.cnblogs.com/abc-begin/p/7530890.html
Copyright © 2011-2022 走看看