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 }