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

ruby-changes:15323

From: marcandre <ko1@a...>
Date: Sun, 4 Apr 2010 06:00:10 +0900 (JST)
Subject: [ruby-changes:15323] Ruby:r27210 (trunk): * array.c (rb_ary_product): Don't limit based on size when a block is given

marcandre	2010-04-04 05:59:56 +0900 (Sun, 04 Apr 2010)

  New Revision: 27210

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=27210

  Log:
    * array.c (rb_ary_product): Don't limit based on size when a block is given
      cf [ruby-core:29240]
    
    * test/ruby/test_array.rb (class): Test for above

  Modified files:
    trunk/array.c
    trunk/test/ruby/test_array.rb

Index: array.c
===================================================================
--- array.c	(revision 27209)
+++ array.c	(revision 27210)
@@ -4092,25 +4092,30 @@
     /* initialize the counters for the arrays */
     for (i = 0; i < n; i++) counters[i] = 0;
 
-    /* Compute the length of the result array; return [] if any is empty */
-    for (i = 0; i < n; i++) {
-	long k = RARRAY_LEN(arrays[i]), l = resultlen;
-	if (k == 0) return rb_block_given_p() ? ary : rb_ary_new2(0);
-	resultlen *= k;
-	if (resultlen < k || resultlen < l || resultlen / k != l) {
-	    rb_raise(rb_eRangeError, "too big to product");
-	}
-    }
-
     /* Otherwise, allocate and fill in an array of results */
     if (rb_block_given_p()) {
-	/* Make defensive copies of arrays */
-	for (i = 0; i < n; i++) arrays[i] = ary_make_substitution(arrays[i]);
+	/* Make defensive copies of arrays; exit if any is empty */
+	for (i = 0; i < n; i++) {
+	    if (RARRAY_LEN(arrays[i]) == 0) goto done;
+	    arrays[i] = ary_make_substitution(arrays[i]);
+	}
     }
     else {
+	/* Compute the length of the result array; return [] if any is empty */
+	for (i = 0; i < n; i++) {
+	    long k = RARRAY_LEN(arrays[i]), l = resultlen;
+	    if (k == 0) {
+		result = rb_ary_new2(0);
+		goto done;
+	    }
+	    resultlen *= k;
+	    if (resultlen < k || resultlen < l || resultlen / k != l) {
+		rb_raise(rb_eRangeError, "too big to product");
+	    }
+	}
 	result = rb_ary_new2(resultlen);
     }
-    for (i = 0; i < resultlen; i++) {
+    for (;;) {
 	int m;
 	/* fill in one subarray */
 	VALUE subarray = rb_ary_new2(n);
@@ -4135,12 +4140,14 @@
 	 */
 	m = n-1;
 	counters[m]++;
-	while (m > 0 && counters[m] == RARRAY_LEN(arrays[m])) {
+	while (counters[m] == RARRAY_LEN(arrays[m])) {
 	    counters[m] = 0;
-	    m--;
+	    /* If the first counter overlows, we are done */
+	    if (--m < 0) goto done;
 	    counters[m]++;
 	}
     }
+done:
     tmpbuf_discard(t0);
     tmpbuf_discard(t1);
 
Index: test/ruby/test_array.rb
===================================================================
--- test/ruby/test_array.rb	(revision 27209)
+++ test/ruby/test_array.rb	(revision 27210)
@@ -1850,8 +1850,11 @@
   def test_product2
     a = (0..100).to_a
     assert_raise(RangeError) do
-      a.product(a, a, a, a, a, a, a, a, a, a) {}
+      a.product(a, a, a, a, a, a, a, a, a, a)
     end
+    assert_nothing_raised(RangeError) do
+      a.product(a, a, a, a, a, a, a, a, a, a) { break }
+    end
   end
 
   class Array2 < Array

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

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