main()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 
testKeysValues1()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 
testKeysValues2()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 
testGet1()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 
testGet2()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 
testRequire1()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 
testRequire2()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 
testRequire3()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 
testUpdate1()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 
testUpdate2()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 
testByKey1()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 
testByKey2()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 
testByKey3()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 
testByKey4()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 
issue5842()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.
issue5842Expanded()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 
issue5925()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
issue8583()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 
issue9052()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