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:
parent
b33dc193c8
commit
97c3c98762
5 changed files with 107 additions and 11 deletions
|
@ -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.
|
||||
|
|
1
ext/-test-/st/numhash/extconf.rb
Normal file
1
ext/-test-/st/numhash/extconf.rb
Normal file
|
@ -0,0 +1 @@
|
|||
create_makefile("-test-/st/numhash")
|
63
ext/-test-/st/numhash/numhash.c
Normal file
63
ext/-test-/st/numhash/numhash.c
Normal 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
28
st.c
|
@ -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:
|
||||
|
|
21
test/-ext-/st/test_numhash.rb
Normal file
21
test/-ext-/st/test_numhash.rb
Normal 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
|
Loading…
Reference in a new issue