1 void main() 2 { 3 testKeysValues1(); 4 testKeysValues2(); 5 testGet1(); 6 testGet2(); 7 testRequire1(); 8 testRequire2(); 9 testRequire3(); 10 testUpdate1(); 11 testUpdate2(); 12 testByKey1(); 13 testByKey2(); 14 testByKey3(); 15 testByKey4(); 16 issue5842(); 17 issue5842Expanded(); 18 issue5925(); 19 issue8583(); 20 issue9052(); 21 issue9119(); 22 issue9852(); 23 issue10381(); 24 issue10720(); 25 issue11761(); 26 issue13078(); 27 issue14104(); 28 issue14626(); 29 issue15290(); 30 issue15367(); 31 issue16974(); 32 issue18071(); 33 testIterationWithConst(); 34 testStructArrayKey(); 35 miscTests1(); 36 miscTests2(); 37 testRemove(); 38 testZeroSizedValue(); 39 testTombstonePurging(); 40 testClear(); 41 } 42 43 void testKeysValues1() 44 { 45 static struct T 46 { 47 byte b; 48 static size_t count; 49 this(this) { ++count; } 50 } 51 T[int] aa; 52 T t; 53 aa[0] = t; 54 aa[1] = t; 55 assert(T.count == 2); 56 auto vals = aa.values; 57 assert(vals.length == 2); 58 assert(T.count == 4); 59 60 T.count = 0; 61 int[T] aa2; 62 aa2[t] = 0; 63 assert(T.count == 1); 64 aa2[t] = 1; 65 assert(T.count == 1); 66 auto keys = aa2.keys; 67 assert(keys.length == 1); 68 assert(T.count == 2); 69 } 70 71 void testKeysValues2() nothrow pure 72 { 73 int[string] aa; 74 75 assert(aa.keys.length == 0); 76 assert(aa.values.length == 0); 77 78 aa["hello"] = 3; 79 assert(aa["hello"] == 3); 80 aa["hello"]++; 81 assert(aa["hello"] == 4); 82 83 assert(aa.length == 1); 84 85 string[] keys = aa.keys; 86 assert(keys.length == 1); 87 assert(keys[0] == "hello"); 88 89 int[] values = aa.values; 90 assert(values.length == 1); 91 assert(values[0] == 4); 92 93 aa.rehash; 94 assert(aa.length == 1); 95 assert(aa["hello"] == 4); 96 97 aa["foo"] = 1; 98 aa["bar"] = 2; 99 aa["batz"] = 3; 100 101 assert(aa.keys.length == 4); 102 assert(aa.values.length == 4); 103 104 foreach (a; aa.keys) 105 { 106 assert(a.length != 0); 107 assert(a.ptr != null); 108 } 109 110 foreach (v; aa.values) 111 { 112 assert(v != 0); 113 } 114 } 115 116 void testGet1() @safe 117 { 118 int[string] aa; 119 int a; 120 foreach (val; aa.byKeyValue) 121 { 122 ++aa[val.key]; 123 a = val.value; 124 } 125 } 126 127 void testGet2() 128 { 129 static class T 130 { 131 static size_t count; 132 this() { ++count; } 133 } 134 135 T[string] aa; 136 137 auto a = new T; 138 aa["foo"] = a; 139 assert(T.count == 1); 140 auto b = aa.get("foo", new T); 141 assert(T.count == 1); 142 assert(b is a); 143 auto c = aa.get("bar", new T); 144 assert(T.count == 2); 145 assert(c !is a); 146 147 //Obviously get doesn't add. 148 assert("bar" !in aa); 149 } 150 151 void testRequire1() 152 { 153 static class T 154 { 155 static size_t count; 156 this() { ++count; } 157 } 158 159 T[string] aa; 160 161 auto a = new T; 162 aa["foo"] = a; 163 assert(T.count == 1); 164 auto b = aa.require("foo", new T); 165 assert(T.count == 1); 166 assert(b is a); 167 auto c = aa.require("bar", null); 168 assert(T.count == 1); 169 assert(c is null); 170 assert("bar" in aa); 171 auto d = aa.require("bar", new T); 172 assert(d is null); 173 auto e = aa.require("baz", new T); 174 assert(T.count == 2); 175 assert(e !is a); 176 177 assert("baz" in aa); 178 179 bool created = false; 180 auto f = aa.require("qux", { created = true; return new T; }()); 181 assert(created == true); 182 183 T g; 184 auto h = aa.require("qux", { g = new T; return g; }()); 185 assert(g !is h); 186 } 187 188 void testRequire2() 189 { 190 static struct S 191 { 192 int value; 193 } 194 195 S[string] aa; 196 197 aa.require("foo").value = 1; 198 assert(aa == ["foo" : S(1)]); 199 200 aa["bar"] = S(2); 201 auto a = aa.require("bar", S(3)); 202 assert(a == S(2)); 203 204 auto b = aa["bar"]; 205 assert(b == S(2)); 206 207 S* c = &aa.require("baz", S(4)); 208 assert(c is &aa["baz"]); 209 assert(*c == S(4)); 210 211 assert("baz" in aa); 212 213 auto d = aa["baz"]; 214 assert(d == S(4)); 215 } 216 217 void testRequire3() pure 218 { 219 string[string] aa; 220 221 auto a = aa.require("foo", "bar"); 222 assert("foo" in aa); 223 } 224 225 226 void testUpdate1() 227 { 228 static class C {} 229 C[string] aa; 230 231 C orig = new C; 232 aa["foo"] = orig; 233 234 C newer; 235 C older; 236 237 void test(string key) 238 { 239 aa.update(key, { 240 newer = new C; 241 return newer; 242 }, (ref C c) { 243 older = c; 244 newer = new C; 245 return newer; 246 }); 247 } 248 249 test("foo"); 250 assert(older is orig); 251 assert(newer is aa["foo"]); 252 253 test("bar"); 254 assert(newer is aa["bar"]); 255 } 256 257 void testUpdate2() 258 { 259 static class C {} 260 C[string] aa; 261 262 auto created = false; 263 auto updated = false; 264 265 class Creator 266 { 267 C opCall() 268 { 269 created = true; 270 return new C(); 271 } 272 } 273 274 class Updater 275 { 276 C opCall(ref C) 277 { 278 updated = true; 279 return new C(); 280 } 281 } 282 283 aa.update("foo", new Creator, new Updater); 284 assert(created); 285 aa.update("foo", new Creator, new Updater); 286 assert(updated); 287 } 288 289 void testByKey1() 290 { 291 static assert(!__traits(compiles, 292 () @safe { 293 struct BadValue 294 { 295 int x; 296 this(this) @safe { *(cast(ubyte*)(null) + 100000) = 5; } // not @safe 297 alias x this; 298 } 299 300 BadValue[int] aa; 301 () @safe { auto x = aa.byKey.front; } (); 302 } 303 )); 304 } 305 306 void testByKey2() nothrow pure 307 { 308 int[int] a; 309 foreach (i; a.byKey) 310 { 311 assert(false); 312 } 313 foreach (i; a.byValue) 314 { 315 assert(false); 316 } 317 } 318 319 void testByKey3() /*nothrow*/ pure 320 { 321 auto a = [ 1:"one", 2:"two", 3:"three" ]; 322 auto b = a.dup; 323 assert(b == [ 1:"one", 2:"two", 3:"three" ]); 324 325 int[] c; 326 foreach (k; a.byKey) 327 { 328 c ~= k; 329 } 330 331 assert(c.length == 3); 332 assert(c[0] == 1 || c[1] == 1 || c[2] == 1); 333 assert(c[0] == 2 || c[1] == 2 || c[2] == 2); 334 assert(c[0] == 3 || c[1] == 3 || c[2] == 3); 335 } 336 337 void testByKey4() nothrow pure 338 { 339 string[] keys = ["a", "b", "c", "d", "e", "f"]; 340 341 // Test forward range capabilities of byKey 342 { 343 int[string] aa; 344 foreach (key; keys) 345 aa[key] = 0; 346 347 auto keyRange = aa.byKey(); 348 auto savedKeyRange = keyRange.save; 349 350 // Consume key range once 351 size_t keyCount = 0; 352 while (!keyRange.empty) 353 { 354 aa[keyRange.front]++; 355 keyCount++; 356 keyRange.popFront(); 357 } 358 359 foreach (key; keys) 360 { 361 assert(aa[key] == 1); 362 } 363 assert(keyCount == keys.length); 364 365 // Verify it's possible to iterate the range the second time 366 keyCount = 0; 367 while (!savedKeyRange.empty) 368 { 369 aa[savedKeyRange.front]++; 370 keyCount++; 371 savedKeyRange.popFront(); 372 } 373 374 foreach (key; keys) 375 { 376 assert(aa[key] == 2); 377 } 378 assert(keyCount == keys.length); 379 } 380 381 // Test forward range capabilities of byValue 382 { 383 size_t[string] aa; 384 foreach (i; 0 .. keys.length) 385 { 386 aa[keys[i]] = i; 387 } 388 389 auto valRange = aa.byValue(); 390 auto savedValRange = valRange.save; 391 392 // Consume value range once 393 int[] hasSeen; 394 hasSeen.length = keys.length; 395 while (!valRange.empty) 396 { 397 assert(hasSeen[valRange.front] == 0); 398 hasSeen[valRange.front]++; 399 valRange.popFront(); 400 } 401 402 foreach (sawValue; hasSeen) { assert(sawValue == 1); } 403 404 // Verify it's possible to iterate the range the second time 405 hasSeen = null; 406 hasSeen.length = keys.length; 407 while (!savedValRange.empty) 408 { 409 assert(!hasSeen[savedValRange.front]); 410 hasSeen[savedValRange.front] = true; 411 savedValRange.popFront(); 412 } 413 414 foreach (sawValue; hasSeen) { assert(sawValue); } 415 } 416 } 417 418 void issue5842() pure nothrow 419 { 420 string[string] test = null; 421 test["test1"] = "test1"; 422 test.remove("test1"); 423 test.rehash; 424 test["test3"] = "test3"; // causes divide by zero if rehash broke the AA 425 } 426 427 /// expanded test for 5842: increase AA size past the point where the AA 428 /// stops using binit, in order to test another code path in rehash. 429 void issue5842Expanded() pure nothrow 430 { 431 int[int] aa; 432 foreach (int i; 0 .. 32) 433 aa[i] = i; 434 foreach (int i; 0 .. 32) 435 aa.remove(i); 436 aa.rehash; 437 aa[1] = 1; 438 } 439 440 void issue5925() nothrow pure 441 { 442 const a = [4:0]; 443 const b = [4:0]; 444 assert(a == b); 445 } 446 447 /// test for bug 8583: ensure Slot and aaA are on the same page wrt value alignment 448 void issue8583() nothrow pure 449 { 450 string[byte] aa0 = [0: "zero"]; 451 string[uint[3]] aa1 = [[1,2,3]: "onetwothree"]; 452 ushort[uint[3]] aa2 = [[9,8,7]: 987]; 453 ushort[uint[4]] aa3 = [[1,2,3,4]: 1234]; 454 string[uint[5]] aa4 = [[1,2,3,4,5]: "onetwothreefourfive"]; 455 456 assert(aa0.byValue.front == "zero"); 457 assert(aa1.byValue.front == "onetwothree"); 458 assert(aa2.byValue.front == 987); 459 assert(aa3.byValue.front == 1234); 460 assert(aa4.byValue.front == "onetwothreefourfive"); 461 } 462 463 void issue9052() nothrow pure 464 { 465 static struct Json { 466 Json[string] aa; 467 void opAssign(Json) {} 468 size_t length() const { return aa.length; } 469 // This length() instantiates AssociativeArray!(string, const(Json)) to call AA.length(), and 470 // inside ref Slot opAssign(Slot p); (which is automatically generated by compiler in Slot), 471 // this.value = p.value would actually fail, because both side types of the assignment 472 // are const(Json). 473 } 474 } 475 476 void issue9119() 477 { 478 int[string] aa; 479 assert(aa.byKeyValue.empty); 480 481 aa["a"] = 1; 482 aa["b"] = 2; 483 aa["c"] = 3; 484 485 auto pairs = aa.byKeyValue; 486 487 auto savedPairs = pairs.save; 488 size_t count = 0; 489 while (!pairs.empty) 490 { 491 assert(pairs.front.key in aa); 492 assert(pairs.front.value == aa[pairs.front.key]); 493 count++; 494 pairs.popFront(); 495 } 496 assert(count == aa.length); 497 498 // Verify that saved range can iterate over the AA again 499 count = 0; 500 while (!savedPairs.empty) 501 { 502 assert(savedPairs.front.key in aa); 503 assert(savedPairs.front.value == aa[savedPairs.front.key]); 504 count++; 505 savedPairs.popFront(); 506 } 507 assert(count == aa.length); 508 } 509 510 void issue9852() nothrow pure 511 { 512 // Original test case (revised, original assert was wrong) 513 int[string] a; 514 a["foo"] = 0; 515 a.remove("foo"); 516 assert(a == null); // should not crash 517 518 int[string] b; 519 assert(b is null); 520 assert(a == b); // should not deref null 521 assert(b == a); // ditto 522 523 int[string] c; 524 c["a"] = 1; 525 assert(a != c); // comparison with empty non-null AA 526 assert(c != a); 527 assert(b != c); // comparison with null AA 528 assert(c != b); 529 } 530 531 void issue10381() 532 { 533 alias II = int[int]; 534 II aa1 = [0 : 1]; 535 II aa2 = [0 : 1]; 536 II aa3 = [0 : 2]; 537 assert(aa1 == aa2); // Passes 538 assert(typeid(II).equals(&aa1, &aa2)); 539 assert(!typeid(II).equals(&aa1, &aa3)); 540 } 541 542 void issue10720() nothrow pure 543 { 544 static struct NC 545 { 546 @disable this(this) { } 547 } 548 549 NC[string] aa; 550 static assert(!is(aa.nonExistingField)); 551 } 552 553 /// bug 11761: test forward range functionality 554 void issue11761() pure nothrow 555 { 556 auto aa = ["a": 1]; 557 558 void testFwdRange(R, T)(R fwdRange, T testValue) 559 { 560 assert(!fwdRange.empty); 561 assert(fwdRange.front == testValue); 562 static assert(is(typeof(fwdRange.save) == typeof(fwdRange))); 563 564 auto saved = fwdRange.save; 565 fwdRange.popFront(); 566 assert(fwdRange.empty); 567 568 assert(!saved.empty); 569 assert(saved.front == testValue); 570 saved.popFront(); 571 assert(saved.empty); 572 } 573 574 testFwdRange(aa.byKey, "a"); 575 testFwdRange(aa.byValue, 1); 576 //testFwdRange(aa.byPair, tuple("a", 1)); 577 } 578 579 void issue13078() nothrow pure 580 { 581 shared string[][string] map; 582 map.rehash; 583 } 584 585 void issue14104() 586 { 587 import core.stdc.stdio; 588 589 alias K = const(ubyte)*; 590 size_t[K] aa; 591 immutable key = cast(K)(cast(size_t) uint.max + 1); 592 aa[key] = 12; 593 assert(key in aa); 594 } 595 596 void issue14626() 597 { 598 static struct S 599 { 600 string[string] aa; 601 inout(string) key() inout { return aa.byKey().front; } 602 inout(string) val() inout { return aa.byValue().front; } 603 auto keyval() inout { return aa.byKeyValue().front; } 604 } 605 606 S s = S(["a":"b"]); 607 assert(s.key() == "a"); 608 assert(s.val() == "b"); 609 assert(s.keyval().key == "a"); 610 assert(s.keyval().value == "b"); 611 612 void testInoutKeyVal(inout(string) key) 613 { 614 inout(string)[typeof(key)] aa; 615 616 foreach (i; aa.byKey()) {} 617 foreach (i; aa.byValue()) {} 618 foreach (i; aa.byKeyValue()) {} 619 } 620 621 const int[int] caa; 622 static assert(is(typeof(caa.byValue().front) == const int)); 623 } 624 625 /// test duplicated keys in AA literal 626 /// https://issues.dlang.org/show_bug.cgi?id=15290 627 void issue15290() 628 { 629 string[int] aa = [ 0: "a", 0: "b" ]; 630 assert(aa.length == 1); 631 assert(aa.keys == [ 0 ]); 632 } 633 634 void issue15367() 635 { 636 void f1() {} 637 void f2() {} 638 639 // TypeInfo_Delegate.getHash 640 int[void delegate()] aa; 641 assert(aa.length == 0); 642 aa[&f1] = 1; 643 assert(aa.length == 1); 644 aa[&f1] = 1; 645 assert(aa.length == 1); 646 647 auto a1 = [&f2, &f1]; 648 auto a2 = [&f2, &f1]; 649 650 // TypeInfo_Delegate.equals 651 for (auto i = 0; i < 2; i++) 652 assert(a1[i] == a2[i]); 653 assert(a1 == a2); 654 655 // TypeInfo_Delegate.compare 656 for (auto i = 0; i < 2; i++) 657 assert(a1[i] <= a2[i]); 658 assert(a1 <= a2); 659 } 660 661 /// test AA as key 662 /// https://issues.dlang.org/show_bug.cgi?id=16974 663 void issue16974() 664 { 665 int[int] a = [1 : 2], a2 = [1 : 2]; 666 667 assert([a : 3] == [a : 3]); 668 assert([a : 3] == [a2 : 3]); 669 670 assert(typeid(a).getHash(&a) == typeid(a).getHash(&a)); 671 assert(typeid(a).getHash(&a) == typeid(a).getHash(&a2)); 672 } 673 674 /// test safety for alias-this'd AA that have unsafe opCast 675 /// https://issues.dlang.org/show_bug.cgi?id=18071 676 void issue18071() 677 { 678 static struct Foo 679 { 680 int[int] aa; 681 auto opCast() pure nothrow @nogc 682 { 683 *cast(uint*)0xdeadbeef = 0xcafebabe;// unsafe 684 return null; 685 } 686 alias aa this; 687 } 688 689 Foo f; 690 () @safe { assert(f.byKey.empty); }(); 691 } 692 693 /// Verify iteration with const. 694 void testIterationWithConst() 695 { 696 auto aa = [1:2, 3:4]; 697 foreach (const t; aa.byKeyValue) 698 { 699 auto k = t.key; 700 auto v = t.value; 701 } 702 } 703 704 void testStructArrayKey() @safe 705 { 706 struct S 707 { 708 int i; 709 const @safe nothrow: 710 hash_t toHash() { return 0; } 711 bool opEquals(const S) { return true; } 712 int opCmp(const S) { return 0; } 713 } 714 715 int[S[]] aa = [[S(11)] : 13]; 716 assert(aa[[S(12)]] == 13); 717 } 718 719 void miscTests1() pure nothrow 720 { 721 string[int] key1 = [1 : "true", 2 : "false"]; 722 string[int] key2 = [1 : "false", 2 : "true"]; 723 string[int] key3; 724 725 // AA lits create a larger hashtable 726 int[string[int]] aa1 = [key1 : 100, key2 : 200, key3 : 300]; 727 728 // Ensure consistent hash values are computed for key1 729 assert((key1 in aa1) !is null); 730 731 // Manually assigning to an empty AA creates a smaller hashtable 732 int[string[int]] aa2; 733 aa2[key1] = 100; 734 aa2[key2] = 200; 735 aa2[key3] = 300; 736 737 assert(aa1 == aa2); 738 739 // Ensure binary-independence of equal hash keys 740 string[int] key2a; 741 key2a[1] = "false"; 742 key2a[2] = "true"; 743 744 assert(aa1[key2a] == 200); 745 } 746 747 void miscTests2() 748 { 749 int[int] aa; 750 foreach (k, v; aa) 751 assert(false); 752 foreach (v; aa) 753 assert(false); 754 assert(aa.byKey.empty); 755 assert(aa.byValue.empty); 756 assert(aa.byKeyValue.empty); 757 758 size_t n; 759 aa = [0 : 3, 1 : 4, 2 : 5]; 760 foreach (k, v; aa) 761 { 762 n += k; 763 assert(k >= 0 && k < 3); 764 assert(v >= 3 && v < 6); 765 } 766 assert(n == 3); 767 n = 0; 768 769 foreach (v; aa) 770 { 771 n += v; 772 assert(v >= 3 && v < 6); 773 } 774 assert(n == 12); 775 776 n = 0; 777 foreach (k, v; aa) 778 { 779 ++n; 780 break; 781 } 782 assert(n == 1); 783 784 n = 0; 785 foreach (v; aa) 786 { 787 ++n; 788 break; 789 } 790 assert(n == 1); 791 } 792 793 void testRemove() 794 { 795 int[int] aa; 796 assert(!aa.remove(0)); 797 aa = [0 : 1]; 798 assert(aa.remove(0)); 799 assert(!aa.remove(0)); 800 aa[1] = 2; 801 assert(!aa.remove(0)); 802 assert(aa.remove(1)); 803 804 assert(aa.length == 0); 805 assert(aa.byKey.empty); 806 } 807 808 /// test zero sized value (hashset) 809 void testZeroSizedValue() 810 { 811 alias V = void[0]; 812 auto aa = [0 : V.init]; 813 assert(aa.length == 1); 814 assert(aa.byKey.front == 0); 815 assert(aa.byValue.front == V.init); 816 aa[1] = V.init; 817 assert(aa.length == 2); 818 aa[0] = V.init; 819 assert(aa.length == 2); 820 assert(aa.remove(0)); 821 aa[0] = V.init; 822 assert(aa.length == 2); 823 assert(aa == [0 : V.init, 1 : V.init]); 824 } 825 826 void testTombstonePurging() 827 { 828 int[int] aa; 829 foreach (i; 0 .. 6) 830 aa[i] = i; 831 foreach (i; 0 .. 6) 832 assert(aa.remove(i)); 833 foreach (i; 6 .. 10) 834 aa[i] = i; 835 assert(aa.length == 4); 836 foreach (i; 6 .. 10) 837 assert(i in aa); 838 } 839 840 void testClear() 841 { 842 int[int] aa; 843 assert(aa.length == 0); 844 foreach (i; 0 .. 100) 845 aa[i] = i * 2; 846 assert(aa.length == 100); 847 auto aa2 = aa; 848 assert(aa2.length == 100); 849 aa.clear(); 850 assert(aa.length == 0); 851 assert(aa2.length == 0); 852 853 aa2[5] = 6; 854 assert(aa.length == 1); 855 assert(aa[5] == 6); 856 } 857