* 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
This commit is contained in:
parent
88a4bf912d
commit
93f4317f89
37
array.c
37
array.c
@ -4092,25 +4092,30 @@ rb_ary_product(int argc, VALUE *argv, VALUE ary)
|
|||||||
/* initialize the counters for the arrays */
|
/* initialize the counters for the arrays */
|
||||||
for (i = 0; i < n; i++) counters[i] = 0;
|
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 */
|
/* Otherwise, allocate and fill in an array of results */
|
||||||
if (rb_block_given_p()) {
|
if (rb_block_given_p()) {
|
||||||
/* Make defensive copies of arrays */
|
/* Make defensive copies of arrays; exit if any is empty */
|
||||||
for (i = 0; i < n; i++) arrays[i] = ary_make_substitution(arrays[i]);
|
for (i = 0; i < n; i++) {
|
||||||
|
if (RARRAY_LEN(arrays[i]) == 0) goto done;
|
||||||
|
arrays[i] = ary_make_substitution(arrays[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
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);
|
result = rb_ary_new2(resultlen);
|
||||||
}
|
}
|
||||||
for (i = 0; i < resultlen; i++) {
|
for (;;) {
|
||||||
int m;
|
int m;
|
||||||
/* fill in one subarray */
|
/* fill in one subarray */
|
||||||
VALUE subarray = rb_ary_new2(n);
|
VALUE subarray = rb_ary_new2(n);
|
||||||
@ -4135,12 +4140,14 @@ rb_ary_product(int argc, VALUE *argv, VALUE ary)
|
|||||||
*/
|
*/
|
||||||
m = n-1;
|
m = n-1;
|
||||||
counters[m]++;
|
counters[m]++;
|
||||||
while (m > 0 && counters[m] == RARRAY_LEN(arrays[m])) {
|
while (counters[m] == RARRAY_LEN(arrays[m])) {
|
||||||
counters[m] = 0;
|
counters[m] = 0;
|
||||||
m--;
|
/* If the first counter overlows, we are done */
|
||||||
|
if (--m < 0) goto done;
|
||||||
counters[m]++;
|
counters[m]++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
done:
|
||||||
tmpbuf_discard(t0);
|
tmpbuf_discard(t0);
|
||||||
tmpbuf_discard(t1);
|
tmpbuf_discard(t1);
|
||||||
|
|
||||||
|
@ -1850,7 +1850,10 @@ class TestArray < Test::Unit::TestCase
|
|||||||
def test_product2
|
def test_product2
|
||||||
a = (0..100).to_a
|
a = (0..100).to_a
|
||||||
assert_raise(RangeError) do
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user