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)); } ******************************************************************