[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]