From 058949ac13003ce54ba421b346977d75ee229bb0 Mon Sep 17 00:00:00 2001 From: nobu Date: Sun, 29 Apr 2018 07:12:56 +0000 Subject: range.c: optimize range_each for Bignum git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@63299 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- range.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 8 deletions(-) (limited to 'range.c') diff --git a/range.c b/range.c index 4f45b24f0f..917d24bd83 100644 --- a/range.c +++ b/range.c @@ -786,6 +786,7 @@ static VALUE range_each(VALUE range) { VALUE beg, end; + long i, lim; RETURN_SIZED_ENUMERATOR(range, 0, 0, range_enum_size); @@ -793,26 +794,67 @@ range_each(VALUE range) end = RANGE_END(range); if (FIXNUM_P(beg) && NIL_P(end)) { - long i = FIX2LONG(beg); + fixnum_endless: + i = FIX2LONG(beg); while (FIXABLE(i)) { rb_yield(LONG2FIX(i++)); } beg = LONG2NUM(i); - - inf_loop: - for (;; beg = rb_funcallv(beg, id_succ, 0, 0)) + bignum_endless: + for (;; beg = rb_big_plus(beg, INT2FIX(1))) rb_yield(beg); } else if (FIXNUM_P(beg) && FIXNUM_P(end)) { /* fixnums are special */ - long lim = FIX2LONG(end); - long i; - + fixnum_loop: + lim = FIX2LONG(end); if (!EXCL(range)) lim += 1; for (i = FIX2LONG(beg); i < lim; i++) { rb_yield(LONG2FIX(i)); } } + else if (RB_INTEGER_TYPE_P(beg) && (NIL_P(end) || RB_INTEGER_TYPE_P(end))) { + if (SPECIAL_CONST_P(end) || RBIGNUM_POSITIVE_P(end)) { /* end >= FIXNUM_MIN */ + if (!FIXNUM_P(beg)) { + if (RBIGNUM_NEGATIVE_P(beg)) { + do { + rb_yield(beg); + } while (!FIXNUM_P(beg = rb_big_plus(beg, INT2FIX(1)))); + if (NIL_P(end)) goto fixnum_endless; + if (FIXNUM_P(end)) goto fixnum_loop; + } + else { + if (NIL_P(end)) goto bignum_endless; + if (FIXNUM_P(end)) return range; + } + } + if (FIXNUM_P(beg)) { + i = FIX2LONG(beg); + do { + rb_yield(LONG2FIX(i)); + } while (POSFIXABLE(++i)); + beg = LONG2NUM(i); + } + ASSUME(!FIXNUM_P(beg)); + ASSUME(!SPECIAL_CONST_P(end)); + } + if (!FIXNUM_P(beg) && RBIGNUM_SIGN(beg) == RBIGNUM_SIGN(end)) { + if (EXCL(range)) { + while (rb_big_cmp(beg, end) == INT2FIX(-1)) { + rb_yield(beg); + beg = rb_big_plus(beg, INT2FIX(1)); + } + } + else { + VALUE c; + while ((c = rb_big_cmp(beg, end)) != INT2FIX(1)) { + rb_yield(beg); + if (c == INT2FIX(0)) break; + beg = rb_big_plus(beg, INT2FIX(1)); + } + } + } + } else if (SYMBOL_P(beg) && (NIL_P(end) || SYMBOL_P(end))) { /* symbols are special */ beg = rb_sym2str(beg); if (NIL_P(end)) { @@ -841,7 +883,8 @@ range_each(VALUE range) if (!NIL_P(end)) range_each_func(range, each_i, 0); else - goto inf_loop; + for (;; beg = rb_funcallv(beg, id_succ, 0, 0)) + rb_yield(beg); } } return range; -- cgit v1.2.3