redis之sds(simple dynamic string)阅读笔记4-sds字符串修改(长度和内容)

redis之sds(simple dynamic string)阅读笔记4-sds字符串修改(长度和内容)
******************************************************************
函数sdsIncrLen负责在调用函数sdsMakeRoomFor之后更新字符串长度
/* 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.
用‘增加’(这个增加应该是变化,即可能是负数)增加sds字符串长度减少字符串末尾的剩余自由空间,
同时也在新字符串的末尾设置/0
 * 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.
在调用函数sdsMakeRoomFor写入一些字符在原字符串的结尾之后,这个函数(sdsIncrLen)用来确认新字符串的长度,
 * 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:
使用函数sdsIncrLen() and sdsMakeRoomFor(),可以完成接下来的模式,
连接从核心来的字符串到末尾而不使用中间缓存

 * oldlen = sdslen(s); //原字符串长度
 * s = sdsMakeRoomFor(s, BUFFER_SIZE);//给增加的字符长度BUFFER_SIZE分配扩大的内存空间
 * nread = read(fd, s+oldlen, BUFFER_SIZE); //从句柄fb中读取BUFFER_SIZE大小的字节到s+oldlen指向的内存空间
 * ... check for nread <= 0 and handle it ...
 * sdsIncrLen(s, nread);//确定新增字符串的结尾
 */
void sdsIncrLen(sds s, ssize_t incr) {
    unsigned char flags = s[-1]; // 获取结构体类型
    size_t len;
    switch(flags&SDS_TYPE_MASK) {  //获取结构体类型,确保低三位
        case SDS_TYPE_5: {
            unsigned char *fp = ((unsigned char*)s)-1; //获取sdshdr5的flags
            unsigned char oldlen = SDS_TYPE_5_LEN(flags); //获取高5位的值,即字符串长度
            assert((incr > 0 && oldlen+incr < 32) || (incr < 0 && oldlen >= (unsigned int)(-incr)));
            // 确认新增长度之后的字符串在结构体定义的长度范围内 0-31
            *fp = SDS_TYPE_5 | ((oldlen+incr) << SDS_TYPE_BITS); // 更新字符串长度
            len = oldlen+incr; //获取新字符串结尾地址
            break;
        }
        case SDS_TYPE_8: {
            SDS_HDR_VAR(8,s); //用宏定义获取结构体指正
            assert((incr >= 0 && sh->alloc-sh->len >= incr) || (incr < 0 && sh->len >= (unsigned int)(-incr)));
            //确认新增长度的字符串所需空间我们已经定义好 sh->alloc-sh->len为剩余空间 ,
            //sh->len >= (unsigned int)(-incr)确保不会小于0
            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'; //给新字符串结尾一个确认
}
******************************************************************
函数sdsgrowzero用来增长sds字符串到指定长度
/* 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.
增加字符串sds到指定的长度,新增的非原字符串字节被设置为0
 * 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); //原字符串小于指定长度, 申请指定长度和原字符串之间的差值
    if (s == NULL) return NULL;
    /* Make sure added region doesn't contain garbage */  
    memset(s+curlen,0,(len-curlen+1)); /* also set trailing \0 byte */
    //确认新增区域不会有垃圾,将新增区域全部设置为0,包括结尾的位置
    sdssetlen(s, len); //设置新字符串的长度
    return s;
}
******************************************************************
函数sdscatlen 将特定字符串添加到原字符串结尾

/* Append the specified binary-safe string pointed by 't' of 'len' bytes to the
 * end of the specified sds string 's'.
添加长度为len字节的二进制安全字符串(t指向这个字符串) 到 sds字符串的结尾
 * 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字符串被释放,所有这个字符串的引用必须要用函数调用返回的新指针代替
 
sds sdscatlen(sds s, const void *t, size_t len) {
    size_t curlen = sdslen(s); //获取原长度

    s = sdsMakeRoomFor(s,len); //为新增字符数组分配空间
    if (s == NULL) return NULL;// 空间分配失败的情况
    memcpy(s+curlen, t, len); //将指针t指向的字符串(长度为len)拷贝到s+curlen开始的位置(即原字符串结尾)
    sdssetlen(s, curlen+len);//设置新字符串的长度
    s[curlen+len] = '\0';// 设置结尾的/0
    return s;
}
******************************************************************
函数sdscat添加特定以/0结尾的字符串到sds字符串
/* 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)); //通过调用sdscatlen完成
}
******************************************************************
函数sdscpylen  将指针t指向的数组整个拷贝到sds中(覆盖原数组)
/* Destructively modify the sds string 's' to hold the specified binary
 * safe string pointed by 't' of length 'len' bytes. */
用安全字符串指针t指向的长度为len字节的字符串破坏性修改原sds字符串(覆盖原字符串)
sds sdscpylen(sds s, const char *t, size_t len) {
    if (sdsalloc(s) < len) { //原sds字符串分配的长度 小于 要拷贝的字符串长度
        s = sdsMakeRoomFor(s,len-sdslen(s)); // 给不足部分的字符串分配内存空间  新字符串长度-原来字符串已使用长度
        if (s == NULL) return NULL;
    }
    memcpy(s, t, len);// 从t拷贝len长的字节到s
    s[len] = '\0'; // 设置结尾符号/0
    sdssetlen(s, len);//设置新字符串的长度
    return s;
}
******************************************************************
函数sdscpy 借用了函数sdscpylen完成了整个字符串的深拷贝
/* Like sdscpylen() but 't' must be a null-termined string so that the length
 * of the string is obtained with strlen(). */
拷贝的字符串t必须要以/0结尾,否则strlen会不可控
sds sdscpy(sds s, const char *t) {
    return sdscpylen(s, t, strlen(t));
}
******************************************************************

 

posted on 2020-07-29 17:17  子虚乌有  阅读(280)  评论(0)    收藏  举报