Wiki Roadmap Timeline Tickets New Ticket Source Search Help / Guide About Trac Login

root/runtime/internal/aaA.d

Revision 1512:09734fb929c0, 18.2 kB (checked in by Christian Kamm <kamm incasoftware de>, 3 years ago)

Make == for associative arrays test for equality, not identity.

_aaEq was added to runtime/internal/aaA.d which forwards to
TypeInfo?_AssociativeArray.equals in genobj.d. On the codegen side, DtoAAEquals
was added to gen/aa.cpp and is called from EqualExp::toElem in gen/toir.cpp.

I assume that the frontend will produce an error if == is used on associative
arrays of different type.

This fixes DMD bug 1429.

Line 
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, 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  *  Modified by Tomas Lindquist Olsen <tomas@famolsen.dk> for use with LDC.
33  */
34
35 private
36 {
37     import tango.stdc.stdarg;
38     import tango.stdc.string;
39
40     enum BlkAttr : uint
41     {
42         FINALIZE = 0b0000_0001,
43         NO_SCAN  = 0b0000_0010,
44         NO_MOVE  = 0b0000_0100,
45         ALL_BITS = 0b1111_1111
46     }
47
48     extern (C) void* gc_malloc( size_t sz, uint ba = 0 );
49     extern (C) void* gc_calloc( size_t sz, uint ba = 0 );
50     extern (C) void  gc_free( void* p );
51 }
52
53 // Auto-rehash and pre-allocate - Dave Fladebo
54
55 static size_t[] prime_list = [
56                97UL,            389UL,
57             1_543UL,          6_151UL,
58            24_593UL,         98_317UL,
59           393_241UL,      1_572_869UL,
60         6_291_469UL,     25_165_843UL,
61       100_663_319UL,    402_653_189UL,
62     1_610_612_741UL,  4_294_967_291UL,
63 //  8_589_934_513UL, 17_179_869_143UL
64 ];
65
66 struct aaA
67 {
68     aaA *left;
69     aaA *right;
70     hash_t hash;
71     /* key   */
72     /* value */
73 }
74
75 struct BB
76 {
77     aaA*[] b;
78     size_t nodes;       // total number of aaA nodes
79     TypeInfo keyti;     // TODO: replace this with TypeInfo_AssociativeArray when available in _aaGet()
80 }
81
82 /* This is the type actually seen by the programmer, although
83  * it is completely opaque.
84  */
85
86 // LDC doesn't pass structs in registers so no need to wrap it ...
87 alias BB* AA;
88
89 /**********************************
90  * Align to next pointer boundary, so that
91  * GC won't be faced with misaligned pointers
92  * in value.
93  */
94
95 size_t aligntsize(size_t tsize)
96 {
97     return (tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1);
98 }
99
100 extern (C):
101
102 /*************************************************
103  * Invariant for aa.
104  */
105
106 /+
107 void _aaInvAh(aaA*[] aa)
108 {
109     for (size_t i = 0; i < aa.length; i++)
110     {
111         if (aa[i])
112             _aaInvAh_x(aa[i]);
113     }
114 }
115
116 private int _aaCmpAh_x(aaA *e1, aaA *e2)
117 {   int c;
118
119     c = e1.hash - e2.hash;
120     if (c == 0)
121     {
122         c = e1.key.length - e2.key.length;
123         if (c == 0)
124             c = memcmp((char *)e1.key, (char *)e2.key, e1.key.length);
125     }
126     return c;
127 }
128
129 private void _aaInvAh_x(aaA *e)
130 {
131     hash_t key_hash;
132     aaA *e1;
133     aaA *e2;
134
135     key_hash = getHash(e.key);
136     assert(key_hash == e.hash);
137
138     while (1)
139     {   int c;
140
141         e1 = e.left;
142         if (e1)
143         {
144             _aaInvAh_x(e1);             // ordinary recursion
145             do
146             {
147                 c = _aaCmpAh_x(e1, e);
148                 assert(c < 0);
149                 e1 = e1.right;
150             } while (e1 != null);
151         }
152
153         e2 = e.right;
154         if (e2)
155         {
156             do
157             {
158                 c = _aaCmpAh_x(e, e2);
159                 assert(c < 0);
160                 e2 = e2.left;
161             } while (e2 != null);
162             e = e.right;                // tail recursion
163         }
164         else
165             break;
166     }
167 }
168 +/
169
170 /****************************************************
171  * Determine number of entries in associative array.
172  */
173
174 size_t _aaLen(AA aa)
175 in
176 {
177     //printf("_aaLen()+\n");
178     //_aaInv(aa);
179 }
180 out (result)
181 {
182     size_t len = 0;
183
184     void _aaLen_x(aaA* ex)
185     {
186         auto e = ex;
187         len++;
188
189         while (1)
190         {
191             if (e.right)
192                _aaLen_x(e.right);
193             e = e.left;
194             if (!e)
195                 break;
196             len++;
197         }
198     }
199
200     if (aa)
201     {
202         foreach (e; aa.b)
203         {
204             if (e)
205                 _aaLen_x(e);
206         }
207     }
208     assert(len == result);
209
210     //printf("_aaLen()-\n");
211 }
212 body
213 {
214     return aa ? aa.nodes : 0;
215 }
216
217
218 /*************************************************
219  * Get pointer to value in associative array indexed by key.
220  * Add entry for key if it is not already there.
221  */
222
223 void* _aaGet(AA* aa_arg, TypeInfo keyti, size_t valuesize, void* pkey)
224 in
225 {
226     assert(aa_arg);
227 }
228 out (result)
229 {
230     assert(result);
231     assert(*aa_arg);
232     assert((*aa_arg).b.length);
233     //assert(_aaInAh(*aa, key));
234 }
235 body
236 {
237     //auto pkey = cast(void *)(&valuesize + 1);
238     size_t i;
239     aaA *e;
240     auto keysize = aligntsize(keyti.tsize());
241
242     if (!*aa_arg)
243         *aa_arg = new BB();
244     auto aa = *aa_arg;
245     aa.keyti = keyti;
246
247     if (!aa.b.length)
248     {
249         alias aaA *pa;
250         auto len = prime_list[0];
251
252         aa.b = new pa[len];
253     }
254
255     auto key_hash = keyti.getHash(pkey);
256     //printf("hash = %d\n", key_hash);
257     i = key_hash % aa.b.length;
258     auto pe = &aa.b[i];
259     while ((e = *pe) !is null)
260     {
261         if (key_hash == e.hash)
262         {
263             auto c = keyti.compare(pkey, e + 1);
264             if (c == 0)
265                 goto Lret;
266             pe = (c < 0) ? &e.left : &e.right;
267         }
268         else
269             pe = (key_hash < e.hash) ? &e.left : &e.right;
270     }
271
272     // Not found, create new elem
273     //printf("create new one\n");
274     size_t size = aaA.sizeof + keysize + valuesize;
275     e = cast(aaA *) gc_calloc(size);
276     memcpy(e + 1, pkey, keysize);
277     e.hash = key_hash;
278     *pe = e;
279
280     auto nodes = ++aa.nodes;
281     //printf("length = %d, nodes = %d\n", (*aa).length, nodes);
282     if (nodes > aa.b.length * 4)
283     {
284         _aaRehash(aa_arg,keyti);
285     }
286
287 Lret:
288     return cast(void *)(e + 1) + keysize;
289 }
290
291
292 /*************************************************
293  * Get pointer to value in associative array indexed by key.
294  * Returns null if it is not already there.
295  * Used for both "aa[key]" and "key in aa"
296  * Returns:
297  *      null    not in aa
298  *      !=null  in aa, return pointer to value
299  */
300
301 void* _aaIn(AA aa, TypeInfo keyti, void *pkey)
302 in
303 {
304 }
305 out (result)
306 {
307     //assert(result == 0 || result == 1);
308 }
309 body
310 {
311     if (aa)
312     {
313         //auto pkey = cast(void *)(&keyti + 1);
314
315         //printf("_aaIn(), .length = %d, .ptr = %x\n", aa.length, cast(uint)aa.ptr);
316         auto len = aa.b.length;
317
318         if (len)
319         {
320             auto key_hash = keyti.getHash(pkey);
321             //printf("hash = %d\n", key_hash);
322             size_t i = key_hash % len;
323             auto e = aa.b[i];
324             while (e !is null)
325             {
326                 if (key_hash == e.hash)
327                 {
328                     auto c = keyti.compare(pkey, e + 1);
329                     if (c == 0)
330                         return cast(void *)(e + 1) + aligntsize(keyti.tsize());
331                     e = (c < 0) ? e.left : e.right;
332                 }
333                 else
334                     e = (key_hash < e.hash) ? e.left : e.right;
335             }
336         }
337     }
338
339     // Not found
340     return null;
341 }
342
343 /*************************************************
344  * Delete key entry in aa[].
345  * If key is not in aa[], do nothing.
346  */
347
348 void _aaDel(AA aa, TypeInfo keyti, void *pkey)
349 {
350     //auto pkey = cast(void *)(&keyti + 1);
351     aaA *e;
352
353     if (aa && aa.b.length)
354     {
355         auto key_hash = keyti.getHash(pkey);
356         //printf("hash = %d\n", key_hash);
357         size_t i = key_hash % aa.b.length;
358         auto pe = &aa.b[i];
359         while ((e = *pe) !is null) // null means not found
360         {
361             if (key_hash == e.hash)
362             {
363                 auto c = keyti.compare(pkey, e + 1);
364                 if (c == 0)
365                 {
366                     if (!e.left && !e.right)
367                     {
368                         *pe = null;
369                     }
370                     else if (e.left && !e.right)
371                     {
372                         *pe = e.left;
373                          e.left = null;
374                     }
375                     else if (!e.left && e.right)
376                     {
377                         *pe = e.right;
378                          e.right = null;
379                     }
380                     else
381                     {
382                         *pe = e.left;
383                         e.left = null;
384                         do
385                             pe = &(*pe).right;
386                         while (*pe);
387                         *pe = e.right;
388                         e.right = null;
389                     }
390
391                     aa.nodes--;
392                     gc_free(e);
393
394                     break;
395                 }
396                 pe = (c < 0) ? &e.left : &e.right;
397             }
398             else
399                 pe = (key_hash < e.hash) ? &e.left : &e.right;
400         }
401     }
402 }
403
404
405 /********************************************
406  * Produce array of values from aa.
407  * The actual type is painted on the return value by the frontend
408  * This means the returned length should be the number of elements
409  */
410
411 void[] _aaValues(AA aa, size_t keysize, size_t valuesize)
412 in
413 {
414     assert(keysize == aligntsize(keysize));
415 }
416 body
417 {
418     size_t resi;
419     void[] a;
420
421     void _aaValues_x(aaA* e)
422     {
423         do
424         {
425             memcpy(a.ptr + resi * valuesize,
426                    cast(byte*)e + aaA.sizeof + keysize,
427                    valuesize);
428             resi++;
429             if (e.left)
430             {   if (!e.right)
431                 {   e = e.left;
432                     continue;
433                 }
434                 _aaValues_x(e.left);
435             }
436             e = e.right;
437         } while (e !is null);
438     }
439
440     if (aa)
441     {
442         auto len = _aaLen(aa);
443         auto ptr = cast(byte*) gc_malloc(len * valuesize,
444                                       valuesize < (void*).sizeof ? BlkAttr.NO_SCAN : 0);
445         a = ptr[0 .. len];
446         resi = 0;
447         foreach (e; aa.b)
448         {
449             if (e)
450                 _aaValues_x(e);
451         }
452         assert(resi == a.length);
453     }
454     return a;
455 }
456
457
458 /********************************************
459  * Rehash an array.
460  */
461
462 void* _aaRehash(AA* paa, TypeInfo keyti)
463 in
464 {
465     //_aaInvAh(paa);
466 }
467 out (result)
468 {
469     //_aaInvAh(result);
470 }
471 body
472 {
473     BB newb;
474
475     void _aaRehash_x(aaA* olde)
476     {
477         while (1)
478         {
479             auto left = olde.left;
480             auto right = olde.right;
481             olde.left = null;
482             olde.right = null;
483
484             aaA *e;
485
486             //printf("rehash %p\n", olde);
487             auto key_hash = olde.hash;
488             size_t i = key_hash % newb.b.length;
489             auto pe = &newb.b[i];
490             while ((e = *pe) !is null)
491             {
492                 //printf("\te = %p, e.left = %p, e.right = %p\n", e, e.left, e.right);
493                 assert(e.left != e);
494                 assert(e.right != e);
495                 if (key_hash == e.hash)
496                 {
497                     auto c = keyti.compare(olde + 1, e + 1);
498                     assert(c != 0);
499                     pe = (c < 0) ? &e.left : &e.right;
500                 }
501                 else
502                     pe = (key_hash < e.hash) ? &e.left : &e.right;
503             }
504             *pe = olde;
505
506             if (right)
507             {
508                 if (!left)
509                 {   olde = right;
510                     continue;
511                 }
512                 _aaRehash_x(right);
513             }
514             if (!left)
515                 break;
516             olde = left;
517         }
518     }
519
520     //printf("Rehash\n");
521     if (*paa)
522     {
523         auto aa = *paa;
524         auto len = _aaLen(aa);
525         if (len)
526         {   size_t i;
527
528             for (i = 0; i < prime_list.length - 1; i++)
529             {
530                 if (len <= prime_list[i])
531                     break;
532             }
533             len = prime_list[i];
534             newb.b = new aaA*[len];
535             newb.keyti = keyti;
536
537             foreach (e; aa.b)
538             {
539                 if (e)
540                     _aaRehash_x(e);
541             }
542
543             newb.nodes = (*aa).nodes;
544         }
545
546         **paa = newb;
547     }
548     return *paa;
549 }
550
551
552 /********************************************
553  * Produce array of N byte keys from aa.
554  * The actual type is painted on the return value by the frontend
555  * This means the returned length should be the number of elements
556  */
557
558 void[] _aaKeys(AA aa, size_t keysize)
559 {
560     byte[] res;
561     size_t resi;
562
563     void _aaKeys_x(aaA* e)
564     {
565         do
566         {
567             memcpy(&res[resi * keysize], cast(byte*)(e + 1), keysize);
568             resi++;
569             if (e.left)
570             {   if (!e.right)
571                 {   e = e.left;
572                     continue;
573                 }
574                 _aaKeys_x(e.left);
575             }
576             e = e.right;
577         } while (e !is null);
578     }
579
580     auto len = _aaLen(aa);
581     if (!len)
582         return null;
583     res = (cast(byte*) gc_malloc(len * keysize,
584                                  !(aa.keyti.flags() & 1) ? BlkAttr.NO_SCAN : 0)) [0 .. len * keysize];
585     resi = 0;
586     foreach (e; aa.b)
587     {
588         if (e)
589             _aaKeys_x(e);
590     }
591     assert(resi == len);
592
593     return res.ptr[0 .. len];
594 }
595
596
597 /**********************************************
598  * 'apply' for associative arrays - to support foreach
599  */
600
601 // dg is D, but _aaApply() is C
602 extern (D) typedef int delegate(void *) dg_t;
603
604 int _aaApply(AA aa, size_t keysize, dg_t dg)
605 in
606 {
607     assert(aligntsize(keysize) == keysize);
608 }
609 body
610 {   int result;
611
612     //printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa, keysize, dg);
613
614     int treewalker(aaA* e)
615     {   int result;
616
617         do
618         {
619             //printf("treewalker(e = %p, dg = x%llx)\n", e, dg);
620             result = dg(cast(void *)(e + 1) + keysize);
621             if (result)
622                 break;
623             if (e.right)
624             {   if (!e.left)
625                 {
626                     e = e.right;
627                     continue;
628                 }
629                 result = treewalker(e.right);
630                 if (result)
631                     break;
632             }
633             e = e.left;
634         } while (e);
635
636         return result;
637     }
638
639     if (aa)
640     {
641         foreach (e; aa.b)
642         {
643             if (e)
644             {
645                 result = treewalker(e);
646                 if (result)
647                     break;
648             }
649         }
650     }
651     return result;
652 }
653
654 // dg is D, but _aaApply2() is C
655 extern (D) typedef int delegate(void *, void *) dg2_t;
656
657 int _aaApply2(AA aa, size_t keysize, dg2_t dg)
658 in
659 {
660     assert(aligntsize(keysize) == keysize);
661 }
662 body
663 {   int result;
664
665     //printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa, keysize, dg);
666
667     int treewalker(aaA* e)
668     {   int result;
669
670         do
671         {
672             //printf("treewalker(e = %p, dg = x%llx)\n", e, dg);
673             result = dg(cast(void *)(e + 1), cast(void *)(e + 1) + keysize);
674             if (result)
675                 break;
676             if (e.right)
677             {   if (!e.left)
678                 {
679                     e = e.right;
680                     continue;
681                 }
682                 result = treewalker(e.right);
683                 if (result)
684                     break;
685             }
686             e = e.left;
687         } while (e);
688
689         return result;
690     }
691
692     if (aa)
693     {
694         foreach (e; aa.b)
695         {
696             if (e)
697             {
698                 result = treewalker(e);
699                 if (result)
700                     break;
701             }
702         }
703     }
704     return result;
705 }
706
707
708 int _aaEq(AA aa, AA ab, TypeInfo_AssociativeArray ti)
709 {
710     return ti.equals(&aa, &ab);
711 }
712
713 /***********************************
714  * Construct an associative array of type ti from
715  * length pairs of key/value pairs.
716  */
717
718 /+
719
720 extern (C)
721 BB* _d_assocarrayliteralT(TypeInfo_AssociativeArray ti, size_t length, ...)
722 {
723     auto valuesize = ti.next.tsize();           // value size
724     auto keyti = ti.key;
725     auto keysize = keyti.tsize();               // key size
726     BB* result;
727
728     //printf("_d_assocarrayliteralT(keysize = %d, valuesize = %d, length = %d)\n", keysize, valuesize, length);
729     //printf("tivalue = %.*s\n", ti.next.classinfo.name);
730     if (length == 0 || valuesize == 0 || keysize == 0)
731     {
732         ;
733     }
734     else
735     {
736         va_list q;
737         va_start!(size_t)(q, length);
738
739         result = new BB();
740         size_t i;
741
742         for (i = 0; i < prime_list.length - 1; i++)
743         {
744             if (length <= prime_list[i])
745                 break;
746         }
747         auto len = prime_list[i];
748         result.b = new aaA*[len];
749
750         size_t keystacksize   = (keysize   + int.sizeof - 1) & ~(int.sizeof - 1);
751         size_t valuestacksize = (valuesize + int.sizeof - 1) & ~(int.sizeof - 1);
752
753         size_t keytsize = aligntsize(keysize);
754
755         for (size_t j = 0; j < length; j++)
756         {   void* pkey = q;
757             q += keystacksize;
758             void* pvalue = q;
759             q += valuestacksize;
760             aaA* e;
761
762             auto key_hash = keyti.getHash(pkey);
763             //printf("hash = %d\n", key_hash);
764             i = key_hash % len;
765             auto pe = &result.b[i];
766             while (1)
767             {
768                 e = *pe;
769                 if (!e)
770                 {
771                     // Not found, create new elem
772                     //printf("create new one\n");
773                     e = cast(aaA *) cast(void*) new void[aaA.sizeof + keytsize + valuesize];
774                     memcpy(e + 1, pkey, keysize);
775                     e.hash = key_hash;
776                     *pe = e;
777                     result.nodes++;
778                     break;
779                 }
780                 if (key_hash == e.hash)
781                 {
782                     auto c = keyti.compare(pkey, e + 1);
783                     if (c == 0)
784                         break;
785                     pe = (c < 0) ? &e.left : &e.right;
786                 }
787                 else
788                     pe = (key_hash < e.hash) ? &e.left : &e.right;
789             }
790             memcpy(cast(void *)(e + 1) + keytsize, pvalue, valuesize);
791         }
792
793         va_end(q);
794     }
795     return result;
796 }
797
798 +/
Note: See TracBrowser for help on using the browser.
Copyright © 2008, LDC Development Team.