// 字符串类型的别名 typedef char *sds;
// 持有sds的结构 struct sdshdr { // buf中已经被使用的字符串空间数量 int len; // buf中预留字符串的空间数量 int free; // 实际存储字符串的地方 char buf[]; };
sds sdsnewlen(const void *init, size_t initlen) { struct sdshdr *sh; if (init) { // 创建 sh = malloc(sizeof(struct sdshdr) + initlen + 1); } else { // 重分配 sh = calloc(1, sizeof(struct sdshdr) + initlen + 1); } if (sh == NULL) return NULL; sh->len = initlen; sh->free = 0; // 刚开始free为0 if (initlen && init) { memcpy(sh->buf, init, initlen); } sh->buf[initlen] = '\0'; // 只返回sh->buf这个字符串部分 return (char *)sh->buf; }
static inline size_t sdslen(const sds s) { // 从sds中计算出相应的sdshdr结构 struct sdshdr *sh = (void *)(s - (sizeof(struct sdshdr))); return sh->len; } void sdstoupper(sds s) { int len = sdslen(s), j; for (j = 0; j < len; j ++) s[j] = toupper(s[j]); }
static inline size_t sdsavail(const sds s) { struct sdshdr *sh = (void *)(s - (sizeof(struct sdshdr))); return sh->free; }
sds sdsMakeRoomFor(sds s, size_t addlen) { struct sdshdr *sh, *newsh; size_t free = sdsavail(s); size_t len, newlen; // 预留空间可以满足本地拼接 if (free >= addlen) return s; len = sdslen(s); sh = (void *)(s - (sizeof(struct sdshdr))); // 设置新sds的字符串长度 // 这个长度比完成本次拼接实际所需的长度要大 // 通过预留空间优化下次拼接操作 newlen = (len + addlen); if (newlen < 1024 * 1024) newlen *= 2; else newlen += 1024; // 重新分配sdshdr newsh = realloc(sh, sizeof(struct sdshdr) + newlen + 1); if (newsh == NULL) return NULL; newsh->free = newlen - len; // 只返回字符串部分 return newsh->buf; }
/** * 按长度len扩展sds,并将t拼接到sds的末尾 */ sds sdscatlen(sds s, const void *t, size_t len) { struct sdshdr *sh; size_t curlen = sdslen(s); // O(N) s = sdsMakeRoomFor(s, len); if (s == NULL) return NULL; // 复制 memcpy(s + curlen, t, len); // 更新len和free属性 sh = (void *)(s - (sizeof(struct sdshdr))); sh->len = curlen + len; sh->free = sh->free - len; // 终结符 s[curlen + len] = '\0'; return s; } /** * 将一个char数组拼接到sds 末尾 */ sds sdscat(sds s, const char *t) { return sdscatlen(s, t, strlen(t)); }