summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-04-29 07:12:56 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-04-29 07:12:56 +0000
commit058949ac13003ce54ba421b346977d75ee229bb0 (patch)
tree501e0e2168fe34a2b9d4589078facbbce5fae2f8
parent394418c9d53797e8a3f47770537e23411b54159c (diff)
range.c: optimize range_each for Bignum
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@63299 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--range.c59
1 files changed, 51 insertions, 8 deletions
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;