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