use std::ops::Range;
pub const DEFAULT_BLOCK_ITEMS: usize = 64;
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct BlockPlan {
count: usize,
block: usize,
}
impl BlockPlan {
#[must_use]
pub const fn new(count: usize, block: usize) -> Self {
Self {
count,
block: if block == 0 { 1 } else { block },
}
}
#[must_use]
pub const fn with_default_block(count: usize) -> Self {
Self::new(count, DEFAULT_BLOCK_ITEMS)
}
#[must_use]
pub const fn count(self) -> usize {
self.count
}
#[must_use]
pub const fn block(self) -> usize {
self.block
}
#[must_use]
pub const fn blocks(self) -> usize {
self.count.div_ceil(self.block)
}
#[must_use]
pub const fn is_empty(self) -> bool {
self.count == 0
}
#[must_use]
pub fn range(self, index: usize) -> Option<Range<usize>> {
if index >= self.blocks() {
return None;
}
let start = index.checked_mul(self.block)?;
let end = start.checked_add(self.block)?.min(self.count);
Some(start..end)
}
pub fn ranges(self) -> impl Iterator<Item = Range<usize>> {
(0..self.blocks()).filter_map(move |index| self.range(index))
}
#[must_use]
pub fn useful_workers(self, requested: usize) -> usize {
requested.max(1).min(self.blocks().max(1))
}
}
#[cfg(test)]
#[path = "plan_tests.rs"]
mod tests;