From 6ae1818de7ac98b7c1d8459adfcacb82d2ffa816 Mon Sep 17 00:00:00 2001
From: Luben Karavelov <karavelov@spnet.net>
Date: Sat, 14 Aug 2010 20:12:46 +0300
Subject: [PATCH] Add hash iteration macros in hash.h and use them
---
include/parrot/hash.h | 43 +++++++++++++++++
src/hash.c | 119 +++++++++++++--------------------------------
src/packfile.c | 22 ++------
src/pmc/callcontext.pmc | 59 +++++-----------------
src/pmc/hashiterator.pmc | 17 +------
src/pmc/lexinfo.pmc | 22 ++-------
6 files changed, 103 insertions(+), 179 deletions(-)
diff --git a/include/parrot/hash.h b/include/parrot/hash.h
index 84e3c70..fe9bfba 100644
|
a
|
b
|
|
| 78 | 78 | hash_hash_key_fn hash_val; |
| 79 | 79 | }; |
| 80 | 80 | |
| | 81 | /* Utility macros - use them, do not reinvent the weel */ |
| | 82 | #define parrot_hash_iterate parrot_hash_iterate_linear |
| | 83 | |
| | 84 | #define parrot_hash_iterate_linear(_hash, _code) \ |
| | 85 | { \ |
| | 86 | UINTVAL _found=0; \ |
| | 87 | HashBucket *_bucket = (_hash)->buckets; \ |
| | 88 | while (_found < _hash->entries){ \ |
| | 89 | if (_bucket->key){ \ |
| | 90 | _code \ |
| | 91 | _found++; \ |
| | 92 | } \ |
| | 93 | _bucket++; \ |
| | 94 | } \ |
| | 95 | } |
| | 96 | |
| | 97 | #define parrot_hash_iterate_indexed(_hash, _code) \ |
| | 98 | { \ |
| | 99 | INTVAL _loc; \ |
| | 100 | for (_loc = (_hash)->mask; _loc >= 0; --_loc) { \ |
| | 101 | HashBucket *_bucket = (_hash)->bucket_indices[_loc]; \ |
| | 102 | while (_bucket) { \ |
| | 103 | _code \ |
| | 104 | _bucket = _bucket->next; \ |
| | 105 | } \ |
| | 106 | } \ |
| | 107 | } |
| | 108 | |
| | 109 | |
| | 110 | #define parrot_hash_iterator_advance(_hash,_bucket,_loc) \ |
| | 111 | { \ |
| | 112 | /* Try to advance current bucket */ \ |
| | 113 | if ((_bucket)) \ |
| | 114 | (_bucket) = (_bucket)->next; \ |
| | 115 | while (!(_bucket)) { \ |
| | 116 | /* If there is no more buckets */ \ |
| | 117 | if ((_loc) == (INTVAL)(_hash)->mask+1) \ |
| | 118 | break; \ |
| | 119 | (_bucket) = (_hash)->bucket_indices[_loc++]; \ |
| | 120 | } \ |
| | 121 | } |
| | 122 | |
| | 123 | |
| 81 | 124 | typedef void (*value_free)(ARGFREE(void *)); |
| 82 | 125 | |
| 83 | 126 | /* To avoid creating OrderedHashItem PMC we reuse FixedPMCArray PMC */ |
diff --git a/src/hash.c b/src/hash.c
index 7605693..968733b 100644
|
a
|
b
|
|
| 512 | 512 | parrot_mark_hash_keys(PARROT_INTERP, ARGIN(Hash *hash)) |
| 513 | 513 | { |
| 514 | 514 | ASSERT_ARGS(parrot_mark_hash_keys) |
| 515 | | const UINTVAL entries = hash->entries; |
| 516 | | UINTVAL found = 0; |
| 517 | | UINTVAL i; |
| 518 | | |
| 519 | | HashBucket *bucket = hash->buckets; |
| 520 | | |
| 521 | | for (i= 0; i <= hash->mask; ++i, ++bucket) { |
| 522 | | if (bucket->key){ |
| 523 | | |
| 524 | | PARROT_ASSERT(bucket->key); |
| 525 | | Parrot_gc_mark_PObj_alive(interp, (PObj *)bucket->key); |
| 526 | | |
| 527 | | if (++found >= entries) |
| 528 | | break; |
| 529 | | } |
| 530 | | } |
| | 515 | parrot_hash_iterate(hash, |
| | 516 | PARROT_ASSERT(_bucket->key); |
| | 517 | Parrot_gc_mark_PObj_alive(interp, (PObj *)_bucket->key); |
| | 518 | ); |
| 531 | 519 | } |
| 532 | 520 | |
| 533 | 521 | |
| … |
… |
|
| 545 | 533 | parrot_mark_hash_values(PARROT_INTERP, ARGIN(Hash *hash)) |
| 546 | 534 | { |
| 547 | 535 | ASSERT_ARGS(parrot_mark_hash_values) |
| 548 | | const UINTVAL entries = hash->entries; |
| 549 | | UINTVAL found = 0; |
| 550 | | UINTVAL i; |
| 551 | | |
| 552 | | HashBucket *bucket = hash->buckets; |
| 553 | | |
| 554 | | for (i= 0; i <= hash->mask; ++i, ++bucket) { |
| 555 | | if (bucket->key){ |
| 556 | | |
| 557 | | PARROT_ASSERT(bucket->value); |
| 558 | | Parrot_gc_mark_PObj_alive(interp, (PObj *)bucket->value); |
| 559 | | |
| 560 | | if (++found >= entries) |
| 561 | | break; |
| 562 | | } |
| 563 | | } |
| | 536 | parrot_hash_iterate(hash, |
| | 537 | PARROT_ASSERT(_bucket->value); |
| | 538 | Parrot_gc_mark_PObj_alive(interp, (PObj *)_bucket->value); |
| | 539 | ); |
| 564 | 540 | } |
| 565 | 541 | |
| | 542 | |
| 566 | 543 | /* |
| 567 | 544 | |
| 568 | 545 | =item C<static void parrot_mark_hash_both(PARROT_INTERP, Hash *hash)> |
| … |
… |
|
| 577 | 554 | parrot_mark_hash_both(PARROT_INTERP, ARGIN(Hash *hash)) |
| 578 | 555 | { |
| 579 | 556 | ASSERT_ARGS(parrot_mark_hash_both) |
| 580 | | const UINTVAL entries = hash->entries; |
| 581 | | UINTVAL found = 0; |
| 582 | | UINTVAL i; |
| 583 | | |
| 584 | | HashBucket *bucket = hash->buckets; |
| 585 | | |
| 586 | | for (i= 0; i <= hash->mask; ++i, ++bucket) { |
| 587 | | if (bucket->key){ |
| 588 | | PARROT_ASSERT(bucket->key); |
| 589 | | Parrot_gc_mark_PObj_alive(interp, (PObj *)bucket->key); |
| 590 | | |
| 591 | | PARROT_ASSERT(bucket->value); |
| 592 | | Parrot_gc_mark_PObj_alive(interp, (PObj *)bucket->value); |
| 593 | | |
| 594 | | if (++found >= entries) |
| 595 | | break; |
| 596 | | } |
| 597 | | } |
| | 557 | parrot_hash_iterate(hash, |
| | 558 | PARROT_ASSERT(_bucket->key); |
| | 559 | Parrot_gc_mark_PObj_alive(interp, (PObj *)_bucket->key); |
| | 560 | PARROT_ASSERT(_bucket->value); |
| | 561 | Parrot_gc_mark_PObj_alive(interp, (PObj *)_bucket->value); |
| | 562 | ); |
| 598 | 563 | } |
| 599 | 564 | |
| 600 | 565 | /* |
| … |
… |
|
| 714 | 679 | const size_t entries = hash->entries; |
| 715 | 680 | size_t i; |
| 716 | 681 | |
| 717 | | for (i = 0; i < entries; ++i) { |
| 718 | | HashBucket * const b = hash->buckets + i; |
| 719 | | |
| | 682 | parrot_hash_iterate(hash, |
| 720 | 683 | switch (key_type) { |
| 721 | 684 | case Hash_key_type_int: |
| 722 | | VTABLE_push_integer(interp, info, (INTVAL)b->key); |
| | 685 | VTABLE_push_integer(interp, info, (INTVAL)_bucket->key); |
| 723 | 686 | break; |
| 724 | 687 | case Hash_key_type_STRING: |
| 725 | | VTABLE_push_string(interp, info, (STRING *)b->key); |
| | 688 | VTABLE_push_string(interp, info, (STRING *)_bucket->key); |
| 726 | 689 | break; |
| 727 | 690 | case Hash_key_type_PMC: |
| 728 | | VTABLE_push_pmc(interp, info, (PMC *)b->key); |
| | 691 | VTABLE_push_pmc(interp, info, (PMC *)_bucket->key); |
| 729 | 692 | break; |
| 730 | 693 | default: |
| 731 | 694 | Parrot_ex_throw_from_c_args(interp, NULL, 1, |
| 732 | 695 | "unimplemented key type"); |
| 733 | 696 | break; |
| 734 | 697 | } |
| 735 | | |
| 736 | 698 | switch (entry_type) { |
| 737 | 699 | case enum_hash_int: |
| 738 | | VTABLE_push_integer(interp, info, (INTVAL)b->value); |
| | 700 | VTABLE_push_integer(interp, info, (INTVAL)_bucket->value); |
| 739 | 701 | break; |
| 740 | 702 | case enum_hash_string: |
| 741 | | VTABLE_push_string(interp, info, (STRING *)b->value); |
| | 703 | VTABLE_push_string(interp, info, (STRING *)_bucket->value); |
| 742 | 704 | break; |
| 743 | 705 | case enum_hash_pmc: |
| 744 | | VTABLE_push_pmc(interp, info, (PMC *)b->value); |
| | 706 | VTABLE_push_pmc(interp, info, (PMC *)_bucket->value); |
| 745 | 707 | break; |
| 746 | 708 | default: |
| 747 | 709 | Parrot_ex_throw_from_c_args(interp, NULL, 1, |
| 748 | 710 | "unimplemented value type"); |
| 749 | 711 | break; |
| 750 | 712 | } |
| 751 | | } |
| | 713 | ); |
| 752 | 714 | } |
| 753 | 715 | |
| 754 | 716 | |
| … |
… |
|
| 1121 | 1083 | parrot_chash_destroy(PARROT_INTERP, ARGMOD(Hash *hash)) |
| 1122 | 1084 | { |
| 1123 | 1085 | ASSERT_ARGS(parrot_chash_destroy) |
| 1124 | | UINTVAL i; |
| 1125 | | |
| 1126 | | for (i = 0; i <= hash->mask; ++i) { |
| 1127 | | HashBucket *bucket = hash->bucket_indices[i]; |
| 1128 | | while (bucket) { |
| 1129 | | mem_gc_free(interp, bucket->key); |
| 1130 | | mem_gc_free(interp, bucket->value); |
| 1131 | | bucket = bucket->next; |
| 1132 | | } |
| 1133 | | } |
| 1134 | | |
| | 1086 | parrot_hash_iterate(hash, |
| | 1087 | mem_gc_free(interp, _bucket->key); |
| | 1088 | mem_gc_free(interp, _bucket->value); |
| | 1089 | ); |
| 1135 | 1090 | parrot_hash_destroy(interp, hash); |
| 1136 | 1091 | } |
| 1137 | 1092 | |
| … |
… |
|
| 1472 | 1427 | ARGOUT(Hash *dest), int deep) |
| 1473 | 1428 | { |
| 1474 | 1429 | ASSERT_ARGS(parrot_hash_clone_prunable) |
| 1475 | | UINTVAL entries = hash->entries; |
| 1476 | | UINTVAL i; |
| 1477 | 1430 | |
| 1478 | | for (i = 0; i < entries; ++i) { |
| | 1431 | parrot_hash_iterate(hash, |
| 1479 | 1432 | void *valtmp; |
| 1480 | | HashBucket *b = hash->buckets + i; |
| 1481 | | void * const key = b->key; |
| | 1433 | void * const key = _bucket->key; |
| 1482 | 1434 | |
| 1483 | 1435 | switch (hash->entry_type) { |
| 1484 | 1436 | case enum_type_undef: |
| 1485 | 1437 | case enum_type_ptr: |
| 1486 | 1438 | case enum_type_INTVAL: |
| 1487 | | valtmp = (void *)b->value; |
| | 1439 | valtmp = (void *)_bucket->value; |
| 1488 | 1440 | break; |
| 1489 | 1441 | |
| 1490 | 1442 | case enum_type_STRING: |
| 1491 | | valtmp = b->value; |
| | 1443 | valtmp = _bucket->value; |
| 1492 | 1444 | break; |
| 1493 | 1445 | |
| 1494 | 1446 | case enum_type_PMC: |
| 1495 | | if (PMC_IS_NULL((PMC *)b->value)) |
| | 1447 | if (PMC_IS_NULL((PMC *)_bucket->value)) |
| 1496 | 1448 | valtmp = (void *)PMCNULL; |
| 1497 | 1449 | else |
| 1498 | 1450 | if (deep) |
| 1499 | | valtmp = (void *)VTABLE_clone(interp, (PMC*)b->value); |
| | 1451 | valtmp = (void *)VTABLE_clone(interp, (PMC*)_bucket->value); |
| 1500 | 1452 | else |
| 1501 | | valtmp = b->value; |
| | 1453 | valtmp = _bucket->value; |
| 1502 | 1454 | break; |
| 1503 | 1455 | |
| 1504 | 1456 | default: |
| … |
… |
|
| 1506 | 1458 | Parrot_ex_throw_from_c_args(interp, NULL, -1, |
| 1507 | 1459 | "hash corruption: type = %d\n", hash->entry_type); |
| 1508 | 1460 | }; |
| 1509 | | |
| 1510 | 1461 | if (key) |
| 1511 | 1462 | parrot_hash_put(interp, dest, key, valtmp); |
| 1512 | | } |
| | 1463 | ); |
| 1513 | 1464 | } |
| 1514 | 1465 | |
| 1515 | 1466 | /* |
diff --git a/src/packfile.c b/src/packfile.c
index 7320776..672dbea 100644
|
a
|
b
|
|
| 3471 | 3471 | if (!hash) |
| 3472 | 3472 | return; |
| 3473 | 3473 | |
| 3474 | | for (i = 0; i <= hash->mask; ++i) { |
| 3475 | | HashBucket *bucket = hash->bucket_indices[i]; |
| 3476 | | |
| 3477 | | while (bucket) { |
| 3478 | | PackFile_ConstTable * const table = |
| 3479 | | (PackFile_ConstTable *)bucket->key; |
| 3480 | | PackFile_Constant * const orig_consts = table->constants; |
| 3481 | | PackFile_Constant * const consts = |
| 3482 | | (PackFile_Constant *) bucket->value; |
| 3483 | | INTVAL j; |
| 3484 | | |
| 3485 | | mem_gc_free(interp, consts); |
| 3486 | | bucket = bucket->next; |
| 3487 | | } |
| 3488 | | } |
| 3489 | | |
| | 3474 | parrot_hash_iterate(hash, |
| | 3475 | PackFile_ConstTable * const table = (PackFile_ConstTable *)_bucket->key; |
| | 3476 | PackFile_Constant * const orig_consts = table->constants; |
| | 3477 | PackFile_Constant * const consts = (PackFile_Constant *) _bucket->value; |
| | 3478 | mem_gc_free(interp, consts); |
| | 3479 | ); |
| 3490 | 3480 | parrot_hash_destroy(interp, hash); |
| 3491 | 3481 | } |
| 3492 | 3482 | |
diff --git a/src/pmc/callcontext.pmc b/src/pmc/callcontext.pmc
index a73503c..f2a5ac3 100644
|
a
|
b
|
|
| 378 | 378 | mark_hash(PARROT_INTERP, ARGIN(Hash *h)) |
| 379 | 379 | { |
| 380 | 380 | ASSERT_ARGS(mark_hash) |
| 381 | | INTVAL i; |
| 382 | | |
| 383 | | for (i = h->mask; i >= 0; --i) { |
| 384 | | HashBucket *b = h->bucket_indices[i]; |
| 385 | | |
| 386 | | while (b) { |
| 387 | | Parrot_gc_mark_STRING_alive(interp, (STRING *)b->key); |
| 388 | | mark_cell(interp, (Pcc_cell *)b->value); |
| 389 | | b = b->next; |
| 390 | | } |
| 391 | | } |
| | 381 | parrot_hash_iterate(h, |
| | 382 | Parrot_gc_mark_STRING_alive(interp, (STRING *)_bucket->key); |
| | 383 | mark_cell(interp, (Pcc_cell *)_bucket->value); |
| | 384 | ); |
| 392 | 385 | } |
| 393 | 386 | |
| 394 | 387 | PARROT_CAN_RETURN_NULL |
| … |
… |
|
| 402 | 395 | |
| 403 | 396 | /* yes, this *looks* risky, but it's a Parrot STRING hash internally */ |
| 404 | 397 | if (hash && hash->entries) { |
| 405 | | UINTVAL i, j = 0; |
| | 398 | UINTVAL j = 0; |
| 406 | 399 | PMC *result = Parrot_pmc_new_init_int(interp, enum_class_FixedStringArray, hash->entries); |
| 407 | | |
| 408 | | for (i = 0; i <= hash->mask; ++i) { |
| 409 | | HashBucket *b = hash->bucket_indices[i]; |
| 410 | | |
| 411 | | while (b) { |
| 412 | | VTABLE_set_string_keyed_int(interp, result, |
| 413 | | j++, (STRING *)b->key); |
| 414 | | b = b->next; |
| 415 | | } |
| 416 | | } |
| 417 | | |
| | 400 | parrot_hash_iterate(hash, |
| | 401 | VTABLE_set_string_keyed_int(interp, result, j++, (STRING *)_bucket->key); |
| | 402 | ); |
| 418 | 403 | return result; |
| 419 | 404 | } |
| 420 | 405 | |
| … |
… |
|
| 604 | 589 | GET_ATTR_hash(INTERP, SELF, hash); |
| 605 | 590 | |
| 606 | 591 | if (hash) { |
| 607 | | UINTVAL i; |
| 608 | | |
| 609 | | for (i = 0; i <= hash->mask; ++i) { |
| 610 | | HashBucket *b = hash->bucket_indices[i]; |
| 611 | | |
| 612 | | while (b) { |
| 613 | | FREE_CELL(INTERP, (Pcc_cell *)b->value); |
| 614 | | b = b->next; |
| 615 | | } |
| 616 | | } |
| 617 | | |
| | 592 | parrot_hash_iterate(hash, |
| | 593 | FREE_CELL(INTERP, (Pcc_cell *)_bucket->value); |
| | 594 | ); |
| 618 | 595 | parrot_hash_destroy(INTERP, hash); |
| 619 | 596 | SET_ATTR_hash(INTERP, SELF, NULL); |
| 620 | 597 | } |
| … |
… |
|
| 642 | 619 | } |
| 643 | 620 | |
| 644 | 621 | if (hash) { |
| 645 | | UINTVAL i; |
| 646 | | |
| 647 | | for (i = 0; i <= hash->mask; ++i) { |
| 648 | | HashBucket *b = hash->bucket_indices[i]; |
| 649 | | |
| 650 | | while (b) { |
| 651 | | FREE_CELL(INTERP, (Pcc_cell *)b->value); |
| 652 | | b = b->next; |
| 653 | | } |
| 654 | | } |
| 655 | | |
| | 622 | parrot_hash_iterate(hash, |
| | 623 | FREE_CELL(INTERP, (Pcc_cell *)_bucket->value); |
| | 624 | ); |
| 656 | 625 | parrot_hash_destroy(INTERP, hash); |
| 657 | 626 | } |
| 658 | 627 | |
diff --git a/src/pmc/hashiterator.pmc b/src/pmc/hashiterator.pmc
index 5e682c6..0207b77 100644
|
a
|
b
|
|
| 78 | 78 | advance_to_next(PARROT_INTERP, ARGMOD(PMC *self)) |
| 79 | 79 | { |
| 80 | 80 | ASSERT_ARGS(advance_to_next) |
| 81 | | |
| 82 | 81 | Parrot_HashIterator_attributes * const attrs = PARROT_HASHITERATOR(self); |
| 83 | | HashBucket *bucket = attrs->bucket; |
| 84 | | |
| 85 | | /* Try to advance current bucket */ |
| 86 | | if (bucket) |
| 87 | | bucket = bucket->next; |
| 88 | | |
| 89 | | while (!bucket) { |
| 90 | | /* If there is no more buckets */ |
| 91 | | if (attrs->pos == attrs->total_buckets) |
| 92 | | break; |
| 93 | | |
| 94 | | bucket = attrs->parrot_hash->bucket_indices[attrs->pos++]; |
| 95 | | } |
| 96 | | attrs->bucket = bucket; |
| | 82 | parrot_hash_iterator_advance(attrs->parrot_hash, attrs->bucket, attrs->pos); |
| 97 | 83 | --attrs->elements; |
| 98 | | |
| 99 | 84 | return; |
| 100 | 85 | } |
| 101 | 86 | |
diff --git a/src/pmc/lexinfo.pmc b/src/pmc/lexinfo.pmc
index c029944..1caf6ec 100644
|
a
|
b
|
|
| 99 | 99 | if (Parrot_str_equal(INTERP, what, CONST_STRING(INTERP, "symbols"))) { |
| 100 | 100 | PMC * const result = Parrot_pmc_new(INTERP, enum_class_ResizableStringArray); |
| 101 | 101 | const Hash *hash = (Hash *)SELF.get_pointer(); |
| 102 | | const UINTVAL entries = hash->entries; |
| 103 | 102 | |
| 104 | | UINTVAL found = 0; |
| 105 | | INTVAL i; |
| 106 | | |
| 107 | | for (i = hash->mask; i >= 0; --i) { |
| 108 | | HashBucket *bucket = hash->bucket_indices[i]; |
| 109 | | while (bucket) { |
| 110 | | if (++found > entries) |
| 111 | | Parrot_ex_throw_from_c_args(INTERP, NULL, 1, |
| 112 | | "Detected corruption at LexInfo hash %p entries %d", |
| 113 | | hash, (int)entries); |
| 114 | | |
| 115 | | PARROT_ASSERT(bucket->key); |
| 116 | | VTABLE_push_string(INTERP, result, (STRING *)bucket->key); |
| 117 | | |
| 118 | | bucket = bucket->next; |
| 119 | | } |
| 120 | | } |
| | 103 | parrot_hash_iterate(hash, |
| | 104 | PARROT_ASSERT(_bucket->key); |
| | 105 | VTABLE_push_string(INTERP, result, (STRING *)_bucket->key); |
| | 106 | ); |
| 121 | 107 | |
| 122 | 108 | return result; |
| 123 | 109 | } |