1 /* 2 * Hunt - A refined core library for D programming language. 3 * 4 * Copyright (C) 2018-2019 HuntLabs 5 * 6 * Website: https://www.huntlabs.net/ 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 module hunt.collection.Radix; 12 13 import std.stdio; 14 15 import core.memory; 16 import core.stdc.string; 17 import core.stdc.stdlib; 18 19 private: 20 21 void debug_log(A...)(A args) 22 { 23 return; 24 } 25 26 alias log_info = debug_log; 27 alias log_error = debug_log; 28 29 struct RadixNode 30 { 31 size_t args; 32 // 1 iskey 33 // 1 isNull don't store it 34 // 1 isCompr 35 // 29 size 36 37 //void *data; 38 39 // node is not compr 40 // [abc][a-ptr][b-ptr][c-ptr](value-ptr?) 41 // 42 // node is compr 43 // [xyz][z-ptr](value-ptr?) 44 45 pragma(inline, true): 46 47 @property char* str() 48 { 49 return cast(char*)(&this + 1); 50 } 51 52 @property bool iskey() 53 { 54 return cast(bool)(args & 0x8000_0000UL); 55 } 56 57 @property bool iskey(bool value) 58 { 59 if (value) 60 args = args | 0x8000_0000UL; 61 else 62 args = args & (~0x8000_0000UL); 63 64 return value; 65 } 66 67 @property bool isNull() 68 { 69 return cast(bool)(args & 0x4000_0000UL); 70 } 71 72 @property bool isNull(bool value) 73 { 74 if (value) 75 args = args | 0x4000_0000UL; 76 else 77 args = args & (~0x4000_0000UL); 78 79 return value; 80 } 81 82 @property bool isCompr() 83 { 84 return cast(bool)(args & 0x2000_0000UL); 85 } 86 87 @property bool isCompr(bool value) 88 { 89 if (value) 90 args = args | 0x2000_0000UL; 91 else 92 args = args & (~0x2000_0000UL); 93 94 return value; 95 } 96 97 @property size_t size() 98 { 99 return args & 0x1FFF_FFFFUL; 100 } 101 102 @property size_t size(size_t value) 103 { 104 size_t v = args & (~0x1FFF_FFFFUL); 105 v += value; 106 args = v; 107 108 return value; 109 } 110 111 @property RadixNode** orgin() 112 { 113 return cast(RadixNode**)(str + size); 114 } 115 116 @property RadixNode* next() 117 { 118 return *orgin; 119 } 120 121 @property RadixNode* next(RadixNode* n) 122 { 123 *orgin = n; 124 return n; 125 } 126 127 @property RadixNode* nextChild(size_t index) 128 { 129 assert(index < size); 130 return orgin[index]; 131 } 132 133 @property RadixNode* nextChild(size_t index, RadixNode* n) 134 { 135 orgin[index] = n; 136 return n; 137 } 138 139 @property void* value() 140 { 141 if (isCompr) 142 return orgin[1]; 143 else 144 return orgin[size]; 145 } 146 147 @property void* value(void* v) 148 { 149 if (isCompr) 150 orgin[1] = cast(RadixNode*) v; 151 else 152 orgin[size] = cast(RadixNode*) v; 153 return v; 154 } 155 156 pragma(inline, false): 157 158 //alloc non-compr node 159 static RadixNode* create(size_t children, bool hasdata) 160 { 161 size_t nodesize = RadixNode.sizeof + children + (RadixNode*).sizeof * children; 162 if (hasdata) 163 nodesize += (void*).sizeof; 164 165 RadixNode* n = cast(RadixNode*) malloc(nodesize); 166 if (n is null) 167 return null; 168 memset(n, 0, nodesize); 169 170 n.iskey = false; 171 n.isNull = false; 172 n.isCompr = false; 173 n.size = children; 174 175 return n; 176 } 177 178 static RadixNode* createComp(size_t length, bool hasdata) 179 { 180 size_t nodesize = RadixNode.sizeof + length + (RadixNode*).sizeof; 181 if (hasdata) 182 nodesize += (void*).sizeof; 183 184 RadixNode* n = cast(RadixNode*) malloc(nodesize); 185 if (n is null) 186 return null; 187 memset(n, 0, nodesize); 188 189 n.iskey = false; 190 n.isNull = false; 191 n.isCompr = true; 192 n.size = length; 193 194 return n; 195 } 196 197 static RadixNode* recreate(RadixNode* n, size_t children, bool hasdata) 198 { 199 size_t nodesize = RadixNode.sizeof + children + (RadixNode*).sizeof * children; 200 if (hasdata) 201 nodesize += (void*).sizeof; 202 203 auto node = cast(RadixNode*) realloc(n, nodesize); 204 if (node is null) 205 return null; 206 memset(node, 0, nodesize); 207 208 node.isCompr = false; 209 return node; 210 } 211 212 static RadixNode* recreateComp(RadixNode* n, size_t length, bool hasdata) 213 { 214 size_t nodesize = RadixNode.sizeof + length + (RadixNode*).sizeof * length; 215 if (hasdata) 216 nodesize += (void*).sizeof; 217 218 auto node = cast(RadixNode*) realloc(n, nodesize); 219 if (node is null) 220 return null; 221 memset(node, 0, nodesize); 222 223 node.isCompr = true; 224 return node; 225 } 226 227 static void free(RadixNode* n) 228 { 229 .free(n); 230 } 231 } 232 233 struct RadixItem 234 { 235 RadixNode* n; 236 size_t index; 237 } 238 239 public: 240 241 struct Radix 242 { 243 protected RadixNode* head; 244 protected size_t numnodes; 245 size_t numele; 246 247 // 248 // api create 249 // 250 static Radix* create() 251 { 252 Radix* r = cast(Radix*) malloc(Radix.sizeof); 253 if (r is null) 254 return null; 255 memset(r, 0, Radix.sizeof); 256 257 r.numele = 0; 258 r.numnodes = 1; 259 r.head = RadixNode.createComp(0, false); 260 261 if (r.head is null) 262 { 263 free(r); 264 return null; 265 } 266 else 267 { 268 r.head.args = 0; 269 return r; 270 } 271 } 272 273 // 274 // api Free 275 // 276 static void free(Radix* r) 277 { 278 r.recursiveFree(r.head); 279 .free(r); 280 } 281 282 // 283 // api clear 284 // 285 void clear() 286 { 287 recursiveFree(head); 288 289 numele = 0; 290 numnodes = 1; 291 head = RadixNode.createComp(0, false); 292 } 293 294 // 295 // api remove 296 // 297 bool remove(const ubyte[] s) 298 { 299 RadixNode* h = head; 300 RadixNode* p = head; 301 RadixItem[] ts; 302 size_t index = 0; 303 size_t splitpos = 0; 304 size_t last = find(s, h, p, index, splitpos, ts); 305 306 if (last > 0) 307 { 308 log_error("remove ", cast(string) s, " ", last); 309 return false; 310 } 311 else 312 { 313 if (h.iskey) 314 { 315 numele--; 316 h.iskey = false; 317 if (h.size == 0) 318 { 319 if (p.isCompr) 320 { 321 //#1 最后一个节点为空 父节点压缩节点 且是key 则去除父节点 322 // (x) 323 // | - 'test' (x) 324 // ('test') -------------> | 325 // | () 326 // () 327 // 328 if (p.iskey) 329 { 330 h.iskey = true; 331 h.value = p.value; 332 if (p == head) 333 { 334 head = h; 335 } 336 else 337 { 338 RadixItem item = ts[$ - 2]; 339 item.n.nextChild(item.index, h); 340 } 341 numnodes -= 1; 342 RadixNode.free(p); 343 log_info("#####r1"); 344 } 345 //#2 最后一个节点为空 父节点是压缩节点 不是key 父父节点必须是非压缩节点 346 // (t) 347 // | 348 // (A) 349 // | 350 // ['xyz'] 351 // / \ - 'test' 352 // (B) ('test') ----------------> 353 // | | 354 // (C) () 355 // 356 // 357 // #1 当['xy'] size == 2 358 // #1 当['xy']不是key,A为压缩节点 && 当B为压缩节点 且不是key,合并三项 359 // (t) 360 // | 361 // (A) 362 // | 363 // ['xy'] 364 // / \ - 'test' (t) 365 // (B) ('test') ----------------> | 366 // | | (A + 'x' + B) 367 // (C) () | 368 // (C) 369 // 370 // #2 当['xy']不是key,A为压缩节点 , 合并两项 371 // (t) 372 // | 373 // (A) 374 // | 375 // ['xy'] 376 // / \ - 'test' (t) 377 // (B) ('test') ----------------> | 378 // | | ( A + 'x') 379 // (C) () | 380 // (B) 381 // | 382 // (C) 383 // 384 // #3 当B为压缩节点 且不是key , 合并两项 385 // (t) 386 // | 387 // (A) 388 // | (t) 389 // ['xy'] | 390 // / \ - 'test' (A) 391 // (B) ('test') ----------------> | 392 // | | ( 'x' + B) 393 // (C) () | 394 // (C) 395 // 396 // #4 当都不能合并时 397 // (t) 398 // | 399 // (A) 400 // | (t) 401 // ['xy'] | 402 // / \ - 'test' (A) 403 // (B) ('test') ----------------> | 404 // | | ( 'x') 405 // (C) () | 406 // (B) 407 // | 408 // (C) 409 else // pp exist. & pp is non compr 410 { 411 //pp 412 if (p == head) 413 { 414 head = h; 415 numnodes -= 1; 416 log_info("#####r2"); 417 } 418 else 419 { 420 RadixItem t1 = ts[$ - 2]; 421 RadixNode* r1 = ts[$ - 2].n; 422 if (r1.size == 2) 423 { 424 RadixNode* pp = null; 425 if (ts.length >= 3) 426 pp = ts[$ - 3].n; 427 428 bool ppCombine = pp && pp.isCompr && !r1.iskey; 429 RadixNode* nh = r1.nextChild(r1.size - 1 - t1.index); 430 bool nhCombie = nh.isCompr && !nh.iskey; 431 432 if (ppCombine && nhCombie) 433 { 434 bool hasdata = pp.iskey && !pp.isNull; 435 RadixNode* u = RadixNode.createComp(pp.size + nh.size + 1, hasdata); 436 memcpy(u.str, pp.str, pp.size); 437 memcpy(u.str + pp.size, r1.str + r1.size - 1 - t1.index, 1); 438 memcpy(u.str + pp.size + 1, nh.str, nh.size); 439 440 u.iskey = pp.iskey; 441 if (hasdata) 442 { 443 u.value = pp.value; 444 } 445 u.next(nh.next); 446 if (pp == head) 447 { 448 head = u; 449 } 450 else 451 { 452 RadixItem item = ts[$ - 4]; 453 item.n.nextChild(item.index, u); 454 } 455 RadixNode.free(nh); 456 RadixNode.free(pp); 457 RadixNode.free(p); 458 RadixNode.free(h); 459 RadixNode.free(r1); 460 numnodes -= 4; 461 log_info("#####r211"); 462 } 463 else if (ppCombine) 464 { 465 bool hasdata = pp.iskey && !pp.isNull; 466 RadixNode* u = RadixNode.createComp(pp.size + 1, hasdata); 467 memcpy(u.str, pp.str, pp.size); 468 memcpy(u.str + pp.size, r1.str + r1.size - 1 - t1.index, 1); 469 u.next(nh); 470 u.iskey = pp.iskey; 471 if (hasdata) 472 { 473 u.value = pp.value; 474 } 475 476 if (pp == head) 477 { 478 head = u; 479 } 480 else 481 { 482 RadixItem item = ts[$ - 4]; 483 item.n.nextChild(item.index, u); 484 } 485 RadixNode.free(pp); 486 RadixNode.free(p); 487 RadixNode.free(h); 488 RadixNode.free(r1); 489 numnodes -= 3; 490 491 log_info("#####r212"); 492 } 493 else if (nhCombie) 494 { 495 bool hasdata = r1.iskey && !r1.isNull; 496 RadixNode* u = RadixNode.createComp(1 + nh.size, hasdata); 497 memcpy(u.str, r1.str + r1.size - 1 - t1.index, 1); 498 memcpy(u.str + 1, nh.str, nh.size); 499 u.iskey = r1.iskey; 500 501 if (hasdata) 502 { 503 u.value = r1.value; 504 } 505 506 u.next(nh.next); 507 508 if (r1 == head) 509 { 510 head = u; 511 } 512 else 513 { 514 RadixItem item = ts[$ - 3]; 515 log_info(getString(item.n)); 516 item.n.nextChild(item.index, u); 517 } 518 RadixNode.free(nh); 519 RadixNode.free(p); 520 RadixNode.free(h); 521 RadixNode.free(r1); 522 numnodes -= 3; 523 log_info("#####r213"); 524 } 525 else 526 { 527 bool hasdata = r1.iskey && !r1.isNull; 528 RadixNode* n = RadixNode.createComp(1, hasdata); 529 n.iskey = r1.iskey; 530 if (hasdata) 531 n.value = r1.value; 532 n.str[0] = r1.str[r1.size - 1 - t1.index]; 533 n.next(r1.nextChild(r1.size - 1 - t1.index)); 534 535 if (r1 == head) 536 { 537 head = n; 538 } 539 else 540 { 541 RadixItem item = ts[$ - 3]; 542 item.n.nextChild(item.index, n); 543 } 544 545 RadixNode.free(h); 546 RadixNode.free(p); 547 RadixNode.free(r1); 548 numnodes -= 2; 549 log_info("#####r214"); 550 } 551 } 552 // #1 当['xyz'] 的size > 2 553 // 554 // (t) (t) 555 // | | 556 // (A) (A) 557 // | | 558 // ['xyz'] ['xz'] 559 // / \ \ - 'test' / \ 560 // (B)('test') (D) ----------------> ('B') (D) 561 // | | 562 // (C) () 563 // 564 else if (r1.size > 2) 565 { 566 bool hasdata = r1.iskey && !r1.isNull; 567 RadixNode* u = RadixNode.create(r1.size - 1, hasdata); 568 u.iskey = r1.iskey; 569 if (hasdata) 570 { 571 u.value = r1.value; 572 } 573 574 log_info("index ", t1.index, " ", r1.size); 575 576 if (t1.index == 0) 577 { 578 memcpy(u.str, r1.str + 1, r1.size - 1); 579 580 } 581 else if (t1.index == r1.size - 1) 582 { 583 memcpy(u.str, r1.str, r1.size - 1); 584 } 585 else 586 { 587 memcpy(u.str, r1.str, t1.index); 588 memcpy(u.str + t1.index, r1.str + t1.index + 1, 589 r1.size - t1.index - 1); 590 } 591 592 log_info(getString(u)); 593 594 for (size_t i, j = 0; i < r1.size;) 595 { 596 if (i != t1.index) 597 u.orgin[j++] = r1.orgin[i++]; 598 else 599 i++; 600 } 601 602 //RadixNode *test = null; 603 604 if (r1 == head) 605 { 606 head = u; 607 } 608 else 609 { 610 RadixItem i = ts[$ - 3]; 611 612 i.n.nextChild(i.index, u); 613 614 } 615 616 RadixNode.free(r1); 617 RadixNode.free(h); 618 RadixNode.free(p); 619 620 numnodes -= 2; 621 log_info("####r22"); 622 } 623 else 624 { 625 log_error("####r23 none exist"); 626 } 627 } 628 } 629 } 630 // #3 当父节点为非压缩节点 631 // 632 // 633 // (A) 634 // | A+'y' 635 // ['xyz'] -----------> 636 // / | \ 637 // (C) () (D) 638 // 639 // 640 // 641 // #1 当['xy'] 的size == 2时 642 // 643 // 当#1 ['xy']非key,且(C)非key , 合并三项 644 // (t) 645 // | 646 // (A) 647 // | A+'y' (t) 648 // ['xy'] -----------> | 649 // / | (A + 'x' + C) 650 // (C) () | 651 // | (D) 652 // (D) 653 // 654 // 655 // 656 // 当#2 ['xy']非key , 合并两项 657 // (t) 658 // | 659 // (A) 660 // | A+'y' (t) 661 // ['xy'] -----------> | 662 // / | (A + 'x' ) 663 // (C) () | 664 // | (C) 665 // (D) | 666 // (D) 667 // 当#3 (C)非key , 合并两项 668 // (t) 669 // | (t) 670 // (A) | 671 // | A+'y' (A) 672 // ['xy'] -----------> | 673 // / | ('x' + C) 674 // (C) () | 675 // | (D) 676 // (D) 677 // 678 // 当#4 无合并 679 // 680 // (t) 681 // | (t) 682 // (A) | 683 // | A+'y' (A) 684 // ['xy'] -----------> | 685 // / | ('x') 686 // (C) () | 687 // | (C) 688 // (D) | 689 // (D) 690 else if (!p.isCompr) 691 { 692 // noncompr to compr 693 log_info("p ", getString(p)); 694 if (p.size == 2) 695 { 696 RadixNode* pp = null; 697 if (ts.length >= 2) 698 pp = ts[$ - 2].n; 699 bool ppCombine = pp && pp.isCompr && !p.iskey; 700 RadixNode* nh = p.nextChild(p.size - 1 - index); 701 702 log_info("nh ", getString(nh)); 703 bool nhCombie = nh.isCompr && !nh.iskey; 704 705 log_info(ppCombine, " ", nhCombie); 706 707 // #1 合并3个 708 if (ppCombine && nhCombie) 709 { 710 bool hasdata = pp.iskey && !pp.isNull; 711 RadixNode* u = RadixNode.createComp(pp.size + nh.size + 1, hasdata); 712 memcpy(u.str, pp.str, pp.size); 713 memcpy(u.str + pp.size, p.str + p.size - 1 - index, 1); 714 memcpy(u.str + pp.size + 1, nh.str, nh.size); 715 716 u.iskey = pp.iskey; 717 if (hasdata) 718 u.value = pp.value; 719 720 u.next(nh.next); 721 if (pp == head) 722 { 723 head = u; 724 } 725 else 726 { 727 RadixItem item = ts[$ - 3]; 728 item.n.nextChild(item.index, u); 729 } 730 RadixNode.free(nh); 731 RadixNode.free(pp); 732 RadixNode.free(p); 733 RadixNode.free(h); 734 735 numnodes -= 3; 736 737 log_info("#####r311"); 738 } 739 // #2 740 else if (ppCombine) 741 { 742 bool hasdata = pp.iskey && !pp.isNull; 743 RadixNode* u = RadixNode.createComp(pp.size + 1, hasdata); 744 memcpy(u.str, pp.str, pp.size); 745 memcpy(u.str + pp.size, p.str + p.size - 1 - index, 1); 746 u.next(nh); 747 u.iskey = pp.iskey; 748 if (hasdata) 749 u.value = pp.value; 750 751 if (pp == head) 752 { 753 head = u; 754 } 755 else 756 { 757 RadixItem item = ts[$ - 3]; 758 item.n.nextChild(item.index, u); 759 } 760 RadixNode.free(pp); 761 RadixNode.free(p); 762 RadixNode.free(h); 763 numnodes -= 2; 764 765 log_info("#####r312"); 766 } 767 else if (nhCombie) 768 { 769 bool hasdata = p.iskey && !p.isNull; 770 RadixNode* u = RadixNode.createComp(1 + nh.size, hasdata); 771 memcpy(u.str, p.str + p.size - 1 - index, 1); 772 memcpy(u.str + 1, nh.str, nh.size); 773 u.iskey = p.iskey; 774 u.next(nh.next); 775 if (hasdata) 776 u.value = p.value; 777 if (p == head) 778 { 779 head = u; 780 } 781 else 782 { 783 RadixItem item = ts[$ - 2]; 784 item.n.nextChild(item.index, u); 785 } 786 RadixNode.free(nh); 787 RadixNode.free(p); 788 RadixNode.free(h); 789 numnodes -= 2; 790 log_info("#####r313"); 791 } 792 // p.iskey or no combine. 793 else 794 { 795 bool hasdata = p.iskey && !p.isNull; 796 RadixNode* n = RadixNode.createComp(1, hasdata); 797 n.iskey = p.iskey; 798 if (hasdata) 799 n.value = p.value; 800 n.str[0] = p.str[p.size - 1 - index]; 801 n.next(p.nextChild(p.size - 1 - index)); 802 803 if (p == head) 804 { 805 head = n; 806 } 807 else 808 { 809 RadixItem item = ts[$ - 2]; 810 item.n.nextChild(item.index, n); 811 } 812 813 RadixNode.free(h); 814 RadixNode.free(p); 815 numnodes -= 1; 816 log_info("#####r314"); 817 } 818 } 819 // #2 当['xyz'] 的size > 2时 820 // (A) (A) 821 // | A+'y' | 822 // ['xyz'] -----------> ['xz'] 823 // / | \ / \ 824 // (C) () (D) (C) (D) 825 // 826 // 827 // 828 else if (p.size > 2) 829 { 830 bool hasdata = p.iskey && !p.isNull; 831 RadixNode* u = RadixNode.create(p.size - 1, hasdata); 832 u.iskey = p.iskey; 833 if (hasdata) 834 { 835 u.value = p.value; 836 } 837 838 log_info("index ", index, " ", p.size); 839 840 if (index == 0) 841 { 842 memcpy(u.str, p.str + 1, p.size - 1); 843 } 844 else if (index == p.size - 1) 845 { 846 memcpy(u.str, p.str, p.size - 1); 847 } 848 else 849 { 850 memcpy(u.str, p.str, index); 851 memcpy(u.str + index, p.str + index + 1, p.size - index - 1); 852 } 853 854 for (size_t i, j = 0; i < p.size;) 855 { 856 if (i != index) 857 u.orgin[j++] = p.orgin[i++]; 858 else 859 i++; 860 } 861 862 if (p == head) 863 { 864 head = u; 865 } 866 else 867 { 868 RadixItem item = ts[$ - 2]; 869 item.n.nextChild(item.index, u); 870 } 871 872 RadixNode.free(h); 873 RadixNode.free(p); 874 numnodes--; 875 log_info("#####r32"); 876 } 877 } 878 } 879 // h.size > 0 880 else 881 { 882 // #4 节点是压缩节点 , 则合并 883 // (A) (A + 'test') 884 // | | 885 // ('test') - 'test' (B) 886 // | 887 // (B) -----------> 888 // 889 // 890 // #5 只是去掉一个值。 891 892 if (h.isCompr && p.isCompr) 893 { 894 bool hasdata = p.iskey && !p.isNull; 895 RadixNode* u = RadixNode.createComp(p.size + h.size, hasdata); 896 u.iskey = p.iskey; 897 if (hasdata) 898 { 899 u.value = p.value; 900 } 901 902 memcpy(u.str, p.str, p.size); 903 memcpy(u.str + p.size, h.str, h.size); 904 u.next(h.next); 905 if (p == head) 906 { 907 head = u; 908 } 909 else 910 { 911 RadixItem item = ts[$ - 2]; 912 item.n.nextChild(item.index, u); 913 } 914 numnodes--; 915 RadixNode.free(p); 916 RadixNode.free(h); 917 log_info("#####r4"); 918 } 919 else 920 { 921 log_info("#####r5"); 922 } 923 } 924 return true; 925 } 926 else 927 { 928 log_error(cast(string) s, " is not key ", getString(h)); 929 return false; 930 } 931 } 932 } 933 934 // 935 // api insert 936 // 937 bool insert(const ubyte[] s, void* data) 938 { 939 RadixNode* h = head; 940 RadixNode* p = head; 941 RadixItem[] ts; 942 size_t index = 0; 943 size_t splitpos = 0; 944 numele++; 945 946 size_t last = find(s, h, p, index, splitpos, ts); 947 948 log_info("find ", cast(string) s, " last ", last, " split ", splitpos, " index ", index); 949 950 //没有找到该s. 951 if (last > 0) 952 { 953 // #1 如果该树是空树. 954 // 955 // 'test' 956 // () ----------->('test') 957 // | 958 // () 959 // 960 if (p.size == 0) 961 { 962 RadixNode* n = RadixNode.createComp(s.length, false); 963 memcpy(n.str, s.ptr, s.length); 964 965 p = RadixNode.recreateComp(p, 0, true); 966 p.args = 0; 967 p.iskey = true; 968 p.value = data; 969 970 n.next = p; 971 head = n; 972 973 numnodes++; 974 975 log_info("####1"); 976 return true; 977 } 978 else 979 { 980 // #2 直到匹配到叶子节点,都没有匹配到,必须往该叶子节点后面加剩余的字符。 981 // 'tester' 982 // ("test") --------> ("test") 983 // | | 984 // () ("er") 985 // | 986 // () 987 if (h.size == 0) 988 { 989 //1 new comp node 990 RadixNode* n = RadixNode.createComp(last, true); 991 memcpy(n.str, s[$ - last .. $].ptr, last); 992 n.iskey = true; 993 n.value = h.value; 994 995 h.value = data; 996 997 n.next = h; 998 p.nextChild(index, n); 999 1000 numnodes++; 1001 1002 log_info("####2"); 1003 return true; 1004 } 1005 // #3 匹配到压缩节点,1 必须截断前部分。2 取原字符及压缩节点匹配字符构成 两个字符的 非压缩节点。 1006 // 3 非压缩节点 两个子节点 分别指向 截断后半部分 及 原字符后半部分 1007 // 1008 // 'teacher' 1009 // ('test')---------------->('te') 1010 // | | 1011 // (x) ['as'] u2 1012 // / \ 1013 // u4 ('cher') ('t') u3 1014 // / \ 1015 // u5 () (x) 1016 // 1017 else if (h.isCompr) 1018 { 1019 RadixNode* u1; 1020 1021 bool hasvalue = h.iskey && !h.isNull; 1022 auto u2 = RadixNode.create(2, hasvalue && splitpos <= 0); 1023 u2.str[0] = s[$ - last]; 1024 u2.str[1] = h.str[splitpos]; 1025 numnodes++; 1026 1027 if (splitpos > 0) 1028 { 1029 u1 = RadixNode.createComp(splitpos, hasvalue); 1030 memcpy(u1.str, h.str, splitpos); 1031 u1.iskey = h.iskey; 1032 if (hasvalue) 1033 u1.value = h.value; 1034 numnodes++; 1035 } 1036 else 1037 { 1038 u1 = u2; 1039 u1.iskey = h.iskey; 1040 if (hasvalue) 1041 u1.value = h.value; 1042 } 1043 1044 size_t u3_len = h.size - splitpos - 1; 1045 RadixNode* u3; 1046 bool bcombine = false; 1047 if (u3_len > 0) 1048 { 1049 //combin 1050 if (h.next.size > 0 && h.next.isCompr && !h.next.iskey) 1051 { 1052 u3 = RadixNode.createComp(u3_len + h.next.size, h.next.iskey && !h.next.isNull); 1053 memcpy(u3.str, h.str + splitpos + 1, h.size - splitpos - 1); 1054 memcpy(u3.str + h.size - splitpos - 1, h.next.str, h.next.size); 1055 numnodes++; 1056 bcombine = true; 1057 } 1058 else 1059 { 1060 u3 = RadixNode.createComp(h.size - splitpos - 1, false); 1061 memcpy(u3.str, h.str + splitpos + 1, h.size - splitpos - 1); 1062 numnodes++; 1063 } 1064 } 1065 else 1066 { 1067 u3 = h.next; 1068 } 1069 1070 //4 1071 size_t u4_len = last - 1; 1072 RadixNode* u4; 1073 1074 //5 1075 auto u5 = RadixNode.createComp(0, true); 1076 u5.iskey = true; 1077 u5.value = data; 1078 numnodes++; 1079 1080 if (u4_len > 0) 1081 { 1082 u4 = RadixNode.createComp(last - 1, false); 1083 memcpy(u4.str, s.ptr + s.length - last + 1, last - 1); 1084 numnodes++; 1085 } 1086 else 1087 { 1088 u4 = u5; 1089 } 1090 1091 //relation 1092 if (u4_len > 0) 1093 u4.next = u5; 1094 1095 if (bcombine) 1096 { 1097 u3.next = h.next.next; 1098 RadixNode.free(h.next); 1099 numnodes--; 1100 } 1101 else if (u3_len > 0) 1102 { 1103 u3.next = h.next; 1104 } 1105 1106 u2.nextChild(0, u4); 1107 u2.nextChild(1, u3); 1108 1109 if (splitpos > 0) 1110 u1.next = u2; 1111 1112 p.nextChild(index, u1); 1113 1114 if (h == head) 1115 head = u1; 1116 1117 RadixNode.free(h); 1118 numnodes--; 1119 1120 log_info("####3"); 1121 return true; 1122 } 1123 // #4 都不匹配非压缩节点的任何子节点 1 增加该字符 2 截断原字符 1124 // 1125 // 'beer' 1126 // ["tes"] ---------> ['tesb'] 1127 // / / \ / / \ \ 1128 // () () () () () () ('eer') 1129 // \ 1130 // () 1131 else 1132 { 1133 bool hasdata = !h.isNull && h.iskey; 1134 auto i = RadixNode.create(h.size + 1, hasdata); 1135 i.iskey = h.iskey; 1136 if (hasdata) 1137 { 1138 i.value = h.value; //modify 1139 } 1140 1141 numnodes++; 1142 memcpy(i.str, h.str, h.size); 1143 i.str[h.size] = s[$ - last]; 1144 memcpy(i.str + i.size, h.str + h.size, h.size * (RadixNode*).sizeof); 1145 1146 auto u1_len = last - 1; 1147 RadixNode* u1; 1148 1149 auto u2 = RadixNode.createComp(0, true); 1150 u2.value = data; 1151 u2.iskey = true; 1152 numnodes++; 1153 if (u1_len > 0) 1154 { 1155 u1 = RadixNode.createComp(u1_len, false); 1156 memcpy(u1.str, s.ptr + s.length - last + 1, u1_len); 1157 numnodes++; 1158 u1.next = u2; 1159 } 1160 else 1161 { 1162 u1 = u2; 1163 } 1164 1165 i.nextChild(h.size, u1); 1166 p.nextChild(index, i); 1167 1168 if (h == head) 1169 head = i; 1170 RadixNode.free(h); 1171 numnodes--; 1172 log_info("####4"); 1173 return true; 1174 } 1175 } 1176 } 1177 else 1178 { 1179 // #5 完全匹配,只要改个值 即可。 1180 // 'te' 1181 // ('te') -------------> the same 1182 // | 1183 // ['as'] 1184 // / \ 1185 // ('cher') ('t') 1186 // | | 1187 // () () 1188 if (splitpos == 0) 1189 { 1190 bool hasdata = (h.iskey && !h.isNull); 1191 if (hasdata) 1192 { 1193 h.value = data; 1194 if (h.iskey) //replaced 1195 numele--; 1196 else 1197 assert(0); 1198 1199 log_info("####50"); 1200 return false; 1201 } 1202 else 1203 { 1204 RadixNode* u; 1205 if (h.isCompr) 1206 { 1207 u = RadixNode.recreateComp(h, h.size, true); 1208 u.args = 0; 1209 } 1210 else 1211 { 1212 u = RadixNode.recreate(h, h.size, true); 1213 } 1214 1215 u.value = data; 1216 u.iskey = true; 1217 p.nextChild(index, u); 1218 1219 log_info("####51"); 1220 return true; 1221 } 1222 } 1223 // #6 完全匹配压缩节点前半部分。 分割即可。 1224 // 'te' 1225 // ('test') ---------> ('te') 1226 // | | 1227 // (x) ('st') 1228 // | 1229 // (x) 1230 // 1231 else if (h.isCompr) 1232 { 1233 bool hasdata = (h.iskey && !h.isNull); 1234 auto u1 = RadixNode.createComp(splitpos, hasdata); 1235 memcpy(u1.str, h.str, splitpos); 1236 u1.iskey = h.iskey; 1237 if (hasdata) 1238 u1.value = h.value; 1239 numnodes++; 1240 1241 auto u2 = RadixNode.createComp(h.size - splitpos, true); 1242 memcpy(u2.str, h.str + splitpos, h.size - splitpos); 1243 u2.iskey = true; 1244 u2.value = data; 1245 numnodes++; 1246 u2.next = h.next; 1247 1248 u1.next = u2; 1249 1250 RadixNode.free(h); 1251 numnodes--; 1252 if (h == head) 1253 { 1254 head = u1; 1255 } 1256 else 1257 { 1258 p.nextChild(index, u1); 1259 } 1260 1261 log_info("####6"); 1262 return true; 1263 } 1264 else 1265 { 1266 writeln("assert"); 1267 assert(0); 1268 } 1269 } 1270 1271 } 1272 1273 // 1274 // api find 1275 // 1276 bool find(const ubyte[] s, out void* data) 1277 { 1278 RadixNode* h = head; 1279 RadixNode* p = head; 1280 RadixItem[] ts; 1281 size_t index = 0; 1282 size_t splitpos = 0; 1283 size_t last = find(s, h, p, index, splitpos, ts); 1284 if (last == 0 && splitpos == 0 && h.iskey) 1285 { 1286 data = h.value; 1287 return true; 1288 } 1289 1290 return false; 1291 } 1292 1293 private: 1294 1295 void recursiveFree(RadixNode* n) 1296 { 1297 size_t numchildren = 0; 1298 if (n.isCompr) 1299 { 1300 numchildren = n.size > 0 ? 1 : 0; 1301 } 1302 else 1303 { 1304 numchildren = n.size; 1305 } 1306 while (numchildren--) 1307 { 1308 recursiveFree(n.nextChild(numchildren)); 1309 } 1310 RadixNode.free(n); 1311 numnodes--; 1312 } 1313 1314 //find 1315 size_t find(const ubyte[] s, ref RadixNode* r, ref RadixNode* pr, ref size_t index, 1316 ref size_t splitpos, ref RadixItem[] ts) 1317 { 1318 //find it 1319 1320 if (s.length == 0) 1321 { 1322 return 0; 1323 } 1324 1325 if (r.size == 0) 1326 { 1327 return s.length; 1328 } 1329 1330 if (r.isCompr) //is compr 1331 { 1332 char* p = r.str; 1333 size_t i = 0; 1334 for (i = 0; i < r.size && i < s.length; i++) 1335 { 1336 if (p[i] != s[i]) 1337 break; 1338 } 1339 1340 if (i == r.size) 1341 { 1342 pr = r; 1343 r = r.next; 1344 index = 0; 1345 RadixItem item; 1346 item.n = pr; 1347 item.index = index; 1348 ts ~= item; 1349 return find(s[(*pr).size .. $], r, pr, index, splitpos, ts); 1350 } 1351 else 1352 { 1353 splitpos = i; 1354 return s.length - i; 1355 } 1356 } 1357 else 1358 { 1359 char* p = r.str; 1360 char* end = r.str + r.size; 1361 while (p != end) 1362 { 1363 if (*p == s[0]) 1364 break; 1365 p++; 1366 } 1367 1368 size_t i = p - r.str; 1369 if (p == end) 1370 { 1371 splitpos = i; 1372 return s.length; 1373 } 1374 else 1375 { 1376 pr = r; 1377 index = i; 1378 r = r.nextChild(index); 1379 RadixItem item; 1380 item.n = pr; 1381 item.index = index; 1382 ts ~= item; 1383 return find(s[1 .. $], r, pr, index, splitpos, ts); 1384 } 1385 } 1386 } 1387 1388 string getString(RadixNode* h) 1389 { 1390 string str; 1391 for (size_t i = 0; i < h.size; i++) 1392 str ~= h.str[i]; 1393 return str; 1394 } 1395 1396 void recursiveShow(RadixNode* n, size_t level) 1397 { 1398 show(n, level); 1399 1400 if (n.size == 0) 1401 return; 1402 1403 if (n.isCompr) 1404 { 1405 recursiveShow(n.next, ++level); 1406 } 1407 else 1408 { 1409 ++level; 1410 for (size_t i = 0; i < n.size; i++) 1411 { 1412 recursiveShow(n.nextChild(i), level); 1413 } 1414 } 1415 } 1416 1417 void show(RadixNode* n, size_t level) 1418 { 1419 for (size_t i = 0; i < level; i++) 1420 write("\t"); 1421 write(" key:", n.iskey, n.isCompr ? " (" : " ["); 1422 1423 for (size_t i = 0; i < n.size; i++) 1424 write(n.str[i]); 1425 1426 write(n.isCompr ? ") " : "] ", (n.iskey && !n.isNull) ? n.value : null, "\n"); 1427 } 1428 1429 void show() 1430 { 1431 RadixNode* p = head; 1432 writef("numele:%d numnodes:%d\n", numele, numnodes); 1433 1434 recursiveShow(p, 0); 1435 1436 writef("\n"); 1437 } 1438 }; 1439 1440 unittest 1441 { 1442 void test1() 1443 { 1444 string[] toadd = [ 1445 "alligator", "alien", "baloon", "chromodynamic", "romane", "romanus", 1446 "romulus", "rubens", "ruber", "rubicon", "rubicundus", "all", "rub", "ba" 1447 ]; 1448 Radix* r = Radix.create(); 1449 foreach (i, s; toadd) 1450 { 1451 r.insert(cast(ubyte[]) s, cast(void*) i); 1452 } 1453 1454 foreach (s; toadd) 1455 { 1456 r.remove(cast(ubyte[]) s); 1457 } 1458 r.show(); 1459 } 1460 1461 void test2() 1462 { 1463 string origin = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ~ "abcdefghijklmnopqrstuvwxyz" ~ "0123456789"; 1464 import std.random; 1465 1466 string[] keys; 1467 size_t num = 1000; 1468 1469 for (size_t j = 0; j < num; j++) 1470 { 1471 size_t len = uniform(1, 16); 1472 string key; 1473 for (size_t i = 0; i < len; i++) 1474 { 1475 size_t index = uniform(0, origin.length); 1476 key ~= origin[index]; 1477 } 1478 keys ~= key; 1479 } 1480 1481 Radix* r = Radix.create(); 1482 foreach (i, k; keys) 1483 { 1484 r.insert(cast(ubyte[]) k, cast(void*) i); 1485 } 1486 1487 foreach (k; keys) 1488 { 1489 r.remove(cast(ubyte[]) k); 1490 } 1491 1492 r.show(); 1493 //assert(r.numele == 0); There are still problems: inaccurate calculations of numele and numnodes. 1494 } 1495 1496 test1(); 1497 test2(); 1498 }