首页 > 代码库 > Redis源码学习1-sds.c
Redis源码学习1-sds.c
https://github.com/huangz1990/redis-3.0-annotated/blob/unstable/src/sds.c#L120
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 68 struct sdshdr *sh; 69 70 // 根据是否有初始化内容,选择适当的内存分配方式 71 // T = O(N) 72 if (init) { 73 // zmalloc 不初始化所分配的内存 74 sh = zmalloc(sizeof(struct sdshdr)+initlen+1); 75 } else { 76 // zcalloc 将分配的内存全部初始化为 0 77 sh = zcalloc(sizeof(struct sdshdr)+initlen+1); 78 } 79 80 // 内存分配失败,返回 81 if (sh == NULL) return NULL; 82 83 // 设置初始化长度 84 sh->len = initlen; 85 // 新 sds 不预留任何空间 86 sh->free = 0; 87 // 如果有指定初始化内容,将它们复制到 sdshdr 的 buf 中 88 // T = O(N) 89 if (initlen && init) 90 memcpy(sh->buf, init, initlen); 91 // 以 \0 结尾 92 sh->buf[initlen] = ‘\0‘; 93 94 // 返回 buf 部分,而不是整个 sdshdr 95 return (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) { 111 return 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); 131 return 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) { 146 return 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. */ 156 void sdsfree(sds s) { 157 if (s == NULL) return; 158 zfree(s-sizeof(struct sdshdr)); 159 } 160 161 // 未使用函数,可能已废弃 162 /* Set the sds string length to the length as obtained with strlen(), so 163 * considering as content only up to the first null term character. 164 * 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. */ 176 void sdsupdatelen(sds s) { 177 struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr))); 178 int 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. */ 194 void sdsclear(sds s) { 195 196 // 取出 sdshdr 197 struct 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 227 struct sdshdr *sh, *newsh; 228 229 // 获取 s 目前的空余空间长度 230 size_t free = sdsavail(s); 231 232 size_t len, newlen; 233 234 // s 目前的空余空间已经足够,无须再进行扩展,直接返回 235 if (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 分配新空间所需的大小 245 if (newlen < SDS_MAX_PREALLOC) 246 // 如果新长度小于 SDS_MAX_PREALLOC 247 // 那么为它分配两倍于所需长度的空间 248 newlen *= 2; 249 else 250 // 否则,分配长度为目前长度加上 SDS_MAX_PREALLOC 251 newlen += SDS_MAX_PREALLOC; 252 // T = O(N) 253 newsh = zrealloc(sh, sizeof(struct sdshdr)+newlen+1); 254 255 // 内存不足,分配失败,返回 256 if (newsh == NULL) return NULL; 257 258 // 更新 sds 的空余长度 259 newsh->free = newlen - len; 260 261 // 返回 sds 262 return 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) { 282 struct 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 293 return 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) { 310 struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr))); 311 312 return 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 属性的。 329 * 330 * Note: it is possible to use a negative increment in order to 331 * right-trim the string. 332 * 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 */ 352 void sdsIncrLen(sds s, int incr) { 353 struct 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) { 385 struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr))); 386 size_t totlen, curlen = sh->len; 387 388 // 如果 len 比字符串的现有长度小, 389 // 那么直接返回,不做动作 390 if (len <= curlen) return s; 391 392 // 扩展 sds 393 // T = O(N) 394 s = sdsMakeRoomFor(s,len-curlen); 395 // 如果内存不足,直接返回 396 if (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 410 return s; 411 } 412 413 /* 414 * 将长度为 len 的字符串 t 追加到 sds 的字符串末尾 415 * 416 * 返回值 417 * sds :追加成功返回新 sds ,失败返回 NULL 418 * 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 429 struct sdshdr *sh; 430 431 // 原有字符串长度 432 size_t curlen = sdslen(s); 433 434 // 扩展 sds 空间 435 // T = O(N) 436 s = sdsMakeRoomFor(s,len); 437 438 // 内存不足?直接返回 439 if (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 454 return 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) { 471 return 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) { 488 return sdscatlen(s, t, sdslen(t)); 489 } 490 491 /* 492 * 将字符串 t 的前 len 个字符复制到 sds s 当中, 493 * 并在字符串的最后添加终结符。 494 * 495 * 如果 sds 的长度少于 len 个字符,那么扩展 sds 496 * 497 * 复杂度 498 * T = O(N) 499 * 500 * 返回值 501 * sds :复制成功返回新的 sds ,否则返回 NULL 502 */ 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 507 struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr))); 508 509 // sds 现有 buf 的长度 510 size_t totlen = sh->free+sh->len; 511 512 // 如果 s 的 buf 长度不满足 len ,那么扩展它 513 if (totlen < len) { 514 // T = O(N) 515 s = sdsMakeRoomFor(s,len-sh->len); 516 if (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 533 return 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) { 551 return 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 561 int sdsll2str(char *s, long long value) { 562 char *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; 570 do { 571 *p++ = ‘0‘+(v%10); 572 v /= 10; 573 } while(v); 574 if (value < 0) *p++ = ‘-‘; 575 576 /* Compute length and add null term. */ 577 l = p-s; 578 *p = ‘\0‘; 579 580 /* Reverse the string. */ 581 p--; 582 while(s < p) { 583 aux = *s; 584 *s = *p; 585 *p = aux; 586 s++; 587 p--; 588 } 589 return l; 590 } 591 592 /* Identical sdsll2str(), but for unsigned long long type. */ 593 int sdsull2str(char *s, unsigned long long v) { 594 char *p, aux; 595 size_t l; 596 597 /* Generate the string representation, this method produces 598 * an reversed string. */ 599 p = s; 600 do { 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--; 611 while(s < p) { 612 aux = *s; 613 *s = *p; 614 *p = aux; 615 s++; 616 p--; 617 } 618 return 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) { 627 char buf[SDS_LLSTR_SIZE]; 628 int len = sdsll2str(buf,value); 629 630 return 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; 641 char 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. */ 646 if (buflen > sizeof(staticbuf)) { 647 buf = zmalloc(buflen); 648 if (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. */ 655 while(1) { 656 buf[buflen-2] = ‘\0‘; 657 va_copy(cpy,ap); 658 // T = O(N) 659 vsnprintf(buf, buflen, fmt, cpy); 660 if (buf[buflen-2] != ‘\0‘) { 661 if (buf != staticbuf) zfree(buf); 662 buflen *= 2; 663 buf = zmalloc(buflen); 664 if (buf == NULL) return NULL; 665 continue; 666 } 667 break; 668 } 669 670 /* Finally concat the obtained string to the SDS string and return it. */ 671 t = sdscat(s, buf); 672 if (buf != staticbuf) zfree(buf); 673 return 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; 699 char *t; 700 va_start(ap, fmt); 701 // T = O(N^2) 702 t = sdscatvprintf(s,fmt,ap); 703 va_end(ap); 704 return 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, ...) { 724 struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr))); 725 size_t initlen = sdslen(s); 726 const char *f = fmt; 727 int 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. */ 733 while(*f) { 734 char next, *str; 735 size_t l; 736 long long num; 737 unsigned long long unum; 738 739 /* Make sure there is always space for at least 1 char. */ 740 if (sh->free == 0) { 741 s = sdsMakeRoomFor(s,1); 742 sh = (void*) (s-(sizeof(struct sdshdr))); 743 } 744 745 switch(*f) { 746 case ‘%‘: 747 next = *(f+1); 748 f++; 749 switch(next) { 750 case ‘s‘: 751 case ‘S‘: 752 str = va_arg(ap,char*); 753 l = (next == ‘s‘) ? strlen(str) : sdslen(str); 754 if (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; 762 break; 763 case ‘i‘: 764 case ‘I‘: 765 if (next == ‘i‘) 766 num = va_arg(ap,int); 767 else 768 num = va_arg(ap,long long); 769 { 770 char buf[SDS_LLSTR_SIZE]; 771 l = sdsll2str(buf,num); 772 if (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 } 781 break; 782 case ‘u‘: 783 case ‘U‘: 784 if (next == ‘u‘) 785 unum = va_arg(ap,unsigned int); 786 else 787 unum = va_arg(ap,unsigned long long); 788 { 789 char buf[SDS_LLSTR_SIZE]; 790 l = sdsull2str(buf,unum); 791 if (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 } 800 break; 801 default: /* Handle %% and generally %<unknown>. */ 802 s[i++] = next; 803 sh->len += 1; 804 sh->free -= 1; 805 break; 806 } 807 break; 808 default: 809 s[i++] = *f; 810 sh->len += 1; 811 sh->free -= 1; 812 break; 813 } 814 f++; 815 } 816 va_end(ap); 817 818 /* Add null-term */ 819 s[i] = ‘\0‘; 820 return 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. 833 * 834 * After the call, the modified sds string is no longer valid and all the 835 * references must be substituted with the new pointer returned by the call. 836 * 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) { 846 struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr))); 847 char *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) 855 while(sp <= end && strchr(cset, *sp)) sp++; 856 while(ep > start && strchr(cset, *ep)) ep--; 857 858 // 计算 trim 完毕之后剩余的字符串长度 859 len = (sp > ep) ? 0 : ((ep-sp)+1); 860 861 // 如果有需要,前移字符串内容 862 // T = O(N) 863 if (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 873 return 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 */ 902 void sdsrange(sds s, int start, int end) { 903 struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr))); 904 size_t newlen, len = sdslen(s); 905 906 if (len == 0) return; 907 if (start < 0) { 908 start = len+start; 909 if (start < 0) start = 0; 910 } 911 if (end < 0) { 912 end = len+end; 913 if (end < 0) end = 0; 914 } 915 newlen = (start > end) ? 0 : (end-start)+1; 916 if (newlen != 0) { 917 if (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) 929 if (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‘. */ 945 void sdstolower(sds s) { 946 int len = sdslen(s), j; 947 948 for (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‘. */ 957 void sdstoupper(sds s) { 958 int len = sdslen(s), j; 959 960 for (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. */ 982 int sdscmp(const sds s1, const sds s2) { 983 size_t l1, l2, minlen; 984 int cmp; 985 986 l1 = sdslen(s1); 987 l2 = sdslen(s2); 988 minlen = (l1 < l2) ? l1 : l2; 989 cmp = memcmp(s1,s2,minlen); 990 991 if (cmp == 0) return l1-l2; 992 993 return 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 length1004 * separator, NULL is returned.1005 *1006 * 如果出现内存不足、字符串长度为 0 或分隔符长度为 01007 * 的情况,返回 NULL1008 *1009 * Note that ‘sep‘ is able to split a string using1010 * a multi-character separator. For example1011 * sdssplit("foo_-_bar","_-_"); will return two1012 * elements "foo" and "bar".1013 *1014 * 注意分隔符可以的是包含多个字符的字符串1015 *1016 * This version of the function is binary-safe but1017 * requires length arguments. sdssplit() is just the1018 * same function but for zero-terminated strings.1019 *1020 * 这个函数接受 len 参数,因此它是二进制安全的。1021 * (文档中提到的 sdssplit() 已废弃)1022 *1023 * T = O(N^2)1024 */1025 sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count) {1026 int elements = 0, slots = 5, start = 0, j;1027 sds *tokens;1028 1029 if (seplen < 1 || len < 0) return NULL;1030 1031 tokens = zmalloc(sizeof(sds)*slots);1032 if (tokens == NULL) return NULL;1033 1034 if (len == 0) {1035 *count = 0;1036 return tokens;1037 }1038 1039 // T = O(N^2)1040 for (j = 0; j < (len-(seplen-1)); j++) {1041 /* make sure there is room for the next element and the final one */1042 if (slots < elements+2) {1043 sds *newtokens;1044 1045 slots *= 2;1046 newtokens = zrealloc(tokens,sizeof(sds)*slots);1047 if (newtokens == NULL) goto cleanup;1048 tokens = newtokens;1049 }1050 /* search the separator */1051 // T = O(N)1052 if ((seplen == 1 && *(s+j) == sep[0]) || (memcmp(s+j,sep,seplen) == 0)) {1053 tokens[elements] = sdsnewlen(s+start,j-start);1054 if (tokens[elements] == NULL) goto cleanup;1055 elements++;1056 start = j+seplen;1057 j = j+seplen-1; /* skip the separator */1058 }1059 }1060 /* Add the final element. We are sure there is room in the tokens array. */1061 tokens[elements] = sdsnewlen(s+start,len-start);1062 if (tokens[elements] == NULL) goto cleanup;1063 elements++;1064 *count = elements;1065 return tokens;1066 1067 cleanup:1068 {1069 int i;1070 for (i = 0; i < elements; i++) sdsfree(tokens[i]);1071 zfree(tokens);1072 *count = 0;1073 return NULL;1074 }1075 }1076 1077 /*1078 * 释放 tokens 数组中 count 个 sds1079 *1080 * T = O(N^2)1081 */1082 /* Free the result returned by sdssplitlen(), or do nothing if ‘tokens‘ is NULL. */1083 void sdsfreesplitres(sds *tokens, int count) {1084 if (!tokens) return;1085 while(count--)1086 sdsfree(tokens[count]);1087 zfree(tokens);1088 }1089 1090 /*1091 * 将长度为 len 的字符串 p 以带引号(quoted)的格式1092 * 追加到给定 sds 的末尾1093 *1094 * T = O(N)1095 */1096 /* Append to the sds string "s" an escaped string representation where1097 * all the non-printable characters (tested with isprint()) are turned into1098 * escapes in the form "\n\r\a...." or "\x<hex-number>".1099 *1100 * After the call, the modified sds string is no longer valid and all the1101 * references must be substituted with the new pointer returned by the call. */1102 sds sdscatrepr(sds s, const char *p, size_t len) {1103 1104 s = sdscatlen(s,"\"",1);1105 1106 while(len--) {1107 switch(*p) {1108 case ‘\\‘:1109 case ‘"‘:1110 s = sdscatprintf(s,"\\%c",*p);1111 break;1112 case ‘\n‘: s = sdscatlen(s,"\\n",2); break;1113 case ‘\r‘: s = sdscatlen(s,"\\r",2); break;1114 case ‘\t‘: s = sdscatlen(s,"\\t",2); break;1115 case ‘\a‘: s = sdscatlen(s,"\\a",2); break;1116 case ‘\b‘: s = sdscatlen(s,"\\b",2); break;1117 default:1118 if (isprint(*p))1119 s = sdscatprintf(s,"%c",*p);1120 else1121 s = sdscatprintf(s,"\\x%02x",(unsigned char)*p);1122 break;1123 }1124 p++;1125 }1126 1127 return sdscatlen(s,"\"",1);1128 }1129 1130 /* Helper function for sdssplitargs() that returns non zero if ‘c‘1131 * is a valid hex digit. */1132 /*1133 * 如果 c 为十六进制符号的其中一个,返回正数1134 *1135 * T = O(1)1136 */1137 int is_hex_digit(char c) {1138 return (c >= ‘0‘ && c <= ‘9‘) || (c >= ‘a‘ && c <= ‘f‘) ||1139 (c >= ‘A‘ && c <= ‘F‘);1140 }1141 1142 /* Helper function for sdssplitargs() that converts a hex digit into an1143 * integer from 0 to 15 */1144 /*1145 * 将十六进制符号转换为 10 进制1146 *1147 * T = O(1)1148 */1149 int hex_digit_to_int(char c) {1150 switch(c) {1151 case ‘0‘: return 0;1152 case ‘1‘: return 1;1153 case ‘2‘: return 2;1154 case ‘3‘: return 3;1155 case ‘4‘: return 4;1156 case ‘5‘: return 5;1157 case ‘6‘: return 6;1158 case ‘7‘: return 7;1159 case ‘8‘: return 8;1160 case ‘9‘: return 9;1161 case ‘a‘: case ‘A‘: return 10;1162 case ‘b‘: case ‘B‘: return 11;1163 case ‘c‘: case ‘C‘: return 12;1164 case ‘d‘: case ‘D‘: return 13;1165 case ‘e‘: case ‘E‘: return 14;1166 case ‘f‘: case ‘F‘: return 15;1167 default: return 0;1168 }1169 }1170 1171 /* Split a line into arguments, where every argument can be in the1172 * following programming-language REPL-alike form:1173 *1174 * 将一行文本分割成多个参数,每个参数可以有以下的类编程语言 REPL 格式:1175 *1176 * foo bar "newline are supported\n" and "\xff\x00otherstuff"1177 *1178 * The number of arguments is stored into *argc, and an array1179 * of sds is returned.1180 *1181 * 参数的个数会保存在 *argc 中,函数返回一个 sds 数组。1182 *1183 * The caller should free the resulting array of sds strings with1184 * sdsfreesplitres().1185 *1186 * 调用者应该使用 sdsfreesplitres() 来释放函数返回的 sds 数组。1187 *1188 * Note that sdscatrepr() is able to convert back a string into1189 * a quoted string in the same format sdssplitargs() is able to parse.1190 *1191 * sdscatrepr() 可以将一个字符串转换为一个带引号(quoted)的字符串,1192 * 这个带引号的字符串可以被 sdssplitargs() 分析。1193 *1194 * The function returns the allocated tokens on success, even when the1195 * input string is empty, or NULL if the input contains unbalanced1196 * quotes or closed quotes followed by non space characters1197 * as in: "foo"bar or "foo‘1198 *1199 * 即使输入出现空字符串, NULL ,或者输入带有未对应的括号,1200 * 函数都会将已成功处理的字符串先返回。1201 *1202 * 这个函数主要用于 config.c 中对配置文件进行分析。1203 * 例子:1204 * sds *arr = sdssplitargs("timeout 10086\r\nport 123321\r\n");1205 * 会得出1206 * arr[0] = "timeout"1207 * arr[1] = "10086"1208 * arr[2] = "port"1209 * arr[3] = "123321"1210 *1211 * T = O(N^2)1212 */1213 sds *sdssplitargs(const char *line, int *argc) {1214 const char *p = line;1215 char *current = NULL;1216 char **vector = NULL;1217 1218 *argc = 0;1219 while(1) {1220 1221 /* skip blanks */1222 // 跳过空白1223 // T = O(N)1224 while(*p && isspace(*p)) p++;1225 1226 if (*p) {1227 /* get a token */1228 int inq=0; /* set to 1 if we are in "quotes" */1229 int insq=0; /* set to 1 if we are in ‘single quotes‘ */1230 int done=0;1231 1232 if (current == NULL) current = sdsempty();1233 1234 // T = O(N)1235 while(!done) {1236 if (inq) {1237 if (*p == ‘\\‘ && *(p+1) == ‘x‘ &&1238 is_hex_digit(*(p+2)) &&1239 is_hex_digit(*(p+3)))1240 {1241 unsigned char byte;1242 1243 byte = (hex_digit_to_int(*(p+2))*16)+1244 hex_digit_to_int(*(p+3));1245 current = sdscatlen(current,(char*)&byte,1);1246 p += 3;1247 } else if (*p == ‘\\‘ && *(p+1)) {1248 char c;1249 1250 p++;1251 switch(*p) {1252 case ‘n‘: c = ‘\n‘; break;1253 case ‘r‘: c = ‘\r‘; break;1254 case ‘t‘: c = ‘\t‘; break;1255 case ‘b‘: c = ‘\b‘; break;1256 case ‘a‘: c = ‘\a‘; break;1257 default: c = *p; break;1258 }1259 current = sdscatlen(current,&c,1);1260 } else if (*p == ‘"‘) {1261 /* closing quote must be followed by a space or1262 * nothing at all. */1263 if (*(p+1) && !isspace(*(p+1))) goto err;1264 done=1;1265 } else if (!*p) {1266 /* unterminated quotes */1267 goto err;1268 } else {1269 current = sdscatlen(current,p,1);1270 }1271 } else if (insq) {1272 if (*p == ‘\\‘ && *(p+1) == ‘\‘‘) {1273 p++;1274 current = sdscatlen(current,"‘",1);1275 } else if (*p == ‘\‘‘) {1276 /* closing quote must be followed by a space or1277 * nothing at all. */1278 if (*(p+1) && !isspace(*(p+1))) goto err;1279 done=1;1280 } else if (!*p) {1281 /* unterminated quotes */1282 goto err;1283 } else {1284 current = sdscatlen(current,p,1);1285 }1286 } else {1287 switch(*p) {1288 case ‘ ‘:1289 case ‘\n‘:1290 case ‘\r‘:1291 case ‘\t‘:1292 case ‘\0‘:1293 done=1;1294 break;1295 case ‘"‘:1296 inq=1;1297 break;1298 case ‘\‘‘:1299 insq=1;1300 break;1301 default:1302 current = sdscatlen(current,p,1);1303 break;1304 }1305 }1306 if (*p) p++;1307 }1308 /* add the token to the vector */1309 // T = O(N)1310 vector = zrealloc(vector,((*argc)+1)*sizeof(char*));1311 vector[*argc] = current;1312 (*argc)++;1313 current = NULL;1314 } else {1315 /* Even on empty input string return something not NULL. */1316 if (vector == NULL) vector = zmalloc(sizeof(void*));1317 return vector;1318 }1319 }1320 1321 err:1322 while((*argc)--)1323 sdsfree(vector[*argc]);1324 zfree(vector);1325 if (current) sdsfree(current);1326 *argc = 0;1327 return NULL;1328 }1329 1330 /* Modify the string substituting all the occurrences of the set of1331 * characters specified in the ‘from‘ string to the corresponding character1332 * in the ‘to‘ array.1333 *1334 * 将字符串 s 中,1335 * 所有在 from 中出现的字符,替换成 to 中的字符1336 *1337 * For instance: sdsmapchars(mystring, "ho", "01", 2)1338 * will have the effect of turning the string "hello" into "0ell1".1339 *1340 * 比如调用 sdsmapchars(mystring, "ho", "01", 2)1341 * 就会将 "hello" 转换为 "0ell1"1342 *1343 * The function returns the sds string pointer, that is always the same1344 * as the input pointer since no resize is needed. 1345 * 因为无须对 sds 进行大小调整,1346 * 所以返回的 sds 输入的 sds 一样1347 *1348 * T = O(N^2)1349 */1350 sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen) {1351 size_t j, i, l = sdslen(s);1352 1353 // 遍历输入字符串1354 for (j = 0; j < l; j++) {1355 // 遍历映射1356 for (i = 0; i < setlen; i++) {1357 // 替换字符串1358 if (s[j] == from[i]) {1359 s[j] = to[i];1360 break;1361 }1362 }1363 }1364 return s;1365 }1366 1367 /* Join an array of C strings using the specified separator (also a C string).1368 * Returns the result as an sds string. */1369 sds sdsjoin(char **argv, int argc, char *sep) {1370 sds join = sdsempty();1371 int j;1372 1373 for (j = 0; j < argc; j++) {1374 join = sdscat(join, argv[j]);1375 if (j != argc-1) join = sdscat(join,sep);1376 }1377 return join;1378 }1379 1380 #ifdef SDS_TEST_MAIN1381 #include <stdio.h>1382 #include "testhelp.h"1383 #include "limits.h"1384 1385 int main(void) {1386 {1387 struct sdshdr *sh;1388 sds x = sdsnew("foo"), y;1389 1390 test_cond("Create a string and obtain the length",1391 sdslen(x) == 3 && memcmp(x,"foo\0",4) == 0)1392 1393 sdsfree(x);1394 x = sdsnewlen("foo",2);1395 test_cond("Create a string with specified length",1396 sdslen(x) == 2 && memcmp(x,"fo\0",3) == 0)1397 1398 x = sdscat(x,"bar");1399 test_cond("Strings concatenation",1400 sdslen(x) == 5 && memcmp(x,"fobar\0",6) == 0);1401 1402 x = sdscpy(x,"a");1403 test_cond("sdscpy() against an originally longer string",1404 sdslen(x) == 1 && memcmp(x,"a\0",2) == 0)1405 1406 x = sdscpy(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk");1407 test_cond("sdscpy() against an originally shorter string",1408 sdslen(x) == 33 &&1409 memcmp(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk\0",33) == 0)1410 1411 sdsfree(x);1412 x = sdscatprintf(sdsempty(),"%d",123);1413 test_cond("sdscatprintf() seems working in the base case",1414 sdslen(x) == 3 && memcmp(x,"123\0",4) == 0)1415 1416 sdsfree(x);1417 x = sdsnew("--");1418 x = sdscatfmt(x, "Hello %s World %I,%I--", "Hi!", LLONG_MIN,LLONG_MAX);1419 test_cond("sdscatfmt() seems working in the base case",1420 sdslen(x) == 60 &&1421 memcmp(x,"--Hello Hi! World -9223372036854775808,"1422 "9223372036854775807--",60) == 0)1423 1424 sdsfree(x);1425 x = sdsnew("--");1426 x = sdscatfmt(x, "%u,%U--", UINT_MAX, ULLONG_MAX);1427 test_cond("sdscatfmt() seems working with unsigned numbers",1428 sdslen(x) == 35 &&1429 memcmp(x,"--4294967295,18446744073709551615--",35) == 0)1430 1431 sdsfree(x);1432 x = sdsnew("xxciaoyyy");1433 sdstrim(x,"xy");1434 test_cond("sdstrim() correctly trims characters",1435 sdslen(x) == 4 && memcmp(x,"ciao\0",5) == 0)1436 1437 y = sdsdup(x);1438 sdsrange(y,1,1);1439 test_cond("sdsrange(...,1,1)",1440 sdslen(y) == 1 && memcmp(y,"i\0",2) == 0)1441 1442 sdsfree(y);1443 y = sdsdup(x);1444 sdsrange(y,1,-1);1445 test_cond("sdsrange(...,1,-1)",1446 sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0)1447 1448 sdsfree(y);1449 y = sdsdup(x);1450 sdsrange(y,-2,-1);1451 test_cond("sdsrange(...,-2,-1)",1452 sdslen(y) == 2 && memcmp(y,"ao\0",3) == 0)1453 1454 sdsfree(y);1455 y = sdsdup(x);1456 sdsrange(y,2,1);1457 test_cond("sdsrange(...,2,1)",1458 sdslen(y) == 0 && memcmp(y,"\0",1) == 0)1459 1460 sdsfree(y);1461 y = sdsdup(x);1462 sdsrange(y,1,100);1463 test_cond("sdsrange(...,1,100)",1464 sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0)1465 1466 sdsfree(y);1467 y = sdsdup(x);1468 sdsrange(y,100,100);1469 test_cond("sdsrange(...,100,100)",1470 sdslen(y) == 0 && memcmp(y,"\0",1) == 0)1471 1472 sdsfree(y);1473 sdsfree(x);1474 x = sdsnew("foo");1475 y = sdsnew("foa");1476 test_cond("sdscmp(foo,foa)", sdscmp(x,y) > 0)1477 1478 sdsfree(y);1479 sdsfree(x);1480 x = sdsnew("bar");1481 y = sdsnew("bar");1482 test_cond("sdscmp(bar,bar)", sdscmp(x,y) == 0)1483 1484 sdsfree(y);1485 sdsfree(x);1486 x = sdsnew("aar");1487 y = sdsnew("bar");1488 test_cond("sdscmp(bar,bar)", sdscmp(x,y) < 0)1489 1490 sdsfree(y);1491 sdsfree(x);1492 x = sdsnewlen("\a\n\0foo\r",7);1493 y = sdscatrepr(sdsempty(),x,sdslen(x));1494 test_cond("sdscatrepr(...data...)",1495 memcmp(y,"\"\\a\\n\\x00foo\\r\"",15) == 0)1496 1497 {1498 int oldfree;1499 1500 sdsfree(x);1501 x = sdsnew("0");1502 sh = (void*) (x-(sizeof(struct sdshdr)));1503 test_cond("sdsnew() free/len buffers", sh->len == 1 && sh->free == 0);1504 x = sdsMakeRoomFor(x,1);1505 sh = (void*) (x-(sizeof(struct sdshdr)));1506 test_cond("sdsMakeRoomFor()", sh->len == 1 && sh->free > 0);1507 oldfree = sh->free;1508 x[1] = ‘1‘;1509 sdsIncrLen(x,1);1510 test_cond("sdsIncrLen() -- content", x[0] == ‘0‘ && x[1] == ‘1‘);1511 test_cond("sdsIncrLen() -- len", sh->len == 2);1512 test_cond("sdsIncrLen() -- free", sh->free == oldfree-1);1513 }1514 }1515 test_report()1516 return 0;1517 }1518 #endif
Redis源码学习1-sds.c
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。