#[cfg(test)]
mod tests;
pub(crate) mod error;
use std::fmt::Debug;
pub use error::EmptySliceError;
#[derive(Debug)]
pub struct Bisector<'v, T> {
view: &'v [T],
}
impl<'v, T> Bisector<'v, T> {
pub fn new(view: &'v [T]) -> Self {
Self { view }
}
pub fn view(&self) -> &'v [T] {
self.view
}
pub fn bisect<F, L, R>(&self, f: F, indices: Indices) -> Step<L, R>
where
F: FnOnce(&T) -> ConvergeTo<L, R>,
{
let Indices { left, right } = indices;
if left == right {
return Step {
indices,
result: None,
};
}
let middle = indices.middle();
match f(&self.view[middle]) {
ConvergeTo::Left(out) => Step {
indices: Indices {
left,
right: middle,
},
result: Some(ConvergeTo::Left(out)),
},
ConvergeTo::Right(out) => Step {
indices: Indices {
left: middle + 1,
right,
},
result: Some(ConvergeTo::Right(out)),
},
}
}
pub fn try_bisect<F, E, L, R>(&self, f: F, indices: Indices) -> Result<Step<L, R>, E>
where
F: FnOnce(&T) -> Result<ConvergeTo<L, R>, E>,
{
let Indices { left, right } = indices;
if left == right {
return Ok(Step {
indices,
result: None,
});
}
let middle = indices.middle();
match f(&self.view[middle])? {
ConvergeTo::Left(out) => Ok(Step {
indices: Indices {
left,
right: middle,
},
result: Some(ConvergeTo::Left(out)),
}),
ConvergeTo::Right(out) => Ok(Step {
indices: Indices {
left: middle + 1,
right,
},
result: Some(ConvergeTo::Right(out)),
}),
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct Indices {
pub left: usize,
pub right: usize,
}
impl Indices {
pub fn new(left_index: usize, right_index: usize) -> Self {
Self {
left: left_index,
right: right_index,
}
}
pub fn from_bisector<T>(bisector: &Bisector<T>) -> Self {
Self {
left: 0,
right: bisector.view.len(),
}
}
pub fn try_from_bisector<T>(bisector: &Bisector<T>) -> Result<Self, EmptySliceError> {
if !bisector.view.is_empty() {
Ok(Self {
left: 0,
right: bisector.view.len(),
})
} else {
Err(EmptySliceError)
}
}
#[inline]
pub fn middle(&self) -> usize {
debug_assert!(
self.right >= self.left,
"right index ({}) < left index ({}), but expected right index >= left index",
self.right,
self.left,
);
self.left + ((self.right - self.left) / 2)
}
}
pub struct Step<L, R> {
pub indices: Indices,
pub result: Option<ConvergeTo<L, R>>,
}
pub enum ConvergeTo<Left, Right> {
Left(Left),
Right(Right),
}
impl<Left, Right> ConvergeTo<Left, Right> {
pub fn try_into_left(self) -> Option<Left> {
if let Self::Left(left) = self {
Some(left)
} else {
None
}
}
pub fn try_into_right(self) -> Option<Right> {
if let Self::Right(right) = self {
Some(right)
} else {
None
}
}
}