From 93f4317f89f3dc0ab9e11cea5c2d3e73841e442f Mon Sep 17 00:00:00 2001 From: marcandre Date: Sat, 3 Apr 2010 20:59:56 +0000 Subject: [PATCH] * 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 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@27210 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- array.c | 37 ++++++++++++++++++++++--------------- test/ruby/test_array.rb | 5 ++++- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/array.c b/array.c index 77a241259b..aa58b35311 100644 --- a/array.c +++ b/array.c @@ -4092,25 +4092,30 @@ rb_ary_product(int argc, VALUE *argv, VALUE ary) /* 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 @@ rb_ary_product(int argc, VALUE *argv, VALUE ary) */ 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); diff --git a/test/ruby/test_array.rb b/test/ruby/test_array.rb index 6c84b9238b..6fc7fec48d 100644 --- a/test/ruby/test_array.rb +++ b/test/ruby/test_array.rb @@ -1850,7 +1850,10 @@ class TestArray < Test::Unit::TestCase 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