permutation(...)
  public
  
    
    
When invoked with a block, yield all permutations of length n of the elements of
ary, then return the array itself. If n is not specified,
yield all permutations of all elements. The implementation makes no
guarantees about the order in which the permutations are yielded.
When invoked without a block, return an enumerator object instead.
Examples:
    a = [1, 2, 3]
    a.permutation.to_a     
    a.permutation(1).to_a  
    a.permutation(2).to_a  
    a.permutation(3).to_a  
    a.permutation(0).to_a  
    a.permutation(4).to_a  
   
  
    Show source    
    
      /*
 *  call-seq:
 *     ary.permutation { |p| block }          -> array
 *     ary.permutation                        -> enumerator
 *     ary.permutation(n) { |p| block }       -> array
 *     ary.permutation(n)                     -> enumerator
 *  
 * When invoked with a block, yield all permutations of length <i>n</i>
 * of the elements of <i>ary</i>, then return the array itself.
 * If <i>n</i> is not specified, yield all permutations of all elements.
 * The implementation makes no guarantees about the order in which 
 * the permutations are yielded.
 *
 * When invoked without a block, return an enumerator object instead.
 * 
 * Examples:
 *
 *     a = [1, 2, 3]
 *     a.permutation.to_a     
 *     a.permutation(1).to_a  
 *     a.permutation(2).to_a  
 *     a.permutation(3).to_a  
 *     a.permutation(0).to_a  
 *     a.permutation(4).to_a  
 */
static VALUE
rb_ary_permutation(argc, argv, ary)
    int argc;
    VALUE *argv;
    VALUE ary;
{
    VALUE num;
    long r, n, i;
    n = RARRAY(ary)->len;                  /* Array length */
    RETURN_ENUMERATOR(ary, argc, argv);   /* Return enumerator if no block */
    rb_scan_args(argc, argv, "01", &num);
    r = NIL_P(num) ? n : NUM2LONG(num);   /* Permutation size from argument */
    if (r < 0 || n < r) { 
        /* no permutations: yield nothing */
    }
    else if (r == 0) { /* exactly one permutation: the zero-length array */
        rb_yield(rb_ary_new2(0));
    }
    else if (r == 1) { /* this is a special, easy case */
        for (i = 0; i < RARRAY(ary)->len; i++) {
            rb_yield(rb_ary_new3(1, RARRAY(ary)->ptr[i]));
        }
    }
    else {             /* this is the general case */
        volatile VALUE t0 = tmpbuf(n,sizeof(long));
        long *p = (long*)RSTRING(t0)->ptr;
        volatile VALUE t1 = tmpbuf(n,sizeof(int));
        int *used = (int*)RSTRING(t1)->ptr;
        VALUE ary0 = ary_make_shared(ary); /* private defensive copy of ary */
        for (i = 0; i < n; i++) used[i] = 0; /* initialize array */
        permute0(n, r, p, 0, used, ary0); /* compute and yield permutations */
        RB_GC_GUARD(t0);
        RB_GC_GUARD(t1);
    }
    return ary;
}