Project

General

Profile

Feature #8707 ยป patch.diff

Glass_saga (Masaki Matsushita), 07/30/2013 10:58 PM

View differences:

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)
    (1-1/1)