comparison tango/lib/compiler/llvmdc/aaA.d @ 132:1700239cab2e trunk

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