Returns an array of all combinations of elements from all arrays. The length of the returned array is the product of the length of ary and the argument arrays
static VALUE
rb_ary_product(int argc, VALUE *argv, VALUE ary)
{
int n = argc+1; /* How many arrays we're operating on */
volatile VALUE t0 = tmpbuf(n, sizeof(VALUE));
volatile VALUE t1 = tmpbuf(n, sizeof(int));
VALUE *arrays = (VALUE*)RSTRING_PTR(t0); /* The arrays we're computing the product of */
int *counters = (int*)RSTRING_PTR(t1); /* The current position in each one */
VALUE result; /* The array we'll be returning */
long i,j;
long resultlen = 1;
RBASIC(t0)->klass = 0;
RBASIC(t1)->klass = 0;
/* initialize the arrays of arrays */
arrays[0] = ary;
for (i = 1; i < n; i++) arrays[i] = to_ary(argv[i-1]);
/* 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_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 */
result = rb_ary_new2(resultlen);
for (i = 0; i < resultlen; i++) {
int m;
/* fill in one subarray */
VALUE subarray = rb_ary_new2(n);
for (j = 0; j < n; j++) {
rb_ary_push(subarray, rb_ary_entry(arrays[j], counters[j]));
}
/* put it on the result array */
rb_ary_push(result, subarray);
/*
* Increment the last counter. If it overflows, reset to 0
* and increment the one before it.
*/
m = n-1;
counters[m]++;
while (m > 0 && counters[m] == RARRAY_LEN(arrays[m])) {
counters[m] = 0;
m--;
counters[m]++;
}
}
return result;
}