Skip to content

Instantly share code, notes, and snippets.

@conradludgate
Last active May 23, 2021 09:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save conradludgate/9b930cf33b6494186bad1928ab27dcd6 to your computer and use it in GitHub Desktop.
Save conradludgate/9b930cf33b6494186bad1928ab27dcd6 to your computer and use it in GitHub Desktop.
Works with const generics
#![feature(maybe_uninit_uninit_array)]
#![feature(maybe_uninit_write_slice)]
#![feature(maybe_uninit_array_assume_init)]
use std::{mem::MaybeUninit};
fn main() {
let v = vec![1, 2, 3, 4, 5, 6];
for [a, b, c] in CombiIterator::new(v) {
println!("{:?} {:?} {:?}", a, b, c);
}
}
#[derive(Debug, Clone)]
struct CombiIterator<T, const R: usize> {
slice: Vec<T>,
ends: [usize; R],
}
impl<T, const R: usize> CombiIterator<T, R> {
pub fn new(slice: Vec<T>) -> Self {
let n = slice.len();
debug_assert!(n >= R);
Self {
slice,
ends: [n; R],
}
}
}
impl<T: Clone, const R: usize> Iterator for CombiIterator<T, R> {
type Item = [T; R];
fn next(&mut self) -> Option<Self::Item> {
if self.ends[0] < R {
return None;
}
let output = clone_slice(&self.slice);
self.slice[R-1..self.ends[0]].rotate_left(1);
self.ends[0] -= 1;
let mut x = 0;
for i in 0..R-1 {
if self.ends[i] < R {
self.ends[i+1] -= 1;
x = i + 1;
} else {
break;
}
}
for i in 0..x {
self.ends[i] = self.ends[x];
}
if x > 0 {
let e = self.ends[0] + 1;
self.slice[R-x..R].reverse();
self.slice[R-x..e].reverse();
self.slice[R-x-1..e].rotate_left(1);
}
Some(output)
}
}
fn clone_slice<T: Clone, const R: usize>(slice: &[T]) -> [T; R] {
debug_assert!(slice.len() >= R);
let mut output = MaybeUninit::uninit_array::<R>();
// Clone the contents of the slice into the array
MaybeUninit::write_slice_cloned(&mut output, &slice[..R]);
// SAFETY: We have just initialised the array above
unsafe { MaybeUninit::array_assume_init(output) }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment