diff options
author | glass <glass@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2013-07-29 12:39:21 +0000 |
---|---|---|
committer | glass <glass@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2013-07-29 12:39:21 +0000 |
commit | eb8f91866e0bd08a6eef9c9a2bc1318e06b4ee4d (patch) | |
tree | fde6bac860df6f22615a68c9835153eefb4d6c62 /hash.c | |
parent | 952e444877f53492ba0c8ddae7a1fe413b536ec1 (diff) |
* hash.c (rb_hash_assoc): performance improvement by replacing
compare function in RHASH(hash)->ntbl->type temporarily like r42224.
it falls back to rb_hash_foreach() if st_lookup() doesn't find the key.
* test/ruby/test_hash.rb: add a test for above.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42237 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'hash.c')
-rw-r--r-- | hash.c | 52 |
1 files changed, 50 insertions, 2 deletions
@@ -2123,6 +2123,32 @@ rb_hash_merge(VALUE hash1, VALUE hash2) } static int +assoc_cmp(VALUE a, VALUE b) +{ + return !RTEST(rb_equal(a, b)); +} + +static VALUE +lookup2_call(VALUE arg) +{ + VALUE *args = (VALUE *)arg; + return rb_hash_lookup2(args[0], args[1], Qundef); +} + +struct reset_hash_type_arg { + VALUE hash; + const struct st_hash_type *orighash; +}; + +static VALUE +reset_hash_type(VALUE arg) +{ + struct reset_hash_type_arg *p = (struct reset_hash_type_arg *)arg; + RHASH(p->hash)->ntbl->type = p->orighash; + return Qundef; +} + +static int assoc_i(VALUE key, VALUE val, VALUE arg) { VALUE *args = (VALUE *)arg; @@ -2149,11 +2175,33 @@ assoc_i(VALUE key, VALUE val, VALUE arg) */ VALUE -rb_hash_assoc(VALUE hash, VALUE obj) +rb_hash_assoc(VALUE hash, VALUE key) { + st_table *table; + const struct st_hash_type *orighash; VALUE args[2]; - args[0] = obj; + if (RHASH_EMPTY_P(hash)) return Qnil; + table = RHASH(hash)->ntbl; + orighash = table->type; + + if (orighash != &identhash) { + VALUE value; + struct reset_hash_type_arg ensure_arg; + struct st_hash_type assochash; + + assochash.compare = assoc_cmp; + assochash.hash = orighash->hash; + table->type = &assochash; + args[0] = hash; + args[1] = key; + ensure_arg.hash = hash; + ensure_arg.orighash = orighash; + value = rb_ensure(lookup2_call, (VALUE)&args, reset_hash_type, (VALUE)&ensure_arg); + if (value != Qundef) return rb_assoc_new(key, value); + } + + args[0] = key; args[1] = Qnil; rb_hash_foreach(hash, assoc_i, (VALUE)args); return args[1]; |