use core::{borrow::Borrow, fmt, marker::PhantomData};
use crate::{
Augment, AugmentedRBTree, TreeLocation,
alloc_proxy::proxy::{Allocator, Global},
search::{InOrderIter, InOrderPruningPolicy},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Interval<T> {
pub lo: T,
pub hi: T,
}
impl<T: Ord> Interval<T> {
#[must_use]
pub fn new(lo: T, hi: T) -> Self {
assert!(lo <= hi, "Interval requires lo <= hi");
Self { lo, hi }
}
#[must_use]
pub fn overlaps(&self, other: &Self) -> bool {
self.lo <= other.hi && other.lo <= self.hi
}
#[must_use]
pub fn contains_point(&self, point: &T) -> bool {
&self.lo <= point && point <= &self.hi
}
#[must_use]
pub fn len(&self) -> T
where
T: core::ops::Sub<Output = T> + Copy,
{
self.hi - self.lo
}
#[must_use]
pub fn is_point(&self) -> bool
where
T: PartialEq,
{
self.lo == self.hi
}
}
impl<T: Ord> PartialOrd for Interval<T> {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<T: Ord> Ord for Interval<T> {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.lo.cmp(&other.lo).then_with(|| self.hi.cmp(&other.hi))
}
}
impl<T: fmt::Display> fmt::Display for Interval<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[{}, {}]", self.lo, self.hi)
}
}
#[derive(Debug, Clone, Copy)]
pub struct MaxHi<T>(core::marker::PhantomData<T>);
impl<T: Ord + Clone + Default, V> Augment<Interval<T>, V> for MaxHi<T> {
type Stats = T;
fn compute(
key: &Interval<T>,
_value: &V,
left: Option<(&Interval<T>, &V, &Self::Stats)>,
right: Option<(&Interval<T>, &V, &Self::Stats)>,
) -> Self::Stats {
let mut max = key.hi.clone();
if let Some((_, _, l_max)) = left {
if l_max > &max {
max = l_max.clone();
}
}
if let Some((_, _, r_max)) = right {
if r_max > &max {
max = r_max.clone();
}
}
max
}
}
pub mod internal_details {
use core::marker::PhantomData;
#[derive(Debug)]
pub struct IntervalOverlapPolicy<T, KBound> {
pub(crate) lo: KBound,
pub(crate) hi: KBound,
pub(crate) _marker: PhantomData<T>,
}
}
impl<T: Ord, KBound, V> InOrderPruningPolicy<Interval<T>, V, T>
for internal_details::IntervalOverlapPolicy<T, KBound>
where
KBound: Borrow<T>,
{
#[inline]
fn is_match(&self, key: &Interval<T>, _value: &V, _stats: &T) -> bool {
key.lo <= *self.hi.borrow() && key.hi >= *self.lo.borrow()
}
#[inline]
fn should_explore_left(
&self,
left: (&Interval<T>, &V, &T),
_current: (&Interval<T>, &V, &T),
) -> bool {
*left.2 >= *self.lo.borrow()
}
#[inline]
fn should_explore_right(
&self,
right: (&Interval<T>, &V, &T),
current: (&Interval<T>, &V, &T),
) -> bool {
*right.2 >= *self.lo.borrow() && current.0.lo <= *self.hi.borrow()
}
}
pub struct IntervalTree<T: Ord + Clone + Default, V, A: Allocator = Global> {
inner: AugmentedRBTree<Interval<T>, V, MaxHi<T>, A>,
}
impl<T: Ord + Clone + Default, V> IntervalTree<T, V> {
#[must_use]
pub fn new() -> Self {
Self {
inner: AugmentedRBTree::new(),
}
}
}
impl<T: Ord + Clone + Default, V> Default for IntervalTree<T, V> {
fn default() -> Self {
Self::new()
}
}
impl<T: Ord + Clone + Default, V, A: Allocator> IntervalTree<T, V, A> {
#[must_use]
pub fn new_in(alloc: A) -> Self {
Self {
inner: AugmentedRBTree::new_in(alloc),
}
}
#[must_use]
pub fn inner_tree(&self) -> &AugmentedRBTree<Interval<T>, V, MaxHi<T>, A> {
&self.inner
}
pub fn insert(&mut self, interval: Interval<T>, value: V) -> Option<V> {
self.inner.insert(interval, value)
}
pub fn remove(&mut self, interval: &Interval<T>) -> Option<V> {
self.inner.remove(interval)
}
#[must_use]
pub fn get(&self, interval: &Interval<T>) -> Option<&V> {
self.inner.get(interval)
}
#[must_use]
pub fn contains(&self, interval: &Interval<T>) -> bool {
self.inner.contains_key(interval)
}
#[must_use]
pub fn len(&self) -> usize {
self.inner.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = (&Interval<T>, &V)> {
self.inner.iter().map(|(k, v, _)| (k, v))
}
pub fn query_overlap<K>(&self, lo: K, hi: K) -> impl Iterator<Item = (&Interval<T>, &V)>
where
K: Borrow<T>,
{
let policy = internal_details::IntervalOverlapPolicy {
lo,
hi,
_marker: PhantomData,
};
InOrderIter::new(self.inner_tree(), TreeLocation::Root, policy).map(|(k, v, _)| (k, v))
}
pub fn query_point<K>(&self, point: K) -> impl Iterator<Item = (&Interval<T>, &V)>
where
K: Borrow<T> + Clone,
{
let lo = point.clone();
let hi = point;
self.query_overlap::<K>(lo, hi)
}
#[must_use]
pub fn any_overlaps<K>(&self, lo: K, hi: K) -> bool
where
K: Borrow<T>,
{
self.query_overlap(lo, hi).next().is_some()
}
#[must_use]
pub fn any_contains_point<K>(&self, point: K) -> bool
where
K: Borrow<T> + Clone,
{
self.any_overlaps(point.clone(), point)
}
#[must_use]
pub fn first_overlap<K>(&self, lo: K, hi: K) -> Option<(&'_ Interval<T>, &'_ V)>
where
K: Borrow<T>,
{
self.query_overlap(lo, hi).next()
}
}
impl<T: Ord + Clone + Default + fmt::Debug, V: fmt::Debug> fmt::Debug for IntervalTree<T, V> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_map().entries(self.iter()).finish()
}
}
pub type OverlapIter<'a, T, V, K> =
InOrderIter<'a, Interval<T>, V, T, internal_details::IntervalOverlapPolicy<T, K>>;
#[cfg(test)]
mod tests {
#[test]
fn test_interval_functions() {
use super::Interval;
let iv1 = Interval::new(1, 5);
let iv2 = Interval::new(4, 8);
let iv3 = Interval::new(6, 10);
assert!(iv1.overlaps(&iv2));
assert!(!iv1.overlaps(&iv3));
assert!(iv2.overlaps(&iv3));
assert!(iv1.contains_point(&3));
assert!(!iv1.contains_point(&6));
assert_eq!(iv1.len(), 4);
assert!(!iv1.is_point());
}
}