1 //_ aaA.d 2 3 /** 4 * Part of the D programming language runtime library. 5 * Implementation of associative arrays. 6 */ 7 8 /* 9 * Copyright (C) 2000-2008 by Digital Mars, http://www.digitalmars.com 10 * Written by Walter Bright 11 * 12 * This software is provided 'as-is', without any express or implied 13 * warranty. In no event will the authors be held liable for any damages 14 * arising from the use of this software. 15 * 16 * Permission is granted to anyone to use this software for any purpose, 17 * including commercial applications, and to alter it and redistribute it 18 * freely, subject to the following restrictions: 19 * 20 * o The origin of this software must not be misrepresented; you must not 21 * claim that you wrote the original software. If you use this software 22 * in a product, an acknowledgment in the product documentation would be 23 * appreciated but is not required. 24 * o Altered source versions must be plainly marked as such, and must not 25 * be misrepresented as being the original software. 26 * o This notice may not be removed or altered from any source 27 * distribution. 28 */ 29 30 /* 31 * Modified by Sean Kelly <sean@f4.ca> for use with Tango. 32 */ 33 34 module rt.compiler.dmd.rt.aaA; 35 36 private 37 { 38 import tango.stdc.stdarg; 39 import tango.stdc.string: memcmp,memcpy; 40 41 enum BlkAttr : uint 42 { 43 FINALIZE = 0b0000_0001, 44 NO_SCAN = 0b0000_0010, 45 NO_MOVE = 0b0000_0100, 46 ALL_BITS = 0b1111_1111 47 } 48 49 extern (C) void* gc_malloc( size_t sz, uint ba = 0, PointerMap bitMask = PointerMap.init); 50 extern (C) void* gc_calloc( size_t sz, uint ba = 0, PointerMap bitMask = PointerMap.init); 51 extern (C) void gc_free( void* p ); 52 } 53 54 // Auto-rehash and pre-allocate - Dave Fladebo 55 56 static size_t[] prime_list = [ 57 97UL, 389UL, 58 1_543UL, 6_151UL, 59 24_593UL, 98_317UL, 60 393_241UL, 1_572_869UL, 61 6_291_469UL, 25_165_843UL, 62 100_663_319UL, 402_653_189UL, 63 1_610_612_741UL, 4_294_967_291UL, 64 // 8_589_934_513UL, 17_179_869_143UL 65 ]; 66 67 /* This is the type of the return value for dynamic arrays. 68 * It should be a type that is returned in registers. 69 * Although DMD will return types of Array in registers, 70 * gcc will not, so we instead use a 'long'. 71 */ 72 alias void[] ArrayRet_t; 73 74 struct Array 75 { 76 size_t length; 77 void* ptr; 78 } 79 80 struct aaA 81 { 82 aaA *left; 83 aaA *right; 84 hash_t hash; 85 /* key */ 86 /* value */ 87 } 88 89 struct BB 90 { 91 aaA*[] b; 92 size_t nodes; // total number of aaA nodes 93 TypeInfo keyti; // TODO: replace this with TypeInfo_AssociativeArray when available in _aaGet() 94 } 95 96 /* This is the type actually seen by the programmer, although 97 * it is completely opaque. 98 */ 99 100 struct AA 101 { 102 BB* a; 103 } 104 105 /********************************** 106 * Align to next pointer boundary, so that 107 * GC won't be faced with misaligned pointers 108 * in value. 109 */ 110 111 size_t aligntsize(size_t tsize) 112 { 113 version (X86_64) 114 // Size of key needed to align value on 16 bytes 115 return (tsize + 15) & ~(15); 116 else 117 return (tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1); 118 } 119 120 extern (C): 121 122 /************************************************* 123 * Invariant for aa. 124 */ 125 126 /+ 127 void _aaInvAh(aaA*[] aa) 128 { 129 for (size_t i = 0; i < aa.length; i++) 130 { 131 if (aa[i]) 132 _aaInvAh_x(aa[i]); 133 } 134 } 135 136 private int _aaCmpAh_x(aaA *e1, aaA *e2) 137 { int c; 138 139 c = e1.hash - e2.hash; 140 if (c == 0) 141 { 142 c = e1.key.length - e2.key.length; 143 if (c == 0) 144 c = memcmp((char *)e1.key, (char *)e2.key, e1.key.length); 145 } 146 return c; 147 } 148 149 private void _aaInvAh_x(aaA *e) 150 { 151 hash_t key_hash; 152 aaA *e1; 153 aaA *e2; 154 155 key_hash = getHash(e.key); 156 assert(key_hash == e.hash); 157 158 while (1) 159 { int c; 160 161 e1 = e.left; 162 if (e1) 163 { 164 _aaInvAh_x(e1); // ordinary recursion 165 do 166 { 167 c = _aaCmpAh_x(e1, e); 168 assert(c < 0); 169 e1 = e1.right; 170 } while (e1 != null); 171 } 172 173 e2 = e.right; 174 if (e2) 175 { 176 do 177 { 178 c = _aaCmpAh_x(e, e2); 179 assert(c < 0); 180 e2 = e2.left; 181 } while (e2 != null); 182 e = e.right; // tail recursion 183 } 184 else 185 break; 186 } 187 } 188 +/ 189 190 /**************************************************** 191 * Determine number of entries in associative array. 192 */ 193 194 size_t _aaLen(AA aa) 195 in 196 { 197 //printf("_aaLen()+\n"); 198 //_aaInv(aa); 199 } 200 out (result) 201 { 202 size_t len = 0; 203 204 void _aaLen_x(aaA* ex) 205 { 206 auto e = ex; 207 len++; 208 209 while (1) 210 { 211 if (e.right) 212 _aaLen_x(e.right); 213 e = e.left; 214 if (!e) 215 break; 216 len++; 217 } 218 } 219 220 if (aa.a) 221 { 222 foreach (e; aa.a.b) 223 { 224 if (e) 225 _aaLen_x(e); 226 } 227 } 228 assert(len == result); 229 230 //printf("_aaLen()-\n"); 231 } 232 body 233 { 234 return aa.a ? aa.a.nodes : 0; 235 } 236 237 238 /************************************************* 239 * Get pointer to value in associative array indexed by key. 240 * Add entry for key if it is not already there. 241 */ 242 243 void* _aaGet(AA* aa, TypeInfo keyti, size_t valuesize, ...) 244 { 245 return _aaGetX(aa, keyti, valuesize, cast(void *)(&valuesize + 1)); 246 } 247 248 void* _aaGetX(AA* aa, TypeInfo keyti, size_t valuesize, void* pkey) 249 in 250 { 251 assert(aa); 252 } 253 out (result) 254 { 255 assert(result); 256 assert(aa.a); 257 assert(aa.a.b.length); 258 //assert(_aaInAh(*aa.a, key)); 259 } 260 body 261 { 262 size_t i; 263 aaA *e; 264 auto keysize = aligntsize(keyti.tsize()); 265 266 if (!aa.a) 267 aa.a = new BB(); 268 269 aa.a.keyti = keyti; 270 271 if (!aa.a.b.length) 272 { 273 alias aaA *pa; 274 auto len = prime_list[0]; 275 276 aa.a.b = new pa[len]; 277 } 278 279 auto key_hash = keyti.getHash(pkey); 280 281 //printf("hash = %d\n", key_hash); 282 283 i = key_hash % aa.a.b.length; 284 auto pe = &aa.a.b[i]; 285 286 while ((e = *pe) !is null) 287 { 288 if (key_hash == e.hash) 289 { 290 auto c = keyti.compare(pkey, e + 1); 291 if (c == 0) 292 goto Lret; 293 pe = (c < 0) ? &e.left : &e.right; 294 } 295 else 296 pe = (key_hash < e.hash) ? &e.left : &e.right; 297 } 298 299 // Not found, create new elem 300 //printf("create new one\n"); 301 size_t size = aaA.sizeof + keysize + valuesize; 302 e = cast(aaA *) gc_calloc(size); 303 memcpy(e + 1, pkey, keysize); 304 e.hash = key_hash; 305 *pe = e; 306 307 auto nodes = ++aa.a.nodes; 308 //printf("length = %d, nodes = %d\n", (*aa.a).length, nodes); 309 if (nodes > aa.a.b.length * 4) 310 { 311 _aaRehash(aa,keyti); 312 } 313 314 Lret: 315 return cast(void *)(e + 1) + keysize; 316 } 317 318 319 /************************************************* 320 * Get pointer to value in associative array indexed by key. 321 * Returns null if it is not already there. 322 */ 323 324 void* _aaGetRvalue(AA aa, TypeInfo keyti, size_t valuesize, ...) 325 { 326 return _aaGetRvalueX(aa, keyti, valuesize, cast(void *)(&valuesize + 1)); 327 } 328 329 void* _aaGetRvalueX(AA aa, TypeInfo keyti, size_t valuesize, void* pkey) 330 { 331 //printf("_aaGetRvalue(valuesize = %u)\n", valuesize); 332 if (!aa.a) 333 return null; 334 335 auto keysize = aligntsize(keyti.tsize()); 336 auto len = aa.a.b.length; 337 338 if (len) 339 { 340 auto key_hash = keyti.getHash(pkey); 341 //printf("hash = %d\n", key_hash); 342 size_t i = key_hash % len; 343 auto e = aa.a.b[i]; 344 while (e !is null) 345 { 346 if (key_hash == e.hash) 347 { 348 auto c = keyti.compare(pkey, e + 1); 349 if (c == 0) 350 return cast(void *)(e + 1) + keysize; 351 e = (c < 0) ? e.left : e.right; 352 } 353 else 354 e = (key_hash < e.hash) ? e.left : e.right; 355 } 356 } 357 return null; // not found, caller will throw exception 358 } 359 360 361 /************************************************* 362 * Determine if key is in aa. 363 * Returns: 364 * null not in aa 365 * !=null in aa, return pointer to value 366 */ 367 368 void* _aaIn(AA aa, TypeInfo keyti, ...) 369 { 370 return _aaInX(aa, keyti, cast(void *)(&keyti + 1)); 371 } 372 373 void* _aaInX(AA aa, TypeInfo keyti, void* pkey) 374 in 375 { 376 } 377 out (result) 378 { 379 //assert(result == 0 || result == 1); 380 } 381 body 382 { 383 if (aa.a) 384 { 385 //printf("_aaIn(), .length = %d, .ptr = %x\n", aa.a.length, cast(uint)aa.a.ptr); 386 auto len = aa.a.b.length; 387 388 if (len) 389 { 390 auto key_hash = keyti.getHash(pkey); 391 //printf("hash = %d\n", key_hash); 392 size_t i = key_hash % len; 393 auto e = aa.a.b[i]; 394 while (e !is null) 395 { 396 if (key_hash == e.hash) 397 { 398 auto c = keyti.compare(pkey, e + 1); 399 if (c == 0) 400 return cast(void *)(e + 1) + aligntsize(keyti.tsize()); 401 e = (c < 0) ? e.left : e.right; 402 } 403 else 404 e = (key_hash < e.hash) ? e.left : e.right; 405 } 406 } 407 } 408 409 // Not found 410 return null; 411 } 412 413 /************************************************* 414 * Delete key entry in aa[]. 415 * If key is not in aa[], do nothing. 416 */ 417 418 void _aaDel(AA aa, TypeInfo keyti, ...) 419 { 420 return _aaDelX(aa, keyti, cast(void *)(&keyti + 1)); 421 } 422 423 void _aaDelX(AA aa, TypeInfo keyti, void* pkey) 424 { 425 aaA *e; 426 427 if (aa.a && aa.a.b.length) 428 { 429 auto key_hash = keyti.getHash(pkey); 430 //printf("hash = %d\n", key_hash); 431 size_t i = key_hash % aa.a.b.length; 432 auto pe = &aa.a.b[i]; 433 while ((e = *pe) !is null) // null means not found 434 { 435 if (key_hash == e.hash) 436 { 437 auto c = keyti.compare(pkey, e + 1); 438 if (c == 0) 439 { 440 if (!e.left && !e.right) 441 { 442 *pe = null; 443 } 444 else if (e.left && !e.right) 445 { 446 *pe = e.left; 447 e.left = null; 448 } 449 else if (!e.left && e.right) 450 { 451 *pe = e.right; 452 e.right = null; 453 } 454 else 455 { 456 *pe = e.left; 457 e.left = null; 458 do 459 pe = &(*pe).right; 460 while (*pe); 461 *pe = e.right; 462 e.right = null; 463 } 464 465 aa.a.nodes--; 466 gc_free(e); 467 break; 468 } 469 pe = (c < 0) ? &e.left : &e.right; 470 } 471 else 472 pe = (key_hash < e.hash) ? &e.left : &e.right; 473 } 474 } 475 } 476 477 478 /******************************************** 479 * Produce array of values from aa. 480 */ 481 482 ArrayRet_t _aaValues(AA aa, size_t keysize, size_t valuesize) 483 in 484 { 485 assert(keysize == aligntsize(keysize)); 486 } 487 body 488 { 489 size_t resi; 490 Array a; 491 492 void _aaValues_x(aaA* e) 493 { 494 do 495 { 496 memcpy(a.ptr + resi * valuesize, 497 cast(byte*)e + aaA.sizeof + keysize, 498 valuesize); 499 resi++; 500 if (e.left) 501 { if (!e.right) 502 { e = e.left; 503 continue; 504 } 505 _aaValues_x(e.left); 506 } 507 e = e.right; 508 } while (e !is null); 509 } 510 511 if (aa.a) 512 { 513 a.length = _aaLen(aa); 514 a.ptr = cast(byte*) gc_malloc(a.length * valuesize, 515 valuesize < (void*).sizeof ? BlkAttr.NO_SCAN : 0); 516 resi = 0; 517 foreach (e; aa.a.b) 518 { 519 if (e) 520 _aaValues_x(e); 521 } 522 assert(resi == a.length); 523 } 524 return *cast(ArrayRet_t*)(&a); 525 } 526 527 528 /******************************************** 529 * Rehash an array. 530 */ 531 532 void* _aaRehash(AA* paa, TypeInfo keyti) 533 in 534 { 535 //_aaInvAh(paa); 536 } 537 out (result) 538 { 539 //_aaInvAh(result); 540 } 541 body 542 { 543 BB newb; 544 545 void _aaRehash_x(aaA* olde) 546 { 547 while (1) 548 { 549 auto left = olde.left; 550 auto right = olde.right; 551 olde.left = null; 552 olde.right = null; 553 554 aaA *e; 555 556 //printf("rehash %p\n", olde); 557 auto key_hash = olde.hash; 558 size_t i = key_hash % newb.b.length; 559 auto pe = &newb.b[i]; 560 while ((e = *pe) !is null) 561 { 562 //printf("\te = %p, e.left = %p, e.right = %p\n", e, e.left, e.right); 563 assert(e.left != e); 564 assert(e.right != e); 565 if (key_hash == e.hash) 566 { 567 auto c = keyti.compare(olde + 1, e + 1); 568 assert(c != 0); 569 pe = (c < 0) ? &e.left : &e.right; 570 } 571 else 572 pe = (key_hash < e.hash) ? &e.left : &e.right; 573 } 574 *pe = olde; 575 576 if (right) 577 { 578 if (!left) 579 { olde = right; 580 continue; 581 } 582 _aaRehash_x(right); 583 } 584 if (!left) 585 break; 586 olde = left; 587 } 588 } 589 590 //printf("Rehash\n"); 591 if (paa.a) 592 { 593 auto aa = paa.a; 594 auto len = _aaLen(*paa); 595 if (len) 596 { size_t i; 597 598 for (i = 0; i < prime_list.length - 1; i++) 599 { 600 if (len <= prime_list[i]) 601 break; 602 } 603 len = prime_list[i]; 604 newb.b = new aaA*[len]; 605 606 foreach (e; aa.b) 607 { 608 if (e) 609 _aaRehash_x(e); 610 } 611 delete aa.b; 612 613 newb.nodes = aa.nodes; 614 newb.keyti = aa.keyti; 615 } 616 617 *paa.a = newb; 618 _aaBalance(paa); 619 } 620 return (*paa).a; 621 } 622 623 /******************************************** 624 * Balance an array. 625 */ 626 627 void _aaBalance(AA* paa) 628 { 629 //printf("_aaBalance()\n"); 630 if (paa.a) 631 { 632 aaA*[16] tmp; 633 aaA*[] array = tmp; 634 auto aa = paa.a; 635 foreach (j, e; aa.b) 636 { 637 /* Temporarily store contents of bucket in array[] 638 */ 639 size_t k = 0; 640 void addToArray(aaA* e) 641 { 642 while (e) 643 { addToArray(e.left); 644 if (k == array.length) 645 array.length = array.length * 2; 646 array[k++] = e; 647 e = e.right; 648 } 649 } 650 addToArray(e); 651 /* The contents of the bucket are now sorted into array[]. 652 * Rebuild the tree. 653 */ 654 void buildTree(aaA** p, size_t x1, size_t x2) 655 { 656 if (x1 >= x2) 657 *p = null; 658 else 659 { auto mid = (x1 + x2) >> 1; 660 *p = array[mid]; 661 buildTree(&(*p).left, x1, mid); 662 buildTree(&(*p).right, mid + 1, x2); 663 } 664 } 665 auto p = &aa.b[j]; 666 buildTree(p, 0, k); 667 } 668 } 669 } 670 /******************************************** 671 * Produce array of N byte keys from aa. 672 */ 673 674 ArrayRet_t _aaKeys(AA aa, size_t keysize) 675 { 676 byte[] res; 677 size_t resi; 678 679 void _aaKeys_x(aaA* e) 680 { 681 do 682 { 683 memcpy(&res[resi * keysize], cast(byte*)(e + 1), keysize); 684 resi++; 685 if (e.left) 686 { if (!e.right) 687 { e = e.left; 688 continue; 689 } 690 _aaKeys_x(e.left); 691 } 692 e = e.right; 693 } while (e !is null); 694 } 695 696 auto len = _aaLen(aa); 697 if (!len) 698 return null; 699 res = (cast(byte*) gc_malloc(len * keysize, 700 !(aa.a.keyti.flags() & 1) ? BlkAttr.NO_SCAN : 0))[0 .. len * keysize]; 701 resi = 0; 702 foreach (e; aa.a.b) 703 { 704 if (e) 705 _aaKeys_x(e); 706 } 707 assert(resi == len); 708 709 Array a; 710 a.length = len; 711 a.ptr = res.ptr; 712 return *cast(ArrayRet_t*)(&a); 713 } 714 715 716 /********************************************** 717 * 'apply' for associative arrays - to support foreach 718 */ 719 720 // dg is D, but _aaApply() is C 721 extern (D) typedef int delegate(void *) dg_t; 722 723 int _aaApply(AA aa, size_t keysize, dg_t dg) 724 in 725 { 726 assert(aligntsize(keysize) == keysize); 727 } 728 body 729 { int result; 730 731 //printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa.a, keysize, dg); 732 733 int treewalker(aaA* e) 734 { int result; 735 736 do 737 { 738 //printf("treewalker(e = %p, dg = x%llx)\n", e, dg); 739 result = dg(cast(void *)(e + 1) + keysize); 740 if (result) 741 break; 742 if (e.right) 743 { if (!e.left) 744 { 745 e = e.right; 746 continue; 747 } 748 result = treewalker(e.right); 749 if (result) 750 break; 751 } 752 e = e.left; 753 } while (e); 754 755 return result; 756 } 757 758 if (aa.a) 759 { 760 foreach (e; aa.a.b) 761 { 762 if (e) 763 { 764 result = treewalker(e); 765 if (result) 766 break; 767 } 768 } 769 } 770 return result; 771 } 772 773 // dg is D, but _aaApply2() is C 774 extern (D) typedef int delegate(void *, void *) dg2_t; 775 776 int _aaApply2(AA aa, size_t keysize, dg2_t dg) 777 in 778 { 779 assert(aligntsize(keysize) == keysize); 780 } 781 body 782 { int result; 783 784 //printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa.a, keysize, dg); 785 786 int treewalker(aaA* e) 787 { int result; 788 789 do 790 { 791 //printf("treewalker(e = %p, dg = x%llx)\n", e, dg); 792 result = dg(cast(void *)(e + 1), cast(void *)(e + 1) + keysize); 793 if (result) 794 break; 795 if (e.right) 796 { if (!e.left) 797 { 798 e = e.right; 799 continue; 800 } 801 result = treewalker(e.right); 802 if (result) 803 break; 804 } 805 e = e.left; 806 } while (e); 807 808 return result; 809 } 810 811 if (aa.a) 812 { 813 foreach (e; aa.a.b) 814 { 815 if (e) 816 { 817 result = treewalker(e); 818 if (result) 819 break; 820 } 821 } 822 } 823 return result; 824 } 825 826 extern (C) BB* _d_assocarrayliteralTX(TypeInfo_AssociativeArray ti, void[] keys, void[] values) 827 { 828 auto valueti = ti.next; 829 auto valuesize = valueti.tsize(); // value size 830 auto keyti = ti.key; 831 auto keysize = keyti.tsize(); // key size 832 auto length = keys.length; 833 BB* result; 834 835 //printf("_d_assocarrayliteralT(keysize = %d, valuesize = %d, length = %d)\n", keysize, valuesize, length); 836 //printf("tivalue = %.*s\n", ti.next.classinfo.name); 837 assert(length == values.length); 838 if (length == 0 || valuesize == 0 || keysize == 0) 839 { 840 ; 841 } 842 else 843 { 844 result = new BB(); 845 846 size_t i; 847 for (i = 0; i < prime_list.length - 1; i++) 848 { 849 if (length <= prime_list[i]) 850 break; 851 } 852 auto len = prime_list[i]; 853 result.b = new aaA*[len]; 854 855 size_t keytsize = aligntsize(keysize); 856 857 for (size_t j = 0; j < length; j++) 858 { auto pkey = keys.ptr + j * keysize; 859 auto pvalue = values.ptr + j * valuesize; 860 aaA* e; 861 862 auto key_hash = keyti.getHash(pkey); 863 //printf("hash = %d\n", key_hash); 864 i = key_hash % len; 865 auto pe = &result.b[i]; 866 while (1) 867 { 868 e = *pe; 869 if (!e) 870 { 871 // Not found, create new elem 872 //printf("create new one\n"); 873 e = cast(aaA *) cast(void*) new void[aaA.sizeof + keytsize + valuesize]; 874 memcpy(e + 1, pkey, keysize); 875 e.hash = key_hash; 876 *pe = e; 877 result.nodes++; 878 break; 879 } 880 if (key_hash == e.hash) 881 { 882 auto c = keyti.compare(pkey, e + 1); 883 if (c == 0) 884 break; 885 pe = (c < 0) ? &e.left : &e.right; 886 } 887 else 888 pe = (key_hash < e.hash) ? &e.left : &e.right; 889 } 890 memcpy(cast(void *)(e + 1) + keytsize, pvalue, valuesize); 891 } 892 } 893 return result; 894 } 895 896 /*********************************** 897 * Construct an associative array of type ti from 898 * length pairs of key/value pairs. 899 */ 900 901 extern (C) BB* _d_assocarrayliteralT(TypeInfo_AssociativeArray ti, size_t length, ...) 902 { 903 auto valuesize = ti.next.tsize(); // value size 904 auto keyti = ti.key; 905 auto keysize = keyti.tsize(); // key size 906 BB* result; 907 908 //printf("_d_assocarrayliteralT(keysize = %d, valuesize = %d, length = %d)\n", keysize, valuesize, length); 909 //printf("tivalue = %.*s\n", ti.next.classinfo.name); 910 if (length == 0 || valuesize == 0 || keysize == 0) 911 { 912 ; 913 } 914 else 915 { 916 va_list q; 917 version(X86_64) va_start(q, __va_argsave); else va_start!(size_t)(q, length); 918 919 result = new BB(); 920 result.keyti = keyti; 921 size_t i; 922 923 for (i = 0; i < prime_list.length - 1; i++) 924 { 925 if (length <= prime_list[i]) 926 break; 927 } 928 auto len = prime_list[i]; 929 result.b = new aaA*[len]; 930 931 size_t keystacksize = (keysize + int.sizeof - 1) & ~(int.sizeof - 1); 932 size_t valuestacksize = (valuesize + int.sizeof - 1) & ~(int.sizeof - 1); 933 934 size_t keytsize = aligntsize(keysize); 935 936 for (size_t j = 0; j < length; j++) 937 { void* pkey = q; 938 q += keystacksize; 939 void* pvalue = q; 940 q += valuestacksize; 941 aaA* e; 942 943 auto key_hash = keyti.getHash(pkey); 944 //printf("hash = %d\n", key_hash); 945 i = key_hash % len; 946 auto pe = &result.b[i]; 947 while (1) 948 { 949 e = *pe; 950 if (!e) 951 { 952 // Not found, create new elem 953 //printf("create new one\n"); 954 e = cast(aaA *) cast(void*) new void[aaA.sizeof + keytsize + valuesize]; 955 memcpy(e + 1, pkey, keysize); 956 e.hash = key_hash; 957 *pe = e; 958 result.nodes++; 959 break; 960 } 961 if (key_hash == e.hash) 962 { 963 auto c = keyti.compare(pkey, e + 1); 964 if (c == 0) 965 break; 966 pe = (c < 0) ? &e.left : &e.right; 967 } 968 else 969 pe = (key_hash < e.hash) ? &e.left : &e.right; 970 } 971 memcpy(cast(void *)(e + 1) + keytsize, pvalue, valuesize); 972 } 973 974 va_end(q); 975 } 976 return result; 977 } 978 979 /*********************************** 980 * Compare AA contents for equality. 981 * Returns: 982 * 1 equal 983 * 0 not equal 984 */ 985 int _aaEqual(TypeInfo_AssociativeArray ti, AA e1, AA e2) 986 { 987 //printf("_aaEqual()\n"); 988 //printf("keyti = %.*s\n", ti.key.classinfo.name); 989 //printf("valueti = %.*s\n", ti.next.classinfo.name); 990 991 if (e1.a is e2.a) 992 return 1; 993 994 size_t len = _aaLen(e1); 995 if (len != _aaLen(e2)) 996 return 0; 997 998 /* Algorithm: Visit each key/value pair in e1. If that key doesn't exist 999 * in e2, or if the value in e1 doesn't match the one in e2, the arrays 1000 * are not equal, and exit early. 1001 * After all pairs are checked, the arrays must be equal. 1002 */ 1003 1004 auto keyti = ti.key; 1005 auto valueti = ti.next; 1006 auto keysize = aligntsize(keyti.tsize()); 1007 auto len2 = e2.a.b.length; 1008 1009 int _aaKeys_x(aaA* e) 1010 { 1011 do 1012 { 1013 auto pkey = cast(void*)(e + 1); 1014 auto pvalue = pkey + keysize; 1015 //printf("key = %d, value = %g\n", *cast(int*)pkey, *cast(double*)pvalue); 1016 1017 // We have key/value for e1. See if they exist in e2 1018 1019 auto key_hash = keyti.getHash(pkey); 1020 //printf("hash = %d\n", key_hash); 1021 auto i = key_hash % len2; 1022 auto f = e2.a.b[i]; 1023 while (1) 1024 { 1025 //printf("f is %p\n", f); 1026 if (f is null) 1027 return 0; // key not found, so AA's are not equal 1028 if (key_hash == f.hash) 1029 { 1030 //printf("hash equals\n"); 1031 auto c = keyti.compare(pkey, f + 1); 1032 if (c == 0) 1033 { // Found key in e2. Compare values 1034 //printf("key equals\n"); 1035 auto pvalue2 = cast(void *)(f + 1) + keysize; 1036 if (valueti.equals(pvalue, pvalue2)) 1037 { 1038 //printf("value equals\n"); 1039 break; 1040 } 1041 else 1042 return 0; // values don't match, so AA's are not equal 1043 } 1044 f = (c < 0) ? f.left : f.right; 1045 } 1046 else 1047 f = (key_hash < f.hash) ? f.left : f.right; 1048 } 1049 1050 // Look at next entry in e1 1051 if (e.left) 1052 { if (!e.right) 1053 { e = e.left; 1054 continue; 1055 } 1056 if (_aaKeys_x(e.left) == 0) 1057 return 0; 1058 } 1059 e = e.right; 1060 } while (e !is null); 1061 return 1; // this subtree matches 1062 } 1063 1064 foreach (e; e1.a.b) 1065 { 1066 if (e) 1067 { if (_aaKeys_x(e) == 0) 1068 return 0; 1069 } 1070 } 1071 1072 return 1; // equal 1073 }