pub fn k_permutation_cell<'a, T>(
    d: &'a [T],
    k: usize,
    result: Rc<RefCell<&'a mut [&'a T]>>,
    cb: impl FnMut()
)
Expand description

Similar to safe k_permutation function except the way it return the permutation. It return result through mutable pointer to result assuming the pointer is valid. It’ll notify caller on each new result via empty callback function.

Parameters

  • d A raw data to get k-permutation.
  • k A size of each permutation.
  • result A mutable pointer to slice of length equals to k
  • cb A callback function which will be called after new combination in result is set.

Return

This function return result through function’s parameter result and notify caller that new result is available through cb callback function.

Rationale

The safe k_permutation function return value in callback parameter. It limit the lifetime of return combination to be valid only inside it callback. To use it outside callback scope, it need to copy the value which will have performance penalty. Therefore, jeopardize it own goal of being fast. This function provide alternative safe way to share the permutation with some minor performance cost. This function is about 50% slower than the unsafe counterpart. It’s throughput is slightly slower than using a next_into_cell by 15%-20% in uncontrol test environment.

Example

The scenario is we want to get k-permutation from single source of data then distribute the combination to two workers which read each permutation then do something about it, which in this example, simply print it.

   use permutator::k_permutation_cell;
   use std::fmt::Debug;
   use std::rc::Rc;
   use std::cell::RefCell;
 
   trait Consumer {
       fn consume(&self);
   }
   struct Worker1<'a, T : 'a> {
       data : Rc<RefCell<&'a mut[&'a T]>>
   }
   impl<'a, T : 'a + Debug> Consumer for Worker1<'a, T> {
       fn consume(&self) {
           println!("Work1 has {:?}", self.data.borrow());
       }
   }
   struct Worker2<'a, T : 'a> {
       data : Rc<RefCell<&'a mut[&'a T]>>
   }
   impl<'a, T : 'a + Debug> Consumer for Worker2<'a, T> {
       fn consume(&self) {
           println!("Work2 has {:?}", self.data.borrow());
       }
   }

   fn start_k_permutation_process<'a>(data : &'a[i32], cur_result : Rc<RefCell<&'a mut [&'a i32]>>, k : usize, consumers : Vec<Box<Consumer + 'a>>) {
       k_permutation_cell(data, k, cur_result, || {
           consumers.iter().for_each(|c| {
               c.consume();
           })
       });
   }
   let k = 3;
   let data = &[1, 2, 3, 4, 5];
   let mut result = vec![&data[0]; k];
   let shared = Rc::new(RefCell::new(result.as_mut_slice()));

   let worker1 = Worker1 {
       data : Rc::clone(&shared)
   };
   let worker2 = Worker2 {
       data : Rc::clone(&shared)
   };
   let consumers : Vec<Box<Consumer>> = vec![Box::new(worker1), Box::new(worker2)];
   start_k_permutation_process(data, shared, k, consumers);

Panic

Panic if k == 0 or k > d.len()

See