1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* st.c (st_foreach): should not yield same pair when checking

after unpacking.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@34456 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nobu 2012-02-07 05:29:20 +00:00
parent b33dc193c8
commit 97c3c98762
5 changed files with 107 additions and 11 deletions

View file

@ -1,3 +1,8 @@
Tue Feb 7 14:29:16 2012 Nobuyoshi Nakada <nobu@ruby-lang.org>
* st.c (st_foreach): should not yield same pair when checking
after unpacking.
Mon Feb 6 21:55:13 2012 NARUSE, Yui <naruse@ruby-lang.org>
* tool/merger.rb: abort if the working directory is dirty.

View file

@ -0,0 +1 @@
create_makefile("-test-/st/numhash")

View file

@ -0,0 +1,63 @@
#include <ruby.h>
#include <ruby/st.h>
static VALUE
numhash_alloc(VALUE klass)
{
return Data_Wrap_Struct(klass, 0, 0, 0);
}
static VALUE
numhash_init(VALUE self)
{
st_table *tbl = (st_table *)DATA_PTR(self);
if (tbl) st_free_table(tbl);
DATA_PTR(self) = st_init_numtable();
return self;
}
static VALUE
numhash_aref(VALUE self, VALUE key)
{
st_data_t data;
if (!SPECIAL_CONST_P(key)) rb_raise(rb_eArgError, "not a special const");
if (st_lookup((st_table *)DATA_PTR(self), (st_data_t)key, &data))
return (VALUE)data;
return Qnil;
}
static VALUE
numhash_aset(VALUE self, VALUE key, VALUE data)
{
if (!SPECIAL_CONST_P(key)) rb_raise(rb_eArgError, "not a special const");
if (!SPECIAL_CONST_P(data)) rb_raise(rb_eArgError, "not a special const");
st_insert((st_table *)DATA_PTR(self), (st_data_t)key, (st_data_t)data);
return self;
}
static int
numhash_i(st_data_t key, st_data_t value, st_data_t arg, int error)
{
VALUE ret;
if (key == 0 && value == 0 && error == 1) rb_raise(rb_eRuntimeError, "numhash modified");
ret = rb_yield_values(3, (VALUE)key, (VALUE)value, (VALUE)arg);
if (ret == Qtrue) return ST_CHECK;
return ST_CONTINUE;
}
static VALUE
numhash_each(VALUE self)
{
return st_foreach((st_table *)DATA_PTR(self), numhash_i, self) ? Qtrue : Qfalse;
}
void
Init_numhash(void)
{
VALUE st = rb_define_class_under(rb_define_module("Bug"), "StNumHash", rb_cData);
rb_define_alloc_func(st, numhash_alloc);
rb_define_method(st, "initialize", numhash_init, 0);
rb_define_method(st, "[]", numhash_aref, 1);
rb_define_method(st, "[]=", numhash_aset, 2);
rb_define_method(st, "each", numhash_each, 0);
}

28
st.c
View file

@ -337,6 +337,9 @@ count_collision(const struct st_hash_type *type)
#define FOUND_ENTRY
#endif
#define FIND_ENTRY(table, ptr, hash_val, bin_pos) \
((ptr) = find_entry((table), key, (hash_val), ((bin_pos) = (hash_val)%(table)->num_bins)))
static st_table_entry *
find_entry(st_table *table, st_data_t key, st_index_t hash_val, st_index_t bin_pos)
{
@ -420,8 +423,8 @@ st_get_key(st_table *table, register st_data_t key, st_data_t *result)
#define collision_check 1
static inline void
add_direct(st_table * table, st_data_t key, st_data_t value,
st_index_t hash_val, register st_index_t bin_pos)
add_direct(st_table *table, st_data_t key, st_data_t value,
st_index_t hash_val, register st_index_t bin_pos)
{
register st_table_entry *entry;
if (table->num_entries > ST_DEFAULT_MAX_DENSITY * table->num_bins) {
@ -819,7 +822,14 @@ st_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg)
key = PKEY(table, i);
val = PVAL(table, i);
retval = (*func)(key, val, arg);
if (!table->entries_packed) goto unpacked;
if (!table->entries_packed) {
FIND_ENTRY(table, ptr, key, 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++) {
@ -827,9 +837,7 @@ st_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg)
break;
}
if (j == table->num_entries) {
/* call func with error notice */
retval = (*func)(0, 0, arg, 1);
return 1;
goto deleted;
}
/* fall through */
case ST_CONTINUE:
@ -843,11 +851,6 @@ st_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg)
}
}
return 0;
unpacked:
ptr = table->head;
while (i-- > 0) {
if (!(ptr = ptr->fore)) return 0;
}
}
else {
ptr = table->head;
@ -857,10 +860,12 @@ st_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg)
do {
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 */
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;
@ -868,6 +873,7 @@ st_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg)
}
/* fall through */
case ST_CONTINUE:
unpacked_continue:
ptr = ptr->fore;
break;
case ST_STOP:

View file

@ -0,0 +1,21 @@
require 'test/unit'
require "-test-/st/numhash"
class Bug::StNumHash
class Test_NumHash < Test::Unit::TestCase
def setup
@tbl = Bug::StNumHash.new
5.times {|i| @tbl[i] = i}
end
def test_check
keys = []
@tbl.each do |k, v, t|
keys << k
t[5] = 5 if k == 3
true
end
assert_equal([*0..5], keys)
end
end
end