Add ChunksFixed iterator

This commit is contained in:
Rob Watson 2020-09-09 00:46:05 +02:00
parent 08ee712448
commit 76c978ae1f
2 changed files with 130 additions and 0 deletions

View File

@ -10,6 +10,7 @@ mod app;
mod canvas;
mod controls;
mod home;
mod utils;
#[wasm_bindgen(start)]
pub fn run_app() {

129
src/utils.rs Normal file
View File

@ -0,0 +1,129 @@
/// 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<T>(slice: &[T], num_chunks: usize) -> ChunksFixed<T> {
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::<Vec<_>>();
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::<Vec<_>>();
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::<Vec<_>>();
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::<Vec<_>>();
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::<Vec<_>>();
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::<Vec<_>>();
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);
}
});
}
}