Mercurial > projects > ldc
comparison lphobos/internal/aaA.d @ 109:5ab8e92611f9 trunk
[svn r113] Added initial support for associative arrays (AAs).
Fixed some problems with the string runtime support functions.
Fixed initialization of array of structs.
Fixed slice assignment where LHS is slice but RHS is dynamic array.
Fixed problems with result of assignment expressions.
Fixed foreach problems with key type mismatches.
author | lindquist |
---|---|
date | Wed, 21 Nov 2007 04:13:15 +0100 |
parents | 288fe1029e1f |
children | facc562f5674 |
comparison
equal
deleted
inserted
replaced
108:288fe1029e1f | 109:5ab8e92611f9 |
---|---|
25 * be misrepresented as being the original software. | 25 * be misrepresented as being the original software. |
26 * o This notice may not be removed or altered from any source | 26 * o This notice may not be removed or altered from any source |
27 * distribution. | 27 * distribution. |
28 */ | 28 */ |
29 | 29 |
30 /* | |
31 * Modified for LLVMDC by Tomas Lindquist Olsen. | |
32 * The DMD implementation wont quite work due to the differences in how | |
33 * structs are handled. | |
34 */ | |
35 | |
30 | 36 |
31 //import std.stdio; | 37 //import std.stdio; |
32 import std.c.stdarg; | 38 import std.c.stdarg; |
33 import std.c.stdio; | 39 import std.c.stdio; |
34 import std.c.stdlib; | 40 import std.c.stdlib; |
35 import std.c.string; | 41 import std.c.string; |
36 import std.string; | 42 //import std.string; |
37 | 43 |
38 import std.outofmemory; | 44 import std.outofmemory; |
39 | 45 |
40 // Auto-rehash and pre-allocate - Dave Fladebo | 46 // Auto-rehash and pre-allocate - Dave Fladebo |
41 | 47 |
49 1610612741UL, 4294967291UL | 55 1610612741UL, 4294967291UL |
50 ]; | 56 ]; |
51 | 57 |
52 /* This is the type of the return value for dynamic arrays. | 58 /* This is the type of the return value for dynamic arrays. |
53 * It should be a type that is returned in registers. | 59 * It should be a type that is returned in registers. |
54 * Although DMD will return types of Array in registers, | 60 */ |
55 * gcc will not, so we instead use a 'long'. | 61 alias Array ArrayRet_t; |
56 */ | 62 |
57 alias long ArrayRet_t; | 63 pragma(LLVM_internal, "notypeinfo") |
58 | |
59 struct Array | 64 struct Array |
60 { | 65 { |
61 size_t length; | 66 size_t length; |
62 void* ptr; | 67 void* ptr; |
63 } | 68 } |
64 | 69 |
70 pragma(LLVM_internal, "notypeinfo") | |
65 struct aaA | 71 struct aaA |
66 { | 72 { |
67 aaA *left; | 73 aaA *left; |
68 aaA *right; | 74 aaA *right; |
69 hash_t hash; | 75 hash_t hash; |
70 /* key */ | 76 /* key */ |
71 /* value */ | 77 /* value */ |
72 } | 78 } |
73 | 79 |
80 pragma(LLVM_internal, "notypeinfo") | |
74 struct BB | 81 struct BB |
75 { | 82 { |
76 aaA*[] b; | 83 aaA*[] b; |
77 size_t nodes; // total number of aaA nodes | 84 size_t nodes; // total number of aaA nodes |
78 } | 85 } |
79 | 86 |
80 /* This is the type actually seen by the programmer, although | 87 /* This is the type actually seen by the programmer, although |
81 * it is completely opaque. | 88 * it is completely opaque. |
82 */ | 89 */ |
83 | 90 |
84 struct AA | 91 alias BB* AA; |
85 { | |
86 BB* a; | |
87 } | |
88 | 92 |
89 /********************************** | 93 /********************************** |
90 * Align to next pointer boundary, so that | 94 * Align to next pointer boundary, so that |
91 * GC won't be faced with misaligned pointers | 95 * GC won't be faced with misaligned pointers |
92 * in value. | 96 * in value. |
196 break; | 200 break; |
197 len++; | 201 len++; |
198 } | 202 } |
199 } | 203 } |
200 | 204 |
201 if (aa.a) | 205 if (aa) |
202 { | 206 { |
203 foreach (e; aa.a.b) | 207 foreach (e; aa.b) |
204 { | 208 { |
205 if (e) | 209 if (e) |
206 _aaLen_x(e); | 210 _aaLen_x(e); |
207 } | 211 } |
208 } | 212 } |
210 | 214 |
211 //printf("_aaLen()-\n"); | 215 //printf("_aaLen()-\n"); |
212 } | 216 } |
213 body | 217 body |
214 { | 218 { |
215 return aa.a ? aa.a.nodes : 0; | 219 return aa ? aa.nodes : 0; |
216 } | 220 } |
217 | 221 |
218 | 222 |
219 /************************************************* | 223 /************************************************* |
220 * Get pointer to value in associative array indexed by key. | 224 * Get pointer to value in associative array indexed by key. |
221 * Add entry for key if it is not already there. | 225 * Add entry for key if it is not already there. |
222 */ | 226 */ |
223 | 227 |
224 void* _aaGet(AA* aa, TypeInfo keyti, size_t valuesize, ...) | 228 void* _aaGet(AA* aa, TypeInfo keyti, void* pkey, size_t valuesize) |
225 in | 229 in |
226 { | 230 { |
227 assert(aa); | 231 assert(aa); |
228 } | 232 } |
229 out (result) | 233 out (result) |
230 { | 234 { |
231 assert(result); | 235 assert(result); |
232 assert(aa.a); | 236 assert(*aa); |
233 assert(aa.a.b.length); | 237 assert((*aa).b.length); |
234 //assert(_aaInAh(*aa.a, key)); | 238 //assert(_aaInAh(*aa, key)); |
235 } | 239 } |
236 body | 240 body |
237 { | 241 { |
238 auto pkey = cast(void *)(&valuesize + 1); | 242 //auto pkey = cast(void *)(&valuesize + 1); |
239 size_t i; | 243 size_t i; |
240 aaA* e; | 244 aaA* e; |
241 auto keysize = aligntsize(keyti.tsize()); | 245 auto keysize = aligntsize(keyti.tsize()); |
242 | 246 |
243 if (!aa.a) | 247 if (!*aa) |
244 aa.a = new BB(); | 248 *aa = new BB(); |
245 | 249 |
246 if (!aa.a.b.length) | 250 if (!(*aa).b.length) |
247 { | 251 { |
248 alias aaA *pa; | 252 alias aaA *pa; |
249 auto len = prime_list[0]; | 253 auto len = prime_list[0]; |
250 | 254 |
251 aa.a.b = new pa[len]; | 255 (*aa).b = new pa[len]; |
252 } | 256 } |
253 | 257 |
254 auto key_hash = keyti.getHash(pkey); | 258 auto key_hash = keyti.getHash(pkey); |
255 //printf("hash = %d\n", key_hash); | 259 //printf("hash = %d\n", key_hash); |
256 i = key_hash % aa.a.b.length; | 260 i = key_hash % (*aa).b.length; |
257 auto pe = &aa.a.b[i]; | 261 auto pe = &(*aa).b[i]; |
258 while ((e = *pe) != null) | 262 while ((e = *pe) != null) |
259 { | 263 { |
260 if (key_hash == e.hash) | 264 if (key_hash == e.hash) |
261 { | 265 { |
262 auto c = keyti.compare(pkey, e + 1); | 266 auto c = keyti.compare(pkey, e + 1); |
273 e = cast(aaA *) cast(void*) new void[aaA.sizeof + keysize + valuesize]; | 277 e = cast(aaA *) cast(void*) new void[aaA.sizeof + keysize + valuesize]; |
274 memcpy(e + 1, pkey, keysize); | 278 memcpy(e + 1, pkey, keysize); |
275 e.hash = key_hash; | 279 e.hash = key_hash; |
276 *pe = e; | 280 *pe = e; |
277 | 281 |
278 auto nodes = ++aa.a.nodes; | 282 auto nodes = ++(*aa).nodes; |
279 //printf("length = %d, nodes = %d\n", (*aa.a).length, nodes); | 283 //printf("length = %d, nodes = %d\n", (*aa).length, nodes); |
280 if (nodes > aa.a.b.length * 4) | 284 if (nodes > (*aa).b.length * 4) |
281 { | 285 { |
282 _aaRehash(aa,keyti); | 286 _aaRehash(aa,keyti); |
283 } | 287 } |
284 | 288 |
285 Lret: | 289 Lret: |
290 /************************************************* | 294 /************************************************* |
291 * Get pointer to value in associative array indexed by key. | 295 * Get pointer to value in associative array indexed by key. |
292 * Returns null if it is not already there. | 296 * Returns null if it is not already there. |
293 */ | 297 */ |
294 | 298 |
295 void* _aaGetRvalue(AA aa, TypeInfo keyti, size_t valuesize, ...) | 299 void* _aaGetRvalue(AA aa, TypeInfo keyti, size_t valuesize, void* pkey) |
296 { | 300 { |
297 //printf("_aaGetRvalue(valuesize = %u)\n", valuesize); | 301 //printf("_aaGetRvalue(valuesize = %u)\n", valuesize); |
298 if (!aa.a) | 302 if (!aa) |
299 return null; | 303 return null; |
300 | 304 |
301 auto pkey = cast(void *)(&valuesize + 1); | 305 //auto pkey = cast(void *)(&valuesize + 1); |
302 auto keysize = aligntsize(keyti.tsize()); | 306 auto keysize = aligntsize(keyti.tsize()); |
303 auto len = aa.a.b.length; | 307 auto len = aa.b.length; |
304 | 308 |
305 if (len) | 309 if (len) |
306 { | 310 { |
307 auto key_hash = keyti.getHash(pkey); | 311 auto key_hash = keyti.getHash(pkey); |
308 //printf("hash = %d\n", key_hash); | 312 //printf("hash = %d\n", key_hash); |
309 size_t i = key_hash % len; | 313 size_t i = key_hash % len; |
310 auto e = aa.a.b[i]; | 314 auto e = aa.b[i]; |
311 while (e != null) | 315 while (e != null) |
312 { | 316 { |
313 if (key_hash == e.hash) | 317 if (key_hash == e.hash) |
314 { | 318 { |
315 auto c = keyti.compare(pkey, e + 1); | 319 auto c = keyti.compare(pkey, e + 1); |
330 * Returns: | 334 * Returns: |
331 * null not in aa | 335 * null not in aa |
332 * !=null in aa, return pointer to value | 336 * !=null in aa, return pointer to value |
333 */ | 337 */ |
334 | 338 |
335 void* _aaIn(AA aa, TypeInfo keyti, ...) | 339 void* _aaIn(AA aa, TypeInfo keyti, void* pkey) |
336 in | 340 in |
337 { | 341 { |
338 } | 342 } |
339 out (result) | 343 out (result) |
340 { | 344 { |
341 //assert(result == 0 || result == 1); | 345 //assert(result == 0 || result == 1); |
342 } | 346 } |
343 body | 347 body |
344 { | 348 { |
345 if (aa.a) | 349 if (aa) |
346 { | 350 { |
347 auto pkey = cast(void *)(&keyti + 1); | 351 //auto pkey = cast(void *)(&keyti + 1); |
348 | 352 |
349 //printf("_aaIn(), .length = %d, .ptr = %x\n", aa.a.length, cast(uint)aa.a.ptr); | 353 //printf("_aaIn(), .length = %d, .ptr = %x\n", aa.length, cast(uint)aa.ptr); |
350 auto len = aa.a.b.length; | 354 auto len = aa.b.length; |
351 | 355 |
352 if (len) | 356 if (len) |
353 { | 357 { |
354 auto key_hash = keyti.getHash(pkey); | 358 auto key_hash = keyti.getHash(pkey); |
355 //printf("hash = %d\n", key_hash); | 359 //printf("hash = %d\n", key_hash); |
356 size_t i = key_hash % len; | 360 size_t i = key_hash % len; |
357 auto e = aa.a.b[i]; | 361 auto e = aa.b[i]; |
358 while (e != null) | 362 while (e != null) |
359 { | 363 { |
360 if (key_hash == e.hash) | 364 if (key_hash == e.hash) |
361 { | 365 { |
362 auto c = keyti.compare(pkey, e + 1); | 366 auto c = keyti.compare(pkey, e + 1); |
378 /************************************************* | 382 /************************************************* |
379 * Delete key entry in aa[]. | 383 * Delete key entry in aa[]. |
380 * If key is not in aa[], do nothing. | 384 * If key is not in aa[], do nothing. |
381 */ | 385 */ |
382 | 386 |
383 void _aaDel(AA aa, TypeInfo keyti, ...) | 387 void _aaDel(AA aa, TypeInfo keyti, void* pkey) |
384 { | 388 { |
385 auto pkey = cast(void *)(&keyti + 1); | 389 //auto pkey = cast(void *)(&keyti + 1); |
386 aaA* e; | 390 aaA* e; |
387 | 391 |
388 if (aa.a && aa.a.b.length) | 392 if (aa && aa.b.length) |
389 { | 393 { |
390 auto key_hash = keyti.getHash(pkey); | 394 auto key_hash = keyti.getHash(pkey); |
391 //printf("hash = %d\n", key_hash); | 395 //printf("hash = %d\n", key_hash); |
392 size_t i = key_hash % aa.a.b.length; | 396 size_t i = key_hash % aa.b.length; |
393 auto pe = &aa.a.b[i]; | 397 auto pe = &aa.b[i]; |
394 while ((e = *pe) != null) // null means not found | 398 while ((e = *pe) != null) // null means not found |
395 { | 399 { |
396 if (key_hash == e.hash) | 400 if (key_hash == e.hash) |
397 { | 401 { |
398 auto c = keyti.compare(pkey, e + 1); | 402 auto c = keyti.compare(pkey, e + 1); |
421 while (*pe); | 425 while (*pe); |
422 *pe = e.right; | 426 *pe = e.right; |
423 e.right = null; | 427 e.right = null; |
424 } | 428 } |
425 | 429 |
426 aa.a.nodes--; | 430 aa.nodes--; |
427 | 431 |
428 // Should notify GC that e can be free'd now | 432 // Should notify GC that e can be free'd now |
429 break; | 433 break; |
430 } | 434 } |
431 pe = (c < 0) ? &e.left : &e.right; | 435 pe = (c < 0) ? &e.left : &e.right; |
468 } | 472 } |
469 e = e.right; | 473 e = e.right; |
470 } while (e != null); | 474 } while (e != null); |
471 } | 475 } |
472 | 476 |
473 if (aa.a) | 477 if (aa) |
474 { | 478 { |
475 a.length = _aaLen(aa); | 479 a.length = _aaLen(aa); |
476 a.ptr = (new void[a.length * valuesize]).ptr; | 480 a.ptr = (new void[a.length * valuesize]).ptr; |
477 resi = 0; | 481 resi = 0; |
478 foreach (e; aa.a.b) | 482 foreach (e; aa.b) |
479 { | 483 { |
480 if (e) | 484 if (e) |
481 _aaValues_x(e); | 485 _aaValues_x(e); |
482 } | 486 } |
483 assert(resi == a.length); | 487 assert(resi == a.length); |
484 } | 488 } |
485 return *cast(ArrayRet_t*)(&a); | 489 return a; |
486 } | 490 } |
487 | 491 |
488 | 492 |
489 /******************************************** | 493 /******************************************** |
490 * Rehash an array. | 494 * Rehash an array. |
491 */ | 495 */ |
492 | 496 |
493 void* _aaRehash(AA* paa, TypeInfo keyti) | 497 void* _aaRehash(AA* paa, TypeInfo keyti) |
494 in | 498 in |
495 { | 499 { |
500 assert(paa); | |
496 //_aaInvAh(paa); | 501 //_aaInvAh(paa); |
497 } | 502 } |
498 out (result) | 503 out (result) |
499 { | 504 { |
500 //_aaInvAh(result); | 505 //_aaInvAh(result); |
547 olde = left; | 552 olde = left; |
548 } | 553 } |
549 } | 554 } |
550 | 555 |
551 //printf("Rehash\n"); | 556 //printf("Rehash\n"); |
552 if (paa.a) | 557 if (paa) |
553 { | 558 { |
554 auto aa = paa.a; | 559 auto aa = *paa; |
555 auto len = _aaLen(*paa); | 560 auto len = _aaLen(*paa); |
556 if (len) | 561 if (len) |
557 { size_t i; | 562 { size_t i; |
558 | 563 |
559 for (i = 0; i < prime_list.length - 1; i++) | 564 for (i = 0; i < prime_list.length - 1; i++) |
571 } | 576 } |
572 | 577 |
573 newb.nodes = aa.nodes; | 578 newb.nodes = aa.nodes; |
574 } | 579 } |
575 | 580 |
576 *paa.a = newb; | 581 **paa = newb; |
577 } | 582 } |
578 return (*paa).a; | 583 return *paa; |
579 } | 584 } |
580 | 585 |
581 | 586 |
582 /******************************************** | 587 /******************************************** |
583 * Produce array of N byte keys from aa. | 588 * Produce array of N byte keys from aa. |
605 } while (e != null); | 610 } while (e != null); |
606 } | 611 } |
607 | 612 |
608 auto len = _aaLen(aa); | 613 auto len = _aaLen(aa); |
609 if (!len) | 614 if (!len) |
610 return 0; | 615 return ArrayRet_t.init; |
611 res = cast(byte[])new void[len * keysize]; | 616 res = cast(byte[])new void[len * keysize]; |
612 resi = 0; | 617 resi = 0; |
613 foreach (e; aa.a.b) | 618 foreach (e; aa.b) |
614 { | 619 { |
615 if (e) | 620 if (e) |
616 _aaKeys_x(e); | 621 _aaKeys_x(e); |
617 } | 622 } |
618 assert(resi == len); | 623 assert(resi == len); |
619 | 624 |
620 Array a; | 625 return Array(len, res.ptr); |
621 a.length = len; | |
622 a.ptr = res.ptr; | |
623 return *cast(ArrayRet_t*)(&a); | |
624 } | 626 } |
625 | 627 |
626 | 628 |
627 /********************************************** | 629 /********************************************** |
628 * 'apply' for associative arrays - to support foreach | 630 * 'apply' for associative arrays - to support foreach |
637 assert(aligntsize(keysize) == keysize); | 639 assert(aligntsize(keysize) == keysize); |
638 } | 640 } |
639 body | 641 body |
640 { int result; | 642 { int result; |
641 | 643 |
642 //printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa.a, keysize, dg); | 644 //printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa, keysize, dg); |
643 | 645 |
644 int treewalker(aaA* e) | 646 int treewalker(aaA* e) |
645 { int result; | 647 { int result; |
646 | 648 |
647 do | 649 do |
664 } while (e); | 666 } while (e); |
665 | 667 |
666 return result; | 668 return result; |
667 } | 669 } |
668 | 670 |
669 if (aa.a) | 671 if (aa) |
670 { | 672 { |
671 foreach (e; aa.a.b) | 673 foreach (e; aa.b) |
672 { | 674 { |
673 if (e) | 675 if (e) |
674 { | 676 { |
675 result = treewalker(e); | 677 result = treewalker(e); |
676 if (result) | 678 if (result) |
690 assert(aligntsize(keysize) == keysize); | 692 assert(aligntsize(keysize) == keysize); |
691 } | 693 } |
692 body | 694 body |
693 { int result; | 695 { int result; |
694 | 696 |
695 //printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa.a, keysize, dg); | 697 //printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa, keysize, dg); |
696 | 698 |
697 int treewalker(aaA* e) | 699 int treewalker(aaA* e) |
698 { int result; | 700 { int result; |
699 | 701 |
700 do | 702 do |
717 } while (e); | 719 } while (e); |
718 | 720 |
719 return result; | 721 return result; |
720 } | 722 } |
721 | 723 |
722 if (aa.a) | 724 if (aa) |
723 { | 725 { |
724 foreach (e; aa.a.b) | 726 foreach (e; aa.b) |
725 { | 727 { |
726 if (e) | 728 if (e) |
727 { | 729 { |
728 result = treewalker(e); | 730 result = treewalker(e); |
729 if (result) | 731 if (result) |