/// Utils: general utilities. /// An iterator over a slice in a fixed number of non-overlapping /// chunks, starting at the beginning of the slice. /// /// When the slice len is not evenly divisible by the number of /// chunks, the length of individual chunks may vary, with each chunk /// being augmented by a single element until the remainder is /// evenly distributed. /// /// TODO: /// - implement size_hint, count, etc as appropriate /// - improve test coverage /// - extract to own crate #[derive(Debug, Clone)] pub struct ChunksFixed<'a, T: 'a> { v: &'a [T], size: usize, rem: usize, } pub fn chunks_fixed(slice: &[T], num_chunks: usize) -> ChunksFixed { ChunksFixed { v: slice, size: slice.len() / num_chunks, rem: slice.len() % num_chunks, } } impl<'a, T> Iterator for ChunksFixed<'a, T> { type Item = &'a [T]; #[inline] fn next(&mut self) -> Option<&'a [T]> { if self.v.is_empty() { return None; } let s = if self.rem > 0 { self.rem -= 1; self.size + 1 } else { self.size }; let (fst, snd) = self.v.split_at(s); self.v = snd; Some(fst) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_chunks_fixed_10_into_10() { let v = vec![0; 10]; let chunks = chunks_fixed(&v, 10).collect::>(); assert_eq!(chunks.len(), 10); chunks.iter().for_each(|chunk| assert_eq!(chunk.len(), 1)); } #[test] fn test_chunks_fixed_100_into_10() { let v = vec![0; 100]; let chunks = chunks_fixed(&v, 10).collect::>(); assert_eq!(chunks.len(), 10); chunks.iter().for_each(|chunk| assert_eq!(chunk.len(), 10)); } #[test] fn test_chunks_fixed_101_into_10() { let v = vec![0; 101]; let chunks = chunks_fixed(&v, 10).collect::>(); assert_eq!(chunks.len(), 10); chunks.iter().enumerate().for_each(|(i, chunk)| { if i == 0 { assert_eq!(chunk.len(), 11); } else { assert_eq!(chunk.len(), 10); } }); } #[test] fn test_chunks_fixed_10399_into_800() { let v = vec![0; 10399]; let chunks = chunks_fixed(&v, 800).collect::>(); assert_eq!(chunks.len(), 800); chunks.iter().enumerate().for_each(|(i, chunk)| { if i < 799 { assert_eq!(chunk.len(), 13); } else { assert_eq!(chunk.len(), 12); } }); } #[test] fn test_chunks_fixed_10400_into_800() { let v = vec![0; 10400]; let chunks = chunks_fixed(&v, 800).collect::>(); assert_eq!(chunks.len(), 800); chunks.iter().for_each(|chunk| { assert_eq!(chunk.len(), 13); }); } #[test] fn test_chunks_fixed_10401_into_800() { let v = vec![0; 10401]; let chunks = chunks_fixed(&v, 800).collect::>(); assert_eq!(chunks.len(), 800); chunks.iter().enumerate().for_each(|(i, chunk)| { if i == 0 { assert_eq!(chunk.len(), 14); } else { assert_eq!(chunk.len(), 13); } }); } }