[SDS阅读理解/6]源码中的函数/3

还有好几个函数,接着讲。

       第十四个。该函数的作用是更新字符串变量的长度,比如我们在这个字符串后面又存了几个字符或删除了几个字符,这时我们就要调用这个函数将新增加的字符个数或减少的字符个数加到头结构体里的长度变量里头。它不会自动更新的,每次更改了字符个数,都需要我们自己更新字符串的实际长度,不然下次使用时可能会出错。这也是一件比较繁琐的事情。代码内容跟前几节讲的差不多,前几节的理解后,这个也容易理解。

// 作者注释
/* 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);
 */

void sdsIncrLen(sds s, int incr) {
    // 获取字符串类型
    unsigned char flags = s[-1];
    size_t len;
    // 判断是什么类型
    switch(flags&SDS_TYPE_MASK) {
        // type 5的不讲
        case SDS_TYPE_5: {
            unsigned char *fp = ((unsigned char*)s)-1;
            unsigned char oldlen = SDS_TYPE_5_LEN(flags);
            assert((incr > 0 && oldlen+incr < 32) || (incr < 0 && oldlen >= (unsigned int)(-incr)));
            *fp = SDS_TYPE_5 | ((oldlen+incr) << SDS_TYPE_BITS);
            len = oldlen+incr;
            break;
        }
        // 如果是type 8的
        case SDS_TYPE_8: {
            // 定义一个对应类型的结构体指针。该宏的原理在宏那节有讲
            SDS_HDR_VAR(8,s);
            // 断言。作用就是假设里面的内容是成立的才执行后面的代码
            // 否则程序就中断。||前面是假设增加的个数是合理的,||后
            // 面是假设减少的个数是合理的
            assert((incr >= 0 && sh->alloc-sh->len >= incr) || (incr < 0 && sh->len >= (unsigned int)(-incr)));
            // 结构体里头的长度变量加上增加的个数或加上减少的个数(加上一个负数)
            len = (sh->len += incr);
            break;
        }
        // 原理如上
        case SDS_TYPE_16: {
            SDS_HDR_VAR(16,s);
            assert((incr >= 0 && sh->alloc-sh->len >= incr) || (incr < 0 && sh->len >= (unsigned int)(-incr)));
            len = (sh->len += incr);
            break;
        }
        // 原理如上
        case SDS_TYPE_32: {
            SDS_HDR_VAR(32,s);
            assert((incr >= 0 && sh->alloc-sh->len >= (unsigned int)incr) || (incr < 0 && sh->len >= (unsigned int)(-incr)));
            len = (sh->len += incr);
            break;
        }
        // 原理如上
        case SDS_TYPE_64: {
            SDS_HDR_VAR(64,s);
            assert((incr >= 0 && sh->alloc-sh->len >= (uint64_t)incr) || (incr < 0 && sh->len >= (uint64_t)(-incr)));
            len = (sh->len += incr);
            break;
        }
        // 如果都不是上面中的一种类型
        default: len = 0; /* Just to avoid compilation warnings. */
    }
    // 设置结尾符
    s[len] = '\0';
}

       第十五个。该函数的作用是为字符串变量增加空间并将新增空间里头的内容初始化为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. */

sds sdsgrowzero(sds s, size_t len) {
    // 获取字符串的原始长度
    size_t curlen = sdslen(s);

    // 如果传入的长度小于等于原始长度,就没必要增加空间了
    if (len <= curlen) return s;
    // 否则调用下面的函数为字符串增加空间。是传入的长度减去原始长度
    // 不是直接就是传入的长度。函数的原理前面章节有讲
    s = sdsMakeRoomFor(s,len-curlen);
    // 如果申请空间失败,返回NULL
    if (s == NULL) return NULL;

    /* Make sure added region doesn't contain garbage */
    // 调用memset()函数将新增加的空间初始化为0
    // s+curlen就是指针偏移,s本来指向字符串的首地址,加上原始
    // 长度后就是后面新增空间的首地址。记得还有一个结尾符
    memset(s+curlen,0,(len-curlen+1)); /* also set trailing \0 byte */
    // 调用下面的函数设置字符串的长度。函数原理前面章节有讲
    sdssetlen(s, len);
    return s;
}

       第十六个。该函数的作用是将t指向的字符串的len个合并到s的后面去。

// 作者注释
/* 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. */

sds sdscatlen(sds s, const void *t, size_t len) {
    // 获取原始长度
    size_t curlen = sdslen(s);

    // 为s新申请空间
    s = sdsMakeRoomFor(s,len);
    // 申请失败则返回
    if (s == NULL) return NULL;
    // 调用memcpy()将t指向的内容拷贝len个到s+curlen指向的空间
    memcpy(s+curlen, t, len);
    // 设置字符串长度
    sdssetlen(s, curlen+len);
    // 设置结尾符
    s[curlen+len] = '\0';
    return s;
}

       第十七个。该函数的作用是将t指向的内容合并到s后面,不需要指定长度。

// 作者注释
/* 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. */

sds sdscat(sds s, const char *t) {
    // 调用上面讲的函数进行拷贝
    return sdscatlen(s, t, strlen(t));
}

       第十八个。该函数的作用是将两个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. */

sds sdscatsds(sds s, const sds t) {
    // 还是调用第十六个函数进行拷贝。sdslen()函数的原理前面章节有讲
    return sdscatlen(s, t, sdslen(t));
}

       今晚先记录到这。:)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值