diff options
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | array.c | 42 | ||||
-rw-r--r-- | internal.h | 3 | ||||
-rw-r--r-- | vm_insnhelper.c | 12 |
4 files changed, 55 insertions, 9 deletions
@@ -1,3 +1,10 @@ +Tue Aug 27 16:46:05 2013 Nobuyoshi Nakada <nobu@ruby-lang.org> + + * array.c (rb_ary_index, rb_ary_rindex): use optimized equality to + improve performance. [Feature #8820] + + * vm_insnhelper.c (rb_equal_opt): optimized equality function. + Tue Aug 27 16:11:05 2013 Nobuyoshi Nakada <nobu@ruby-lang.org> * vm_insnhelper.c (opt_eq_func): use RBASIC_CLASS() instead of HEAP_CLASS_OF(). @@ -1414,8 +1414,9 @@ rb_ary_fetch(int argc, VALUE *argv, VALUE ary) static VALUE rb_ary_index(int argc, VALUE *argv, VALUE ary) { + const VALUE *ptr; VALUE val; - long i; + long i, len; if (argc == 0) { RETURN_ENUMERATOR(ary, 0, 0); @@ -1426,12 +1427,24 @@ rb_ary_index(int argc, VALUE *argv, VALUE ary) } return Qnil; } - rb_scan_args(argc, argv, "1", &val); + rb_check_arity(argc, 0, 1); + val = argv[0]; if (rb_block_given_p()) rb_warn("given block not used"); - for (i=0; i<RARRAY_LEN(ary); i++) { - if (rb_equal(RARRAY_AREF(ary, i), val)) + len = RARRAY_LEN(ary); + ptr = RARRAY_RAWPTR(ary); + for (i=0; i<len; i++) { + VALUE e = ptr[i]; + switch (rb_equal_opt(e, val)) { + case Qundef: + if (!rb_equal(e, val)) break; + case Qtrue: return LONG2NUM(i); + case Qfalse: + continue; + } + len = RARRAY_LEN(ary); + ptr = RARRAY_RAWPTR(ary); } return Qnil; } @@ -1463,8 +1476,9 @@ rb_ary_index(int argc, VALUE *argv, VALUE ary) static VALUE rb_ary_rindex(int argc, VALUE *argv, VALUE ary) { + const VALUE *ptr; VALUE val; - long i = RARRAY_LEN(ary); + long i = RARRAY_LEN(ary), len; if (argc == 0) { RETURN_ENUMERATOR(ary, 0, 0); @@ -1477,15 +1491,25 @@ rb_ary_rindex(int argc, VALUE *argv, VALUE ary) } return Qnil; } - rb_scan_args(argc, argv, "1", &val); + rb_check_arity(argc, 0, 1); + val = argv[0]; if (rb_block_given_p()) rb_warn("given block not used"); + ptr = RARRAY_RAWPTR(ary); while (i--) { - if (rb_equal(RARRAY_AREF(ary, i), val)) + VALUE e = ptr[i]; + switch (rb_equal_opt(e, val)) { + case Qundef: + if (!rb_equal(e, val)) break; + case Qtrue: return LONG2NUM(i); - if (i > RARRAY_LEN(ary)) { - i = RARRAY_LEN(ary); + case Qfalse: + continue; } + if (i > (len = RARRAY_LEN(ary))) { + i = len; + } + ptr = RARRAY_RAWPTR(ary); } return Qnil; } diff --git a/internal.h b/internal.h index efbf31fece..e900c42271 100644 --- a/internal.h +++ b/internal.h @@ -483,6 +483,9 @@ typedef void rb_check_funcall_hook(int, VALUE, ID, int, const VALUE *, VALUE); VALUE rb_check_funcall_with_hook(VALUE recv, ID mid, int argc, const VALUE *argv, rb_check_funcall_hook *hook, VALUE arg); +/* vm_insnhelper.c */ +VALUE rb_equal_opt(VALUE obj1, VALUE obj2); + /* vm_method.c */ void Init_eval_method(void); int rb_method_defined_by(VALUE obj, ID mid, VALUE (*cfunc)(ANYARGS)); diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 4b8b2a2334..761c830235 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -918,6 +918,18 @@ opt_eq_func(VALUE recv, VALUE obj, CALL_INFO ci) return Qundef; } +VALUE +rb_equal_opt(VALUE obj1, VALUE obj2) +{ + rb_call_info_t ci; + ci.mid = idEq; + ci.klass = 0; + ci.vmstat = 0; + ci.me = NULL; + ci.defined_class = 0; + return opt_eq_func(obj1, obj2, &ci); +} + static VALUE check_match(VALUE pattern, VALUE target, enum vm_check_match_type type) { |