ruby-changes:23265
From: nobu <ko1@a...>
Date: Fri, 13 Apr 2012 15:27:03 +0900 (JST)
Subject: [ruby-changes:23265] nobu:r35316 (trunk): * hash.c (rb_hash_aset, rb_hash_update, rb_hash_update_by): use
nobu 2012-04-13 15:26:53 +0900 (Fri, 13 Apr 2012) New Revision: 35316 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=35316 Log: * hash.c (rb_hash_aset, rb_hash_update, rb_hash_update_by): use st_update() to reduce evaluation of hash values. Modified files: trunk/ChangeLog trunk/hash.c Index: ChangeLog =================================================================== --- ChangeLog (revision 35315) +++ ChangeLog (revision 35316) @@ -1,3 +1,8 @@ +Fri Apr 13 15:26:51 2012 Nobuyoshi Nakada <nobu@r...> + + * 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@r...> * lib/webrick/server.rb (WEBrick::GenericServer#stop): fix r35303; Index: hash.c =================================================================== --- hash.c (revision 35315) +++ hash.c (revision 35316) @@ -261,13 +261,30 @@ } 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 @@ 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 @@ 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; } @@ -1720,24 +1754,41 @@ } 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_i(VALUE key, VALUE value, VALUE hash) +rb_hash_update_block_callback(st_data_t *key, st_data_t *value, st_data_t arg, int existing) { - if (rb_hash_has_key(hash, key)) { - value = rb_yield_values(3, key, rb_hash_aref(hash, key), value); + VALUE newvalue = (VALUE)arg; + if (existing) { + newvalue = rb_yield_values(3, (VALUE)*key, (VALUE)*value, newvalue); } - hash_update(hash, key); - st_insert(RHASH(hash)->ntbl, key, value); + *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) +{ + RHASH_UPDATE(hash, key, rb_hash_update_block_callback, value); + return ST_CONTINUE; +} + /* * call-seq: * hsh.merge!(other_hash) -> hsh @@ -1777,20 +1828,32 @@ 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; } -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/