[前][次][番号順一覧][スレッド一覧]

ruby-changes:51092

From: nobu <ko1@a...>
Date: Sun, 29 Apr 2018 16:13:02 +0900 (JST)
Subject: [ruby-changes:51092] nobu:r63299 (trunk): range.c: optimize range_each for Bignum

nobu	2018-04-29 16:12:56 +0900 (Sun, 29 Apr 2018)

  New Revision: 63299

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=63299

  Log:
    range.c: optimize range_each for Bignum

  Modified files:
    trunk/range.c
Index: range.c
===================================================================
--- range.c	(revision 63298)
+++ range.c	(revision 63299)
@@ -786,6 +786,7 @@ static VALUE https://github.com/ruby/ruby/blob/trunk/range.c#L786
 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) https://github.com/ruby/ruby/blob/trunk/range.c#L794
     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) https://github.com/ruby/ruby/blob/trunk/range.c#L883
 	    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;

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]