/*
* call-seq:
* ary.product(other_ary, ...)
*
* 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
*
* [1,2,3].product([4,5]) # => [[1,4],[1,5],[2,4],[2,5],[3,4],[3,5]]
* [1,2].product([1,2]) # => [[1,1],[1,2],[2,1],[2,2]]
* [1,2].product([3,4],[5,6]) # => [[1,3,5],[1,3,6],[1,4,5],[1,4,6],
* # [2,3,5],[2,3,6],[2,4,5],[2,4,6]]
* [1,2].product() # => [[1],[2]]
* [1,2].product([]) # => []
*/staticVALUErb_ary_product(argc,argv,ary)intargc;VALUE*argv;VALUEary;{intn=argc+1;/* How many arrays we're operating on */volatileVALUEt0=tmpbuf(n,sizeof(VALUE));volatileVALUEt1=tmpbuf(n,sizeof(int));VALUE*arrays=(VALUE*)RSTRING(t0)->ptr;/* The arrays we're computing the product of */int*counters=(int*)RSTRING(t1)->ptr;/* The current position in each one */VALUEresult;/* The array we'll be returning */longi,j;longresultlen=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++){longk=RARRAY(arrays[i])->len,l=resultlen;if(k==0)returnrb_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++){intm;/* fill in one subarray */VALUEsubarray=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(arrays[m])->len){counters[m]=0;m--;counters[m]++;}}returnresult;}