标签:des style blog http io ar color os 使用
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 length 1004 * separator, NULL is returned. 1005 * 1006 * 如果出现内存不足、字符串长度为 0 或分隔符长度为 0 1007 * 的情况,返回 NULL 1008 * 1009 * Note that ‘sep‘ is able to split a string using 1010 * a multi-character separator. For example 1011 * sdssplit("foo_-_bar","_-_"); will return two 1012 * elements "foo" and "bar". 1013 * 1014 * 注意分隔符可以的是包含多个字符的字符串 1015 * 1016 * This version of the function is binary-safe but 1017 * requires length arguments. sdssplit() is just the 1018 * 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 个 sds 1079 * 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 where 1097 * all the non-printable characters (tested with isprint()) are turned into 1098 * 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 the 1101 * 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 else 1121 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 an 1143 * 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 the 1172 * 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 array 1179 * of sds is returned. 1180 * 1181 * 参数的个数会保存在 *argc 中,函数返回一个 sds 数组。 1182 * 1183 * The caller should free the resulting array of sds strings with 1184 * sdsfreesplitres(). 1185 * 1186 * 调用者应该使用 sdsfreesplitres() 来释放函数返回的 sds 数组。 1187 * 1188 * Note that sdscatrepr() is able to convert back a string into 1189 * 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 the 1195 * input string is empty, or NULL if the input contains unbalanced 1196 * quotes or closed quotes followed by non space characters 1197 * 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 or 1262 * 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 or 1277 * 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 of 1331 * characters specified in the ‘from‘ string to the corresponding character 1332 * 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 same 1344 * 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_MAIN 1381 #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
标签:des style blog http io ar color os 使用
原文地址:http://www.cnblogs.com/forcheryl/p/4114493.html