aboutsummaryrefslogtreecommitdiffstats
path: root/st.c
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2014-10-04 14:13:36 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2014-10-04 14:13:36 +0000
commit6557a6b9edfaff13859cc31fd3501ffdd491dae8 (patch)
treecb0003bb55eb881357595db590764c8057263c28 /st.c
parent27ce2d1328427866ef02aebce6f54ac9dbb34991 (diff)
downloadruby-6557a6b9edfaff13859cc31fd3501ffdd491dae8.tar.gz
st.c: update st_reverse_foreach
* st.c (st_reverse_foreach): update as st_foreach(). git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@47788 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'st.c')
-rw-r--r--st.c140
1 files changed, 111 insertions, 29 deletions
diff --git a/st.c b/st.c
index ac58e4d44b..12e45c27de 100644
--- a/st.c
+++ b/st.c
@@ -1156,52 +1156,68 @@ st_values_check(st_table *table, st_data_t *values, st_index_t size, st_data_t n
#if 0 /* unused right now */
int
-st_reverse_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg)
+st_reverse_foreach_check(st_table *table, int (*func)(ANYARGS), st_data_t arg, st_data_t never)
{
st_table_entry *ptr, **last, *tmp;
enum st_retval retval;
- int i;
+ st_index_t i;
if (table->entries_packed) {
- for (i = table->num_entries-1; 0 <= i; i--) {
- int j;
- st_data_t key, val;
- key = PKEY(table, i);
- val = PVAL(table, i);
- retval = (*func)(key, val, arg, 0);
- switch (retval) {
+ for (i = table->real_entries; 0 < i;) {
+ st_data_t key, val;
+ st_index_t hash;
+ --i;
+ key = PKEY(table, i);
+ val = PVAL(table, i);
+ hash = PHASH(table, i);
+ if (key == never) continue;
+ retval = (*func)(key, val, arg, 0);
+ if (!table->entries_packed) {
+ FIND_ENTRY(table, ptr, hash, i);
+ if (retval == ST_CHECK) {
+ if (!ptr) goto deleted;
+ goto unpacked_continue;
+ }
+ goto unpacked;
+ }
+ switch (retval) {
case ST_CHECK: /* check if hash is modified during iteration */
- for (j = 0; j < table->num_entries; j++) {
- if (PKEY(table, j) == key)
- break;
- }
- if (j == table->num_entries) {
- /* call func with error notice */
- retval = (*func)(0, 0, arg, 1);
- return 1;
- }
+ if (PHASH(table, i) == 0 && PKEY(table, i) == never) {
+ break;
+ }
+ i = find_packed_index_from(table, hash, key, i);
+ if (i >= table->real_entries) {
+ i = find_packed_index(table, hash, key);
+ if (i >= table->real_entries) goto deleted;
+ }
/* fall through */
case ST_CONTINUE:
break;
case ST_STOP:
return 0;
case ST_DELETE:
- remove_packed_entry(table, i);
- break;
- }
- }
- return 0;
+ remove_safe_packed_entry(table, i, never);
+ break;
+ }
+ }
+ return 0;
+ }
+ else {
+ ptr = table->tail;
}
- if ((ptr = table->head) != 0) {
- ptr = ptr->back;
+ if (ptr != 0) {
do {
+ if (ptr->key == never)
+ goto unpacked_continue;
+ i = hash_pos(ptr->hash, table->num_bins);
retval = (*func)(ptr->key, ptr->record, arg, 0);
+ unpacked:
switch (retval) {
case ST_CHECK: /* check if hash is modified during iteration */
- i = hash_pos(ptr->hash, table->num_bins);
for (tmp = table->bins[i]; tmp != ptr; tmp = tmp->next) {
if (!tmp) {
+ deleted:
/* call func with error notice */
retval = (*func)(0, 0, arg, 1);
return 1;
@@ -1209,6 +1225,7 @@ st_reverse_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg)
}
/* fall through */
case ST_CONTINUE:
+ unpacked_continue:
ptr = ptr->back;
break;
case ST_STOP:
@@ -1218,6 +1235,74 @@ st_reverse_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg)
for (; (tmp = *last) != 0; last = &tmp->next) {
if (ptr == tmp) {
tmp = ptr->back;
+ remove_entry(table, ptr);
+ ptr->key = ptr->record = never;
+ ptr->hash = 0;
+ ptr = tmp;
+ break;
+ }
+ }
+ }
+ } while (ptr && table->head);
+ }
+ return 0;
+}
+
+int
+st_reverse_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg)
+{
+ st_table_entry *ptr, **last, *tmp;
+ enum st_retval retval;
+ st_index_t i;
+
+ if (table->entries_packed) {
+ for (i = table->real_entries; 0 < i;) {
+ st_data_t key, val;
+ st_index_t hash;
+ --i;
+ key = PKEY(table, i);
+ val = PVAL(table, i);
+ hash = PHASH(table, i);
+ retval = (*func)(key, val, arg, 0);
+ if (!table->entries_packed) {
+ FIND_ENTRY(table, ptr, hash, i);
+ if (!ptr) return 0;
+ goto unpacked;
+ }
+ switch (retval) {
+ case ST_CONTINUE:
+ break;
+ case ST_CHECK:
+ case ST_STOP:
+ return 0;
+ case ST_DELETE:
+ remove_packed_entry(table, i);
+ break;
+ }
+ }
+ return 0;
+ }
+ else {
+ ptr = table->tail;
+ }
+
+ if (ptr != 0) {
+ do {
+ i = hash_pos(ptr->hash, table->num_bins);
+ retval = (*func)(ptr->key, ptr->record, arg, 0);
+ unpacked:
+ switch (retval) {
+ case ST_CONTINUE:
+ ptr = ptr->back;
+ break;
+ case ST_CHECK:
+ case ST_STOP:
+ return 0;
+ case ST_DELETE:
+ last = &table->bins[hash_pos(ptr->hash, table->num_bins)];
+ for (; (tmp = *last) != 0; last = &tmp->next) {
+ if (ptr == tmp) {
+ tmp = ptr->back;
*last = ptr->next;
remove_entry(table, ptr);
st_free_entry(ptr);
@@ -1225,9 +1310,6 @@ st_reverse_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg)
break;
}
}
- ptr = ptr->next;
- free(tmp);
- table->num_entries--;
}
} while (ptr && table->head);
}