Redis源码学习1-sds.c
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Redis源码学习1-sds.c 1/* SDSLib, A C dynamic strings library
2 *
3 * Copyright (c) 2006-2012, Salvatore Sanfilippo <antirez at gmail dot com>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * * Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * * Neither the name of Redis nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without
16 * specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29*/
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <assert.h>
36 #include "sds.h"
37 #include "zmalloc.h"
38
39/*
40 * 根据给定的初始化字符串 init 和字符串长度 initlen
41 * 创建⼀个新的 sds
42 *
43 * 参数
44 * init :初始化字符串指针
45 * initlen :初始化字符串的长度
46 *
47 * 返回值
48 * sds :创建成功返回 sdshdr 相对应的 sds
49 * 创建失败返回 NULL
50 *
51 * 复杂度
52 * T = O(N)
53*/
54/* Create a new sds string with the content specified by the 'init' pointer
55 * and 'initlen'.
56 * If NULL is used for 'init' the string is initialized with zero bytes.
57 *
58 * The string is always null-termined (all the sds strings are, always) so
59 * even if you create an sds string with:
60 *
61 * mystring = sdsnewlen("abc",3");
62 *
63 * You can print the string with printf() as there is an implicit \0 at the
64 * end of the string. However the string is binary safe and can contain
65 * \0 characters in the middle, as the length is stored in the sds header. */
66 sds sdsnewlen(const void *init, size_t initlen) {
67
68struct sdshdr *sh;
69
70// 根据是否有初始化内容,选择适当的内存分配⽅式
71// T = O(N)
72if (init) {
73// zmalloc 不初始化所分配的内存
74 sh = zmalloc(sizeof(struct sdshdr)+initlen+1);
75 } else {
76// zcalloc 将分配的内存全部初始化为 0
81if (sh == NULL) return NULL;
82
83// 设置初始化长度
84 sh->len = initlen;
85// 新 sds 不预留任何空间
86 sh->free = 0;
87// 如果有指定初始化内容,将它们复制到 sdshdr 的 buf 中
88// T = O(N)
89if (initlen && init)
90 memcpy(sh->buf, init, initlen);
91// 以 \0 结尾
92 sh->buf[initlen] = '\0';
93
94// 返回 buf 部分,⽽不是整个 sdshdr
95return (char*)sh->buf;
96 }
97
98/*
99 * 创建并返回⼀个只保存了空字符串 "" 的 sds
100 *
101 * 返回值
102 * sds :创建成功返回 sdshdr 相对应的 sds
103 * 创建失败返回 NULL
104 *
105 * 复杂度
106 * T = O(1)
107*/
108/* Create an empty (zero length) sds string. Even in this case the string 109 * always has an implicit null term. */
110 sds sdsempty(void) {
111return sdsnewlen("",0);
112 }
113
114/*
115 * 根据给定字符串 init ,创建⼀个包含同样字符串的 sds
116 *
117 * 参数
118 * init :如果输⼊为 NULL ,那么创建⼀个空⽩ sds
119 * 否则,新创建的 sds 中包含和 init 内容相同字符串
120 *
121 * 返回值
122 * sds :创建成功返回 sdshdr 相对应的 sds
123 * 创建失败返回 NULL
124 *
125 * 复杂度
126 * T = O(N)
127*/
128/* Create a new sds string starting from a null termined C string. */
129 sds sdsnew(const char *init) {
130 size_t initlen = (init == NULL) ? 0 : strlen(init);
131return sdsnewlen(init, initlen);
132 }
133
134/*
135 * 复制给定 sds 的副本
136 *
137 * 返回值
138 * sds :创建成功返回输⼊ sds 的副本
139 * 创建失败返回 NULL
140 *
141 * 复杂度
142 * T = O(N)
143*/
144/* Duplicate an sds string. */
145 sds sdsdup(const sds s) {
146return sdsnewlen(s, sdslen(s));
147 }
148
149/*
150 * 释放给定的 sds
151 *
152 * 复杂度
153 * T = O(N)
154*/
155/* Free an sds string. No operation is performed if 's' is NULL. */
156void sdsfree(sds s) {
157if (s == NULL) return;
158 zfree(s-sizeof(struct sdshdr));
159 }
160
165 * This function is useful when the sds string is hacked manually in some
166 * way, like in the following example:
167 *
168 * s = sdsnew("foobar");
169 * s[2] = '\0';
170 * sdsupdatelen(s);
171 * printf("%d\n", sdslen(s));
172 *
173 * The output will be "2", but if we comment out the call to sdsupdatelen()
174 * the output will be "6" as the string was modified but the logical length
175 * remains 6 bytes. */
176void sdsupdatelen(sds s) {
177struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
178int reallen = strlen(s);
179 sh->free += (sh->len-reallen);
180 sh->len = reallen;
181 }
182
183/*
184 * 在不释放 SDS 的字符串空间的情况下,(通过惰性空间释放策略, SDS 避免了缩短字符串时所需的内存重分配操作,并为将来可能有的增长操作提供了优化。
) 185 * 重置 SDS 所保存的字符串为空字符串。
186 *
187 * 复杂度
188 * T = O(1)
189*/
190/* Modify an sds string on-place to make it empty (zero length).
191 * However all the existing buffer is not discarded but set as free space
192 * so that next append operations will not require allocations up to the
193 * number of bytes previously available. */
194void sdsclear(sds s) {
195
196// 取出 sdshdr
197struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
198
199// 重新计算属性
200 sh->free += sh->len;
201 sh->len = 0;
202
203// 将结束符放到最前⾯(相当于惰性地删除 buf 中的内容)
204 sh->buf[0] = '\0';
205 }
206
207/* Enlarge the free space at the end of the sds string so that the caller
208 * is sure that after calling this function can overwrite up to addlen
209 * bytes after the end of the string, plus one more byte for nul term.
210 *
211 * Note: this does not change the *length* of the sds string as returned
212 * by sdslen(), but only the free buffer space we have. */
213/*
214 * 对 sds 中 buf 的长度进⾏扩展,确保在函数执⾏之后,
215 * buf ⾄少会有 addlen + 1 长度的空余空间
216 * (额外的 1 字节是为 \0 准备的)
217 *
218 * 返回值
219 * sds :扩展成功返回扩展后的 sds
220 * 扩展失败返回 NULL
221 *
222 * 复杂度
223 * T = O(N)
224*/
225 sds sdsMakeRoomFor(sds s, size_t addlen) {
226
227struct sdshdr *sh, *newsh;
228
229// 获取 s ⽬前的空余空间长度
230 size_t free = sdsavail(s);
231
232 size_t len, newlen;
233
234// s ⽬前的空余空间已经⾜够,⽆须再进⾏扩展,直接返回
235if (free >= addlen) return s;
236
237// 获取 s ⽬前已占⽤空间的长度
238 len = sdslen(s);
239 sh = (void*) (s-(sizeof(struct sdshdr)));
240
241// s 最少需要的长度
242 newlen = (len+addlen);
243
244// 根据新长度,为 s 分配新空间所需的⼤⼩
249else
250// 否则,分配长度为⽬前长度加上 SDS_MAX_PREALLOC
251 newlen += SDS_MAX_PREALLOC;
252// T = O(N)
253 newsh = zrealloc(sh, sizeof(struct sdshdr)+newlen+1);
254
255// 内存不⾜,分配失败,返回
256if (newsh == NULL) return NULL;
257
258// 更新 sds 的空余长度
259 newsh->free = newlen - len;
260
261// 返回 sds
262return newsh->buf;
263 }
264
265/*
266 * 回收 sds 中的空闲空间,
267 * 回收不会对 sds 中保存的字符串内容做任何修改。
268 *
269 * 返回值
270 * sds :内存调整后的 sds
271 *
272 * 复杂度
273 * T = O(N)
274*/
275/* Reallocate the sds string so that it has no free space at the end. The
276 * contained string remains not altered, but next concatenation operations
277 * will require a reallocation.
278 *
279 * After the call, the passed sds string is no longer valid and all the
280 * references must be substituted with the new pointer returned by the call. */ 281 sds sdsRemoveFreeSpace(sds s) {
282struct sdshdr *sh;
283
284 sh = (void*) (s-(sizeof(struct sdshdr)));
285
286// 进⾏内存重分配,让 buf 的长度仅仅⾜够保存字符串内容
287// T = O(N)
288 sh = zrealloc(sh, sizeof(struct sdshdr)+sh->len+1);
289
290// 空余空间为 0
291 sh->free = 0;
292
293return sh->buf;
294 }
295
296/*
297 * 返回给定 sds 分配的内存字节数
298 *
299 * 复杂度
300 * T = O(1)
301*/
302/* Return the total size of the allocation of the specifed sds string,
303 * including:
304 * 1) The sds header before the pointer.
305 * 2) The string.
306 * 3) The free buffer at the end if any.
307 * 4) The implicit null term.
308*/
309 size_t sdsAllocSize(sds s) {
310struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
311
312return sizeof(*sh)+sh->len+sh->free+1;
313 }
314
315/* Increment the sds length and decrements the left free space at the
316 * end of the string according to 'incr'. Also set the null term
317 * in the new end of the string.
318 *
319 * 根据 incr 参数,增加 sds 的长度,缩减空余空间,
320 * 并将 \0 放到新字符串的尾端
321 *
322 * This function is used in order to fix the string length after the
323 * user calls sdsMakeRoomFor(), writes something after the end of
324 * the current string, and finally needs to set the new length.
325 *
326 * 这个函数是在调⽤ sdsMakeRoomFor() 对字符串进⾏扩展,
327 * 然后⽤户在字符串尾部写⼊了某些内容之后,
328 * ⽤来正确更新 free 和 len 属性的。
333 * 如果 incr 参数为负数,那么对字符串进⾏右截断操作。
334 *
335 * Usage example:
336 *
337 * Using sdsIncrLen() and sdsMakeRoomFor() it is possible to mount the 338 * following schema, to cat bytes coming from the kernel to the end of an 339 * sds string without copying into an intermediate buffer:
340 *
341 * 以下是 sdsIncrLen 的⽤例:
342 *
343 * oldlen = sdslen(s);
344 * s = sdsMakeRoomFor(s, BUFFER_SIZE);
345 * nread = read(fd, s+oldlen, BUFFER_SIZE);
346 * ... check for nread <= 0 and handle it ...
347 * sdsIncrLen(s, nread);
348 *
349 * 复杂度
350 * T = O(1)
351*/
352void sdsIncrLen(sds s, int incr) {
353struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
354
355// 确保 sds 空间⾜够
356 assert(sh->free >= incr);
357
358// 更新属性
359 sh->len += incr;
360 sh->free -= incr;
361
362// 这个 assert 其实可以忽略
363// 因为前⼀个 assert 已经确保 sh->free - incr >= 0 了
364 assert(sh->free >= 0);
365
366// 放置新的结尾符号
367 s[sh->len] = '\0';
368 }
369
370/* Grow the sds to have the specified length. Bytes that were not part of 371 * the original length of the sds will be set to zero.
372 *
373 * if the specified length is smaller than the current length, no operation 374 * is performed. */
375/*
376 * 将 sds 扩充⾄指定长度,未使⽤的空间以 0 字节填充。
377 *
378 * 返回值
379 * sds :扩充成功返回新 sds ,失败返回 NULL
380 *
381 * 复杂度:
382 * T = O(N)
383*/
384 sds sdsgrowzero(sds s, size_t len) {
385struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));
386 size_t totlen, curlen = sh->len;
387
388// 如果 len ⽐字符串的现有长度⼩,
389// 那么直接返回,不做动作
390if (len <= curlen) return s;
391
392// 扩展 sds
393// T = O(N)
394 s = sdsMakeRoomFor(s,len-curlen);
395// 如果内存不⾜,直接返回
396if (s == NULL) return NULL;
397
398/* Make sure added region doesn't contain garbage */
399// 将新分配的空间⽤ 0 填充,防⽌出现垃圾内容
400// T = O(N)
401 sh = (void*)(s-(sizeof(struct sdshdr)));
402 memset(s+curlen,0,(len-curlen+1)); /* also set trailing \0 byte */
403
404// 更新属性
405 totlen = sh->len+sh->free;
406 sh->len = len;
407 sh->free = totlen-sh->len;
408
409// 返回新的 sds
410return s;
411 }
412
419 * 复杂度
420 * T = O(N)
421*/
422/* Append the specified binary-safe string pointed by 't' of 'len' bytes to the 423 * end of the specified sds string 's'.
424 *
425 * After the call, the passed sds string is no longer valid and all the
426 * references must be substituted with the new pointer returned by the call. */ 427 sds sdscatlen(sds s, const void *t, size_t len) {
428
429struct sdshdr *sh;
430
431// 原有字符串长度
432 size_t curlen = sdslen(s);
433
434// 扩展 sds 空间
435// T = O(N)
436 s = sdsMakeRoomFor(s,len);
437
438// 内存不⾜?直接返回
439if (s == NULL) return NULL;
440
441// 复制 t 中的内容到字符串后部
442// T = O(N)
443 sh = (void*) (s-(sizeof(struct sdshdr)));
444 memcpy(s+curlen, t, len);
445
446// 更新属性
447 sh->len = curlen+len;
448 sh->free = sh->free-len;
449
450// 添加新结尾符号
451 s[curlen+len] = '\0';
452
453// 返回新 sds
454return s;
455 }
456
457/*
458 * 将给定字符串 t 追加到 sds 的末尾
459 *
460 * 返回值
461 * sds :追加成功返回新 sds ,失败返回 NULL
462 *
463 * 复杂度
464 * T = O(N)
465*/
466/* Append the specified null termianted C string to the sds string 's'.
467 *
468 * After the call, the passed sds string is no longer valid and all the
469 * references must be substituted with the new pointer returned by the call. */ 470 sds sdscat(sds s, const char *t) {
471return sdscatlen(s, t, strlen(t));
472 }
473
474/*
475 * 将另⼀个 sds 追加到⼀个 sds 的末尾
476 *
477 * 返回值
478 * sds :追加成功返回新 sds ,失败返回 NULL
479 *
480 * 复杂度
481 * T = O(N)
482*/
483/* Append the specified sds 't' to the existing sds 's'.
484 *
485 * After the call, the modified sds string is no longer valid and all the
486 * references must be substituted with the new pointer returned by the call. */ 487 sds sdscatsds(sds s, const sds t) {
488return sdscatlen(s, t, sdslen(t));
489 }
490
491/*
492 * 将字符串 t 的前 len 个字符复制到 sds s 当中,
493 * 并在字符串的最后添加终结符。
494 *
495 * 如果 sds 的长度少于 len 个字符,那么扩展 sds
496 *
503/* Destructively modify the sds string 's' to hold the specified binary
504 * safe string pointed by 't' of length 'len' bytes. */
505 sds sdscpylen(sds s, const char *t, size_t len) {
506
507struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
508
509// sds 现有 buf 的长度
510 size_t totlen = sh->free+sh->len;
511
512// 如果 s 的 buf 长度不满⾜ len ,那么扩展它
513if (totlen < len) {
514// T = O(N)
515 s = sdsMakeRoomFor(s,len-sh->len);
516if (s == NULL) return NULL;
517 sh = (void*) (s-(sizeof(struct sdshdr)));
518 totlen = sh->free+sh->len;
519 }
520
521// 复制内容
522// T = O(N)
523 memcpy(s, t, len);
524
525// 添加终结符号
526 s[len] = '\0';
527
528// 更新属性
529 sh->len = len;
530 sh->free = totlen-len;
531
532// 返回新的 sds
533return s;
534 }
535
536/*
537 * 将字符串复制到 sds 当中,
538 * 覆盖原有的字符。
539 *
540 * 如果 sds 的长度少于字符串的长度,那么扩展 sds 。
541 *
542 * 复杂度
543 * T = O(N)
544 *
545 * 返回值
546 * sds :复制成功返回新的 sds ,否则返回 NULL
547*/
548/* Like sdscpylen() but 't' must be a null-termined string so that the length 549 * of the string is obtained with strlen(). */
550 sds sdscpy(sds s, const char *t) {
551return sdscpylen(s, t, strlen(t));
552 }
553
554/* Helper for sdscatlonglong() doing the actual number -> string
555 * conversion. 's' must point to a string with room for at least
556 * SDS_LLSTR_SIZE bytes.
557 *
558 * The function returns the lenght of the null-terminated string
559 * representation stored at 's'. */
560#define SDS_LLSTR_SIZE 21
561int sdsll2str(char *s, long long value) {
562char *p, aux;
563 unsigned long long v;
564 size_t l;
565
566/* Generate the string representation, this method produces
567 * an reversed string. */
568 v = (value < 0) ? -value : value;
569 p = s;
570do {
571 *p++ = '0'+(v%10);
572 v /= 10;
573 } while(v);
574if (value < 0) *p++ = '-';
575
576/* Compute length and add null term. */
577 l = p-s;
578 *p = '\0';
579
580/* Reverse the string. */
585 *p = aux;
586 s++;
587 p--;
588 }
589return l;
590 }
591
592/* Identical sdsll2str(), but for unsigned long long type. */
593int sdsull2str(char *s, unsigned long long v) {
594char *p, aux;
595 size_t l;
596
597/* Generate the string representation, this method produces
598 * an reversed string. */
599 p = s;
600do {
601 *p++ = '0'+(v%10);
602 v /= 10;
603 } while(v);
604
605/* Compute length and add null term. */
606 l = p-s;
607 *p = '\0';
608
609/* Reverse the string. */
610 p--;
611while(s < p) {
612 aux = *s;
613 *s = *p;
614 *p = aux;
615 s++;
616 p--;
617 }
618return l;
619 }
620
621/* Create an sds string from a long long value. It is much faster than: 622 *
623 * sdscatprintf(sdsempty(),"%lld\n", value);
624*/
625// 根据输⼊的 long long 值 value ,创建⼀个 SDS
626 sds sdsfromlonglong(long long value) {
627char buf[SDS_LLSTR_SIZE];
628int len = sdsll2str(buf,value);
629
630return sdsnewlen(buf,len);
631 }
632
633/*
634 * 打印函数,被 sdscatprintf 所调⽤
635 *
636 * T = O(N^2)
637*/
638/* Like sdscatpritf() but gets va_list instead of being variadic. */
639 sds sdscatvprintf(sds s, const char *fmt, va_list ap) {
640 va_list cpy;
641char staticbuf[1024], *buf = staticbuf, *t;
642 size_t buflen = strlen(fmt)*2;
643
644/* We try to start using a static buffer for speed.
645 * If not possible we revert to heap allocation. */
646if (buflen > sizeof(staticbuf)) {
647 buf = zmalloc(buflen);
648if (buf == NULL) return NULL;
649 } else {
650 buflen = sizeof(staticbuf);
651 }
652
653/* Try with buffers two times bigger every time we fail to
654 * fit the string in the current buffer size. */
655while(1) {
656 buf[buflen-2] = '\0';
657 va_copy(cpy,ap);
658// T = O(N)
659 vsnprintf(buf, buflen, fmt, cpy);
660if (buf[buflen-2] != '\0') {
661if (buf != staticbuf) zfree(buf);
662 buflen *= 2;
663 buf = zmalloc(buflen);
664if (buf == NULL) return NULL;
669
670/* Finally concat the obtained string to the SDS string and return it. */ 671 t = sdscat(s, buf);
672if (buf != staticbuf) zfree(buf);
673return t;
674 }
675
676/*
677 * 打印任意数量个字符串,并将这些字符串追加到给定 sds 的末尾
678 *
679 * T = O(N^2)
680*/
681/* Append to the sds string 's' a string obtained using printf-alike format
682 * specifier.
683 *
684 * After the call, the modified sds string is no longer valid and all the
685 * references must be substituted with the new pointer returned by the call. 686 *
687 * Example:
688 *
689 * s = sdsempty("Sum is: ");
690 * s = sdscatprintf(s,"%d+%d = %d",a,b,a+b).
691 *
692 * Often you need to create a string from scratch with the printf-alike
693 * format. When this is the need, just use sdsempty() as the target string: 694 *
695 * s = sdscatprintf(sdsempty(), "... your format ...", args);
696*/
697 sds sdscatprintf(sds s, const char *fmt, ...) {
698 va_list ap;
699char *t;
700 va_start(ap, fmt);
701// T = O(N^2)
702 t = sdscatvprintf(s,fmt,ap);
703 va_end(ap);
704return t;
705 }
706
707/* This function is similar to sdscatprintf, but much faster as it does
708 * not rely on sprintf() family functions implemented by the libc that
709 * are often very slow. Moreover directly handling the sds string as
710 * new data is concatenated provides a performance improvement.
711 *
712 * However this function only handles an incompatible subset of printf-alike 713 * format specifiers:
714 *
715 * %s - C String
716 * %S - SDS string
717 * %i - signed int
718 * %I - 64 bit signed integer (long long, int64_t)
719 * %u - unsigned int
720 * %U - 64 bit unsigned integer (unsigned long long, uint64_t)
721 * %% - Verbatim "%" character.
722*/
723 sds sdscatfmt(sds s, char const *fmt, ...) {
724struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
725 size_t initlen = sdslen(s);
726const char *f = fmt;
727int i;
728 va_list ap;
729
730 va_start(ap,fmt);
731 f = fmt; /* Next format specifier byte to process. */
732 i = initlen; /* Position of the next byte to write to dest str. */
733while(*f) {
734char next, *str;
735 size_t l;
736long long num;
737 unsigned long long unum;
738
739/* Make sure there is always space for at least 1 char. */
740if (sh->free == 0) {
741 s = sdsMakeRoomFor(s,1);
742 sh = (void*) (s-(sizeof(struct sdshdr)));
743 }
744
745switch(*f) {
746case'%':
747 next = *(f+1);
748 f++;
753 l = (next == 's') ? strlen(str) : sdslen(str);
754if (sh->free < l) {
755 s = sdsMakeRoomFor(s,l);
756 sh = (void*) (s-(sizeof(struct sdshdr)));
757 }
758 memcpy(s+i,str,l);
759 sh->len += l;
760 sh->free -= l;
761 i += l;
762break;
763case'i':
764case'I':
765if (next == 'i')
766 num = va_arg(ap,int);
767else
768 num = va_arg(ap,long long);
769 {
770char buf[SDS_LLSTR_SIZE];
771 l = sdsll2str(buf,num);
772if (sh->free < l) {
773 s = sdsMakeRoomFor(s,l);
774 sh = (void*) (s-(sizeof(struct sdshdr)));
775 }
776 memcpy(s+i,buf,l);
777 sh->len += l;
778 sh->free -= l;
779 i += l;
780 }
781break;
782case'u':
783case'U':
784if (next == 'u')
785 unum = va_arg(ap,unsigned int);
786else
787 unum = va_arg(ap,unsigned long long);
788 {
789char buf[SDS_LLSTR_SIZE];
790 l = sdsull2str(buf,unum);
791if (sh->free < l) {
792 s = sdsMakeRoomFor(s,l);
793 sh = (void*) (s-(sizeof(struct sdshdr)));
794 }
795 memcpy(s+i,buf,l);
796 sh->len += l;
797 sh->free -= l;
798 i += l;
799 }
800break;
801default: /* Handle %% and generally %<unknown>. */
802 s[i++] = next;
803 sh->len += 1;
804 sh->free -= 1;
805break;
806 }
807break;
808default:
809 s[i++] = *f;
810 sh->len += 1;
811 sh->free -= 1;
812break;
813 }
814 f++;
815 }
816 va_end(ap);
817
818/* Add null-term */
819 s[i] = '\0';
820return s;
821 }
822
823/*
824 * 对 sds 左右两端进⾏修剪,清除其中 cset 指定的所有字符
825 *
826 * ⽐如 sdsstrim(xxyyabcyyxy, "xy") 将返回 "abc"
827 *
828 * 复杂性:
829 * T = O(M*N),M 为 SDS 长度, N 为 cset 长度。
830*/
831/* Remove the part of the string from left and from right composed just of 832 * contiguous characters found in 'cset', that is a null terminted C string.
837 * Example:
838 *
839 * s = sdsnew("AA...AA.a.aa.aHelloWorld :::");
840 * s = sdstrim(s,"A. :");
841 * printf("%s\n", s);
842 *
843 * Output will be just "Hello World".
844*/
845 sds sdstrim(sds s, const char *cset) {
846struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
847char *start, *end, *sp, *ep;
848 size_t len;
849
850// 设置和记录指针
851 sp = start = s;
852 ep = end = s+sdslen(s)-1;
853
854// 修剪, T = O(N^2)
855while(sp <= end && strchr(cset, *sp)) sp++;
856while(ep > start && strchr(cset, *ep)) ep--;
857
858// 计算 trim 完毕之后剩余的字符串长度
859 len = (sp > ep) ? 0 : ((ep-sp)+1);
860
861// 如果有需要,前移字符串内容
862// T = O(N)
863if (sh->buf != sp) memmove(sh->buf, sp, len);
864
865// 添加终结符
866 sh->buf[len] = '\0';
867
868// 更新属性
869 sh->free = sh->free+(sh->len-len);
870 sh->len = len;
871
872// 返回修剪后的 sds
873return s;
874 }
875
876/*
877 * 按索引对截取 sds 字符串的其中⼀段
878 * start 和 end 都是闭区间(包含在内)
879 *
880 * 索引从 0 开始,最⼤为 sdslen(s) - 1
881 * 索引可以是负数, sdslen(s) - 1 == -1
882 *
883 * 复杂度
884 * T = O(N)
885*/
886/* Turn the string into a smaller (or equal) string containing only the
887 * substring specified by the 'start' and 'end' indexes.
888 *
889 * start and end can be negative, where -1 means the last character of the 890 * string, -2 the penultimate character, and so forth.
891 *
892 * The interval is inclusive, so the start and end characters will be part
893 * of the resulting string.
894 *
895 * The string is modified in-place.
896 *
897 * Example:
898 *
899 * s = sdsnew("Hello World");
900 * sdsrange(s,1,-1); => "ello World"
901*/
902void sdsrange(sds s, int start, int end) {
903struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
904 size_t newlen, len = sdslen(s);
905
906if (len == 0) return;
907if (start < 0) {
908 start = len+start;
909if (start < 0) start = 0;
910 }
911if (end < 0) {
912 end = len+end;
913if (end < 0) end = 0;
914 }
915 newlen = (start > end) ? 0 : (end-start)+1;
916if (newlen != 0) {
917if (start >= (signed)len) {
918 newlen = 0;
919 } else if (end >= (signed)len) {
920 end = len-1;
921 newlen = (start > end) ? 0 : (end-start)+1;
922 }
923 } else {
924 start = 0;
925 }
926
927// 如果有需要,对字符串进⾏移动
928// T = O(N)
929if (start && newlen) memmove(sh->buf, sh->buf+start, newlen);
930
931// 添加终结符
932 sh->buf[newlen] = 0;
933
934// 更新属性
935 sh->free = sh->free+(sh->len-newlen);
936 sh->len = newlen;
937 }
938
939/*
940 * 将 sds 字符串中的所有字符转换为⼩写
941 *
942 * T = O(N)
943*/
944/* Apply tolower() to every character of the sds string 's'. */
945void sdstolower(sds s) {
946int len = sdslen(s), j;
947
948for (j = 0; j < len; j++) s[j] = tolower(s[j]);
949 }
950
951/*
952 * 将 sds 字符串中的所有字符转换为⼤写
953 *
954 * T = O(N)
955*/
956/* Apply toupper() to every character of the sds string 's'. */
957void sdstoupper(sds s) {
958int len = sdslen(s), j;
959
960for (j = 0; j < len; j++) s[j] = toupper(s[j]);
961 }
962
963/*
964 * 对⽐两个 sds , strcmp 的 sds 版本
965 *
966 * 返回值
967 * int :相等返回 0 ,s1 较⼤返回正数, s2 较⼤返回负数
968 *
969 * T = O(N)
970*/
971/* Compare two sds strings s1 and s2 with memcmp().
972 *
973 * Return value:
974 *
975 * 1 if s1 > s2.
976 * -1 if s1 < s2.
977 * 0 if s1 and s2 are exactly the same binary string.
978 *
979 * If two strings share exactly the same prefix, but one of the two has
980 * additional characters, the longer string is considered to be greater than 981 * the smaller one. */
982int sdscmp(const sds s1, const sds s2) {
983 size_t l1, l2, minlen;
984int cmp;
985
986 l1 = sdslen(s1);
987 l2 = sdslen(s2);
988 minlen = (l1 < l2) ? l1 : l2;
989 cmp = memcmp(s1,s2,minlen);
990
991if (cmp == 0) return l1-l2;
992
993return cmp;
994 }
995
996/* Split 's' with separator in 'sep'. An array
997 * of sds strings is returned. *count will be set
998 * by reference to the number of tokens returned.
999 *
1000 * 使⽤分隔符 sep 对 s 进⾏分割,返回⼀个 sds 字符串的数组。
1001 * *count 会被设置为返回数组元素的数量。
1002 *
1003 * On out of memory, zero length string, zero length
1004 * separator, NULL is returned.。