ruby-changes:30185
From: glass <ko1@a...>
Date: Mon, 29 Jul 2013 21:39:35 +0900 (JST)
Subject: [ruby-changes:30185] glass:r42237 (trunk): * hash.c (rb_hash_assoc): performance improvement by replacing
glass 2013-07-29 21:39:21 +0900 (Mon, 29 Jul 2013) New Revision: 42237 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=42237 Log: * 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. Modified files: trunk/ChangeLog trunk/hash.c trunk/test/ruby/test_hash.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 42236) +++ ChangeLog (revision 42237) @@ -1,3 +1,11 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Mon Jul 29 21:29:48 2013 Masaki Matsushita <glass.saga@g...> + + * 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. + Mon Jul 29 21:15:30 2013 Akinori MUSHA <knu@i...> * test/ruby/test_lazy_enumerator.rb Index: hash.c =================================================================== --- hash.c (revision 42236) +++ hash.c (revision 42237) @@ -2123,6 +2123,32 @@ rb_hash_merge(VALUE hash1, VALUE hash2) https://github.com/ruby/ruby/blob/trunk/hash.c#L2123 } 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) https://github.com/ruby/ruby/blob/trunk/hash.c#L2175 */ 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]; Index: test/ruby/test_hash.rb =================================================================== --- test/ruby/test_hash.rb (revision 42236) +++ test/ruby/test_hash.rb (revision 42237) @@ -879,6 +879,14 @@ class TestHash < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_hash.rb#L879 assert_equal([1.0,1], {1.0=>1}.assoc(1)) end + def test_assoc_compare_by_identity + h = {} + h.compare_by_identity + h["a"] = 1 + h["a"] = 2 + assert_equal(["a",1], h.assoc("a")) + end + def test_rassoc assert_equal([3,4], {1=>2, 3=>4, 5=>6}.rassoc(4)) assert_nil({1=>2, 3=>4, 5=>6}.rassoc(3)) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/