Feature #8707 ยป patch.diff
hash.c | ||
---|---|---|
return Qnil;
|
||
}
|
||
void
|
||
rb_hash_foreach(VALUE hash, int (*func)(ANYARGS), VALUE farg)
|
||
static VALUE
|
||
hash_reverse_foreach_call(VALUE arg)
|
||
{
|
||
VALUE hash = ((struct hash_foreach_arg *)arg)->hash;
|
||
if (st_reverse_foreach_check(RHASH(hash)->ntbl, hash_foreach_iter, (st_data_t)arg, (st_data_t)Qundef)) {
|
||
rb_raise(rb_eRuntimeError, "hash modified during iteration");
|
||
}
|
||
return Qnil;
|
||
}
|
||
static void
|
||
do_hash_foreach(VALUE hash, int (*func)(ANYARGS), VALUE farg, int reverse)
|
||
{
|
||
struct hash_foreach_arg arg;
|
||
... | ... | |
arg.hash = hash;
|
||
arg.func = (rb_foreach_func *)func;
|
||
arg.arg = farg;
|
||
rb_ensure(hash_foreach_call, (VALUE)&arg, hash_foreach_ensure, hash);
|
||
if (reverse)
|
||
rb_ensure(hash_reverse_foreach_call, (VALUE)&arg, hash_foreach_ensure, hash);
|
||
else
|
||
rb_ensure(hash_foreach_call, (VALUE)&arg, hash_foreach_ensure, hash);
|
||
}
|
||
void
|
||
rb_hash_foreach(VALUE hash, int (*func)(ANYARGS), VALUE farg)
|
||
{
|
||
do_hash_foreach(hash, func, farg, 0);
|
||
}
|
||
static void
|
||
rb_hash_reverse_foreach(VALUE hash, int (*func)(ANYARGS), VALUE farg)
|
||
{
|
||
do_hash_foreach(hash, func, farg, 1);
|
||
}
|
||
static VALUE
|
||
... | ... | |
return hash;
|
||
}
|
||
/*
|
||
* call-seq:
|
||
* hsh.reverse_each {| key, value | block } -> hsh
|
||
* hsh.reverse_each -> an_enumerator
|
||
*
|
||
* Calls <i>block</i> once for each key in <i>hsh</i>, passing the key-value
|
||
* pair as parameters.
|
||
*
|
||
* If no block is given, an enumerator is returned instead.
|
||
*
|
||
* h = { "a" => 100, "b" => 200 }
|
||
* h.reverse_each {|key, value| puts "#{key} is #{value}" }
|
||
*
|
||
* <em>produces:</em>
|
||
*
|
||
* b is 200
|
||
* a is 100
|
||
*
|
||
*/
|
||
static VALUE
|
||
rb_hash_reverse_each_pair(VALUE hash)
|
||
{
|
||
RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
|
||
if (rb_block_arity() > 1)
|
||
rb_hash_reverse_foreach(hash, each_pair_i_fast, 0);
|
||
else
|
||
rb_hash_reverse_foreach(hash, each_pair_i, 0);
|
||
return hash;
|
||
}
|
||
static int
|
||
to_a_i(VALUE key, VALUE value, VALUE ary)
|
||
{
|
||
... | ... | |
rb_define_method(rb_cHash,"each_key", rb_hash_each_key, 0);
|
||
rb_define_method(rb_cHash,"each_pair", rb_hash_each_pair, 0);
|
||
rb_define_method(rb_cHash,"each", rb_hash_each_pair, 0);
|
||
rb_define_method(rb_cHash,"reverse_each", rb_hash_reverse_each_pair, 0);
|
||
rb_define_method(rb_cHash,"keys", rb_hash_keys, 0);
|
||
rb_define_method(rb_cHash,"values", rb_hash_values, 0);
|
include/ruby/st.h | ||
---|---|---|
int st_update(st_table *table, st_data_t key, st_update_callback_func *func, st_data_t arg);
|
||
int st_foreach(st_table *, int (*)(ANYARGS), st_data_t);
|
||
int st_foreach_check(st_table *, int (*)(ANYARGS), st_data_t, st_data_t);
|
||
int st_reverse_foreach(st_table *, int (*)(ANYARGS), st_data_t);
|
||
int st_reverse_foreach_check(st_table *, int (*)(ANYARGS), st_data_t, st_data_t);
|
||
void st_add_direct(st_table *, st_data_t, st_data_t);
|
||
void st_free_table(st_table *);
|
||
void st_cleanup_safe(st_table *, st_data_t);
|
st.c | ||
---|---|---|
return 0;
|
||
}
|
||
#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;
|
||
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);
|
||
switch (retval) {
|
||
for (i = table->num_entries-1; i >= 0; i--) {
|
||
st_data_t key, val;
|
||
st_index_t hash;
|
||
key = PKEY(table, i);
|
||
val = PVAL(table, i);
|
||
hash = PHASH(table, i);
|
||
if (key == never) continue;
|
||
retval = (*func)(key, val, arg);
|
||
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(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;
|
||
}
|
||
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 {
|
||
retval = (*func)(ptr->key, ptr->record, arg, 0);
|
||
if (ptr->key == never)
|
||
goto unpacked_continue;
|
||
i = ptr->hash % table->num_bins;
|
||
retval = (*func)(ptr->key, ptr->record, arg);
|
||
unpacked:
|
||
switch (retval) {
|
||
case ST_CHECK: /* check if hash is modified during iteration */
|
||
i = 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;
|
||
... | ... | |
}
|
||
/* fall through */
|
||
case ST_CONTINUE:
|
||
unpacked_continue:
|
||
ptr = ptr->back;
|
||
break;
|
||
case ST_STOP:
|
||
... | ... | |
for (; (tmp = *last) != 0; last = &tmp->next) {
|
||
if (ptr == tmp) {
|
||
tmp = ptr->back;
|
||
*last = ptr->next;
|
||
remove_entry(table, ptr);
|
||
st_free_entry(ptr);
|
||
ptr->key = ptr->record = never;
|
||
ptr->hash = 0;
|
||
ptr = tmp;
|
||
break;
|
||
}
|
||
}
|
||
ptr = ptr->next;
|
||
free(tmp);
|
||
table->num_entries--;
|
||
}
|
||
} while (ptr && table->head);
|
||
}
|
||
return 0;
|
||
}
|
||
#endif
|
||
/*
|
||
* hash_32 - 32 bit Fowler/Noll/Vo FNV-1a hash code
|
test/ruby/test_hash.rb | ||
---|---|---|
assert_equal([], res - expected)
|
||
end
|
||
def test_reverse_each
|
||
count = 0
|
||
@cls[].reverse_each { |k, v| count + 1 }
|
||
assert_equal(0, count)
|
||
h = @h
|
||
h.reverse_each do |k, v|
|
||
assert_equal(v, h.delete(k))
|
||
end
|
||
assert_equal(@cls[], h)
|
||
h = @cls[]
|
||
h[1] = 1
|
||
h[2] = 2
|
||
assert_equal([[2,2],[1,1]], h.reverse_each.to_a)
|
||
end
|
||
def test_empty?
|
||
assert_empty(@cls[])
|
||
assert_not_empty(@h)
|