pub unsafe fn unsafe_cartesian_product<'a, T>(
    sets: &'a [&[T]],
    result: *mut [&'a T],
    cb: impl FnMut()
)
Expand description

Similar to safe cartesian_product function except the way it return the product. 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

  • sets A raw sets of data to get a cartesian product.
  • result A mutable pointer to slice of length equals to sets.len()
  • cb A callback function which will be called after new product 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.

Unsafe

This function is unsafe because it may dereference a dangling pointer, may cause data race if multiple threads read/write to the same memory, and all of those unsafe Rust condition will be applied here.

Rationale

The safe cartesian_product function return value in callback parameter. It limit the lifetime of return product 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 way that sacrifice safety for performance.

Example

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

   use permutator::unsafe_cartesian_product;
   use std::fmt::Debug;
   // All shared data consumer will get call throught this trait
   trait Consumer {
       fn consume(&self); // need to be ref due to rule of only ref mut is permit at a time
   }
 
   struct Worker1<'a, T : 'a> {
       data : &'a[&'a T] // Store ref to cartesian product.
   }
 
   impl<'a, T : 'a + Debug> Consumer for Worker1<'a, T> {
       fn consume(&self) {
           // read new share cartesian product and do something about it, in this case simply print it.
           println!("Work1 has {:?}", self.data);
       }
   }

   struct Worker2<'a, T : 'a> {
       data : &'a[&'a T] // Store ref to cartesian product.
   }
 
   impl<'a, T : 'a + Debug> Consumer for Worker2<'a, T> {
       fn consume(&self) {
           // read new share cartesian product and do something about it, in this case simply print it.
           println!("Work2 has {:?}", self.data);
       }
   }

   unsafe fn start_cartesian_product_process<'a>(data : &'a[&'a[i32]], cur_result : *mut [&'a i32], consumers : Vec<Box<Consumer + 'a>>) {
       unsafe_cartesian_product(data, cur_result, || {
           consumers.iter().for_each(|c| {
               c.consume();
           })
       });
   }
 
   let data : &[&[i32]] = &[&[1, 2], &[3, 4, 5], &[6]];
   let mut result = vec![&data[0][0]; data.len()];

   unsafe {

       let shared = result.as_mut_slice() as *mut [&i32];
       let worker1 = Worker1 {
           data : &result
       };
       let worker2 = Worker2 {
           data : &result
       };
       let consumers : Vec<Box<Consumer>> = vec![Box::new(worker1), Box::new(worker2)];
       start_cartesian_product_process(data, shared, consumers);
   }

See