* hash.c (rb_hash_aset, rb_hash_update, rb_hash_update_by): use

st_update() to reduce evaluation of hash values.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@35316 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nobu 2012-04-13 06:26:53 +00:00
parent deb0519aec
commit 2d74f3e682
2 changed files with 89 additions and 21 deletions

View File

@ -1,3 +1,8 @@
Fri Apr 13 15:26:51 2012 Nobuyoshi Nakada <nobu@ruby-lang.org>
* hash.c (rb_hash_aset, rb_hash_update, rb_hash_update_by): use
st_update() to reduce evaluation of hash values.
Fri Apr 13 15:17:36 2012 NARUSE, Yui <naruse@ruby-lang.org>
* lib/webrick/server.rb (WEBrick::GenericServer#stop): fix r35303;

105
hash.c
View File

@ -261,13 +261,30 @@ rb_hash_modify(VALUE hash)
}
static void
hash_update(VALUE hash, VALUE key)
no_new_key(int existing)
{
if (RHASH_ITER_LEV(hash) > 0 && !st_lookup(RHASH(hash)->ntbl, key, 0)) {
if (!existing) {
rb_raise(rb_eRuntimeError, "can't add a new key into hash during iteration");
}
}
#define NOINSERT_UPDATE_CALLBACK(func) \
int \
func##_noinsert(st_data_t *key, st_data_t *val, st_data_t arg, int existing) \
{ \
no_new_key(existing); \
return func(key, val, arg, existing); \
}
#define UPDATE_CALLBACK(iter_lev, func) ((iter_lev) > 0 ? func##_noinsert : func)
#define RHASH_UPDATE_ITER(hash, iter_lev, key, func, arg) \
st_update(RHASH(hash)->ntbl, (st_data_t)(key), \
UPDATE_CALLBACK((iter_lev), func), \
(st_data_t)(arg))
#define RHASH_UPDATE(hash, key, func, arg) \
RHASH_UPDATE_ITER(hash, RHASH_ITER_LEV(hash), key, func, arg)
static void
default_proc_arity_check(VALUE proc)
{
@ -1098,12 +1115,23 @@ rb_hash_clear(VALUE hash)
return hash;
}
static st_data_t
copy_str_key(st_data_t str)
static int
hash_aset(st_data_t *key, st_data_t *val, st_data_t arg, int existing)
{
return (st_data_t)rb_str_new4((VALUE)str);
*val = arg;
return ST_CONTINUE;
}
static int
hash_aset_str(st_data_t *key, st_data_t *val, st_data_t arg, int existing)
{
*key = (st_data_t)rb_str_new_frozen((VALUE)*key);
return hash_aset(key, val, arg, existing);
}
static NOINSERT_UPDATE_CALLBACK(hash_aset)
static NOINSERT_UPDATE_CALLBACK(hash_aset_str)
/*
* call-seq:
* hsh[key] = value -> value
@ -1125,13 +1153,19 @@ copy_str_key(st_data_t str)
VALUE
rb_hash_aset(VALUE hash, VALUE key, VALUE val)
{
int iter_lev = RHASH_ITER_LEV(hash);
st_table *tbl = RHASH(hash)->ntbl;
rb_hash_modify(hash);
hash_update(hash, key);
if (RHASH(hash)->ntbl->type == &identhash || rb_obj_class(key) != rb_cString) {
st_insert(RHASH(hash)->ntbl, key, val);
if (!tbl) {
if (iter_lev > 0) no_new_key(0);
tbl = RHASH_TBL(hash);
}
if (tbl->type == &identhash || rb_obj_class(key) != rb_cString) {
RHASH_UPDATE_ITER(hash, iter_lev, key, hash_aset, val);
}
else {
st_insert2(RHASH(hash)->ntbl, key, val, copy_str_key);
RHASH_UPDATE_ITER(hash, iter_lev, key, hash_aset_str, val);
}
return val;
}
@ -1719,22 +1753,39 @@ rb_hash_invert(VALUE hash)
return h;
}
static int
rb_hash_update_callback(st_data_t *key, st_data_t *value, st_data_t arg, int existing)
{
*value = arg;
return ST_CONTINUE;
}
static NOINSERT_UPDATE_CALLBACK(rb_hash_update_callback)
static int
rb_hash_update_i(VALUE key, VALUE value, VALUE hash)
{
hash_update(hash, key);
st_insert(RHASH(hash)->ntbl, key, value);
RHASH_UPDATE(hash, key, rb_hash_update_callback, value);
return ST_CONTINUE;
}
static int
rb_hash_update_block_callback(st_data_t *key, st_data_t *value, st_data_t arg, int existing)
{
VALUE newvalue = (VALUE)arg;
if (existing) {
newvalue = rb_yield_values(3, (VALUE)*key, (VALUE)*value, newvalue);
}
*value = (st_data_t)newvalue;
return ST_CONTINUE;
}
static NOINSERT_UPDATE_CALLBACK(rb_hash_update_block_callback)
static int
rb_hash_update_block_i(VALUE key, VALUE value, VALUE hash)
{
if (rb_hash_has_key(hash, key)) {
value = rb_yield_values(3, key, rb_hash_aref(hash, key), value);
}
hash_update(hash, key);
st_insert(RHASH(hash)->ntbl, key, value);
RHASH_UPDATE(hash, key, rb_hash_update_block_callback, value);
return ST_CONTINUE;
}
@ -1777,20 +1828,32 @@ rb_hash_update(VALUE hash1, VALUE hash2)
struct update_arg {
VALUE hash;
VALUE value;
rb_hash_update_func *func;
};
static int
rb_hash_update_func_callback(st_data_t *key, st_data_t *value, st_data_t arg0, int existing)
{
struct update_arg *arg = (struct update_arg *)arg0;
VALUE newvalue = arg->value;
if (existing) {
newvalue = (*arg->func)((VALUE)*key, (VALUE)*value, newvalue);
}
*value = (st_data_t)newvalue;
return ST_CONTINUE;
}
static NOINSERT_UPDATE_CALLBACK(rb_hash_update_func_callback)
static int
rb_hash_update_func_i(VALUE key, VALUE value, VALUE arg0)
{
struct update_arg *arg = (struct update_arg *)arg0;
VALUE hash = arg->hash;
if (rb_hash_has_key(hash, key)) {
value = (*arg->func)(key, rb_hash_aref(hash, key), value);
}
hash_update(hash, key);
st_insert(RHASH(hash)->ntbl, key, value);
arg->value = value;
RHASH_UPDATE(hash, key, rb_hash_update_func_callback, arg);
return ST_CONTINUE;
}