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