use std::cmp::Ordering;
use std::fmt::{self, Debug};
use std::iter::once;
use std::marker::PhantomData;
use std::ops::{Bound, RangeBounds};
use btree_monstrousity::btree_map::{
IntoIter as BTreeMapIntoIter, SearchBoundCustom,
};
use btree_monstrousity::BTreeMap;
use either::Either;
use serde::de::{MapAccess, Visitor};
use serde::ser::SerializeMap;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::bound_ord::BoundOrd;
use crate::utils::{
cmp_range_with_bound_ord, cut_range, flip_bound, is_valid_range, overlaps,
};
use crate::TryFromBounds;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RangeBoundsMap<I, K, V> {
inner: BTreeMap<K, V>,
phantom: PhantomData<I>,
}
#[derive(PartialEq, Debug)]
pub struct OverlapError;
#[derive(PartialEq, Debug)]
pub struct TryFromBoundsError;
#[derive(PartialEq, Debug)]
pub enum OverlapOrTryFromBoundsError {
Overlap(OverlapError),
TryFromBounds(TryFromBoundsError),
}
impl<I, K, V> RangeBoundsMap<I, K, V>
where
I: Ord + Copy,
K: NiceRange<I>,
{
pub fn new() -> Self {
RangeBoundsMap {
inner: BTreeMap::new(),
phantom: PhantomData,
}
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn overlaps<Q>(&self, range: Q) -> bool
where
Q: NiceRange<I>,
{
invalid_range_panic(range);
self.overlapping(range).next().is_some()
}
pub fn overlapping<Q>(
&self,
range: Q,
) -> impl DoubleEndedIterator<Item = (&K, &V)>
where
Q: NiceRange<I>,
{
invalid_range_panic(range);
let start_comp = overlapping_start_comp(range.start());
let end_comp = overlapping_end_comp(range.end());
let start_bound = SearchBoundCustom::Included;
let end_bound = SearchBoundCustom::Included;
self.inner
.range(start_comp, start_bound, end_comp, end_bound)
}
pub fn overlapping_mut<Q>(
&mut self,
range: Q,
) -> impl DoubleEndedIterator<Item = (&K, &mut V)>
where
Q: NiceRange<I>,
{
invalid_range_panic(range);
let start_comp = overlapping_start_comp(range.start());
let end_comp = overlapping_end_comp(range.end());
let start_bound = SearchBoundCustom::Included;
let end_bound = SearchBoundCustom::Included;
self.inner
.range_mut(start_comp, start_bound, end_comp, end_bound)
}
pub fn get_at_point(&self, point: I) -> Option<&V> {
self.get_entry_at_point(point).map(|(_, value)| value).ok()
}
pub fn get_at_point_mut(&mut self, point: I) -> Option<&mut V> {
self.inner
.get_mut(overlapping_start_comp(Bound::Included(point)))
}
pub fn contains_point(&self, point: I) -> bool {
self.get_entry_at_point(point).is_ok()
}
pub fn get_entry_at_point(
&self,
point: I,
) -> Result<(&K, &V), (Bound<I>, Bound<I>)> {
self.inner
.get_key_value(overlapping_start_comp(Bound::Included(point)))
.ok_or_else(|| {
let lower = self.inner.upper_bound(
overlapping_start_comp(Bound::Included(point)),
SearchBoundCustom::Included,
);
let upper = self.inner.lower_bound(
overlapping_end_comp(Bound::Included(point)),
SearchBoundCustom::Included,
);
(
lower.key().map_or(Bound::Unbounded, |lower| {
flip_bound(lower.end())
}),
upper.key().map_or(Bound::Unbounded, |upper| {
flip_bound(upper.start())
}),
)
})
}
pub fn iter(&self) -> impl DoubleEndedIterator<Item = (&K, &V)> {
self.inner.iter()
}
pub fn iter_mut(
&mut self,
) -> impl DoubleEndedIterator<Item = (&K, &mut V)> {
self.inner.iter_mut()
}
pub fn remove_overlapping<'a, Q>(
&'a mut self,
range: Q,
) -> impl Iterator<Item = (K, V)> + '_
where
Q: NiceRange<I> + 'a,
{
invalid_range_panic(range);
return self
.inner
.drain_filter(move |inner_range, _| overlaps(*inner_range, range));
}
pub fn cut<'a, Q>(
&'a mut self,
range: Q,
) -> Result<
impl Iterator<Item = ((Bound<I>, Bound<I>), V)> + '_,
TryFromBoundsError,
>
where
Q: NiceRange<I> + 'a,
K: TryFromBounds<I>,
V: Clone,
{
invalid_range_panic(range);
let start_comp = overlapping_start_comp(range.start());
let end_comp = overlapping_end_comp(range.end());
let left_overlapping = self
.inner
.get_key_value(start_comp)
.map(|(key, _)| key)
.copied();
let right_overlapping = self
.inner
.get_key_value(end_comp)
.map(|(key, _)| key)
.copied();
if let Some(left) = left_overlapping && let Some(right) = right_overlapping && left.start() == right.start() {
Ok(Either::Left(self.cut_single_overlapping(range, left)?))
} else {
Ok(Either::Right(self.cut_non_single_overlapping(range, left_overlapping, right_overlapping)?))
}
}
fn cut_single_overlapping<Q>(
&mut self,
range: Q,
single_overlapping_range: K,
) -> Result<
impl Iterator<Item = ((Bound<I>, Bound<I>), V)>,
TryFromBoundsError,
>
where
Q: NiceRange<I>,
K: TryFromBounds<I>,
V: Clone,
{
invalid_range_panic(range);
let cut_result = cut_range(single_overlapping_range, range);
let returning_before_cut = match cut_result.before_cut {
Some((start, end)) => Some(K::try_from_bounds(start, end)?),
None => None,
};
let returning_after_cut = match cut_result.after_cut {
Some((start, end)) => Some(K::try_from_bounds(start, end)?),
None => None,
};
let value = self
.inner
.remove(overlapping_start_comp(range.start()))
.unwrap();
if let Some(before) = returning_before_cut {
self.insert_unchecked(before, value.clone());
}
if let Some(after) = returning_after_cut {
self.insert_unchecked(after, value.clone());
}
Ok(once((cut_result.inside_cut.unwrap(), value)))
}
fn cut_non_single_overlapping<'a, Q>(
&'a mut self,
range: Q,
left_overlapping: Option<K>,
right_overlapping: Option<K>,
) -> Result<
impl Iterator<Item = ((Bound<I>, Bound<I>), V)> + '_,
TryFromBoundsError,
>
where
Q: NiceRange<I> + 'a,
K: TryFromBounds<I>,
V: Clone,
{
invalid_range_panic(range);
let before_config = match left_overlapping {
Some(before) => {
let cut_result = cut_range(before, range);
Some((
match cut_result.before_cut {
Some((start, end)) => {
Some(K::try_from_bounds(start, end)?)
}
None => None,
},
cut_result.inside_cut.unwrap(),
))
}
None => None,
};
let after_config = match right_overlapping {
Some(after) => {
let cut_result = cut_range(after, range);
Some((
match cut_result.after_cut {
Some((start, end)) => {
Some(K::try_from_bounds(start, end)?)
}
None => None,
},
cut_result.inside_cut.unwrap(),
))
}
None => None,
};
let before_value =
self.inner.remove(overlapping_start_comp(range.start()));
let after_value = self.inner.remove(overlapping_end_comp(range.end()));
if let Some((Some(returning_before_cut), _)) = before_config {
self.insert_unchecked(
returning_before_cut,
before_value.as_ref().cloned().unwrap(),
);
}
if let Some((Some(returning_after_cut), _)) = after_config {
self.insert_unchecked(
returning_after_cut,
after_value.as_ref().cloned().unwrap(),
);
}
let keeping_before_entry =
before_config.map(|(_, keeping_before_entry)| {
(keeping_before_entry, before_value.unwrap())
});
let keeping_after_entry =
after_config.map(|(_, keeping_after_entry)| {
(keeping_after_entry, after_value.unwrap())
});
return Ok(keeping_before_entry
.into_iter()
.chain(
self.remove_overlapping(range)
.map(|(key, value)| ((key.start(), key.end()), value)),
)
.chain(keeping_after_entry.into_iter()));
}
pub fn gaps<Q>(
&self,
outer_range: Q,
) -> impl DoubleEndedIterator<Item = (Bound<I>, Bound<I>)>
where
Q: NiceRange<I>,
{
invalid_range_panic(outer_range);
let overlapping = self
.overlapping(outer_range)
.map(|(key, _)| (key.start(), key.end()));
let artificial_start = (
flip_bound(outer_range.start()),
flip_bound(outer_range.start()),
);
let artificial_end =
(flip_bound(outer_range.end()), flip_bound(outer_range.end()));
let mut artificials = once(artificial_start)
.chain(overlapping)
.chain(once(artificial_end));
let start_contained = self
.inner
.contains_key(overlapping_start_comp(outer_range.start()));
let end_contained = self
.inner
.contains_key(overlapping_end_comp(outer_range.end()));
if start_contained {
artificials.next();
}
if end_contained {
artificials.next_back();
}
return artificials
.collect::<Vec<_>>()
.windows(2)
.map(|windows| (flip_bound(windows[0].1), flip_bound(windows[1].0)))
.filter(|range| is_valid_range(*range))
.collect::<Vec<_>>()
.into_iter();
}
pub fn contains_range<Q>(&self, range: Q) -> bool
where
Q: NiceRange<I>,
{
invalid_range_panic(range);
self.gaps(range).next().is_none()
}
pub fn insert_strict(
&mut self,
range: K,
value: V,
) -> Result<(), OverlapError> {
invalid_range_panic(range);
if self.overlaps(range) {
return Err(OverlapError);
}
self.insert_unchecked(range, value);
return Ok(());
}
fn insert_unchecked(&mut self, range: K, value: V) {
self.inner.insert(range, value, double_comp());
}
fn insert_merge_with_comps<G1, G2, R1, R2>(
&mut self,
range: K,
value: V,
get_start: G1,
get_end: G2,
remove_start: R1,
remove_end: R2,
) -> Result<K, TryFromBoundsError>
where
K: TryFromBounds<I>,
G1: FnOnce(&Self, &V) -> Option<K>,
G2: FnOnce(&Self, &V) -> Option<K>,
R1: FnOnce(&mut Self, &V),
R2: FnOnce(&mut Self, &V),
{
invalid_range_panic(range);
let matching_start = get_start(self, &value);
let matching_end = get_end(self, &value);
let returning = match (matching_start, matching_end) {
(Some(matching_start), Some(matching_end)) => {
K::try_from_bounds(matching_start.start(), matching_end.end())?
}
(Some(matching_start), None) => {
K::try_from_bounds(matching_start.start(), range.end())?
}
(None, Some(matching_end)) => {
K::try_from_bounds(range.start(), matching_end.end())?
}
(None, None) => range,
};
let _ = self.remove_overlapping(range);
remove_start(self, &value);
remove_end(self, &value);
self.insert_unchecked(returning, value);
Ok(returning)
}
pub fn insert_merge_touching(
&mut self,
range: K,
value: V,
) -> Result<K, OverlapOrTryFromBoundsError>
where
K: TryFromBounds<I>,
{
invalid_range_panic(range);
if self.overlaps(range) {
return Err(OverlapOrTryFromBoundsError::Overlap(OverlapError));
}
self.insert_merge_with_comps(
range,
value,
|selfy, _| {
selfy
.inner
.get_key_value(touching_start_comp(range.start()))
.map(|(key, _)| key)
.copied()
},
|selfy, _| {
selfy
.inner
.get_key_value(touching_end_comp(range.end()))
.map(|(key, _)| key)
.copied()
},
|selfy, _| {
selfy.inner.remove(touching_start_comp(range.start()));
},
|selfy, _| {
selfy.inner.remove(touching_end_comp(range.end()));
},
)
.map_err(OverlapOrTryFromBoundsError::TryFromBounds)
}
pub fn insert_merge_touching_if_values_equal(
&mut self,
range: K,
value: V,
) -> Result<K, OverlapOrTryFromBoundsError>
where
K: TryFromBounds<I>,
V: Eq,
{
invalid_range_panic(range);
if self.overlaps(range) {
return Err(OverlapOrTryFromBoundsError::Overlap(OverlapError));
}
let get_start = |selfy: &Self, value: &V| {
selfy
.inner
.get_key_value(touching_start_comp(range.start()))
.filter(|(_, start_touching_value)| {
*start_touching_value == value
})
.map(|(key, _)| key)
.copied()
};
let get_end = |selfy: &Self, value: &V| {
selfy
.inner
.get_key_value(touching_end_comp(range.end()))
.filter(|(_, start_touching_value)| {
*start_touching_value == value
})
.map(|(key, _)| key)
.copied()
};
self.insert_merge_with_comps(
range,
value,
get_start,
get_end,
|selfy, value| {
if get_start(selfy, value).is_some() {
selfy.inner.remove(touching_start_comp(range.start()));
}
},
|selfy, value| {
if get_end(selfy, value).is_some() {
selfy.inner.remove(touching_end_comp(range.end()));
}
},
)
.map_err(OverlapOrTryFromBoundsError::TryFromBounds)
}
pub fn insert_merge_overlapping(
&mut self,
range: K,
value: V,
) -> Result<K, TryFromBoundsError>
where
K: TryFromBounds<I>,
{
invalid_range_panic(range);
self.insert_merge_with_comps(
range,
value,
|selfy, _| {
selfy
.inner
.get_key_value(overlapping_start_comp(range.start()))
.map(|(key, _)| key)
.copied()
},
|selfy, _| {
selfy
.inner
.get_key_value(overlapping_end_comp(range.end()))
.map(|(key, _)| key)
.copied()
},
|_, _| {},
|_, _| {},
)
}
pub fn insert_merge_touching_or_overlapping(
&mut self,
range: K,
value: V,
) -> Result<K, TryFromBoundsError>
where
K: TryFromBounds<I>,
{
invalid_range_panic(range);
self.insert_merge_with_comps(
range,
value,
|selfy, _| {
selfy
.inner
.get_key_value(touching_start_comp(range.start()))
.map(|(key, _)| key)
.or(selfy
.inner
.get_key_value(overlapping_start_comp(range.start()))
.map(|(key, _)| key))
.copied()
},
|selfy, _| {
selfy
.inner
.get_key_value(touching_end_comp(range.end()))
.map(|(key, _)| key)
.or(selfy
.inner
.get_key_value(overlapping_end_comp(range.end()))
.map(|(key, _)| key))
.copied()
},
|selfy, _| {
selfy.inner.remove(touching_start_comp(range.start()));
},
|selfy, _| {
selfy.inner.remove(touching_end_comp(range.end()));
},
)
}
pub fn insert_overwrite(
&mut self,
range: K,
value: V,
) -> Result<(), TryFromBoundsError>
where
K: TryFromBounds<I>,
V: Clone,
{
invalid_range_panic(range);
let _ = self.cut(range)?;
self.insert_unchecked(range, value);
return Ok(());
}
pub fn first_entry(&self) -> Option<(&K, &V)> {
self.inner.first_key_value()
}
pub fn last_entry(&self) -> Option<(&K, &V)> {
self.inner.last_key_value()
}
pub fn from_slice_strict<const N: usize>(
slice: [(K, V); N],
) -> Result<RangeBoundsMap<I, K, V>, OverlapError> {
let mut map = RangeBoundsMap::new();
for (range, value) in slice {
map.insert_strict(range, value)?;
}
return Ok(map);
}
}
fn invalid_range_panic<Q, I>(range: Q)
where
Q: NiceRange<I>,
I: Ord,
{
if !is_valid_range(range) {
panic!(
"invalid range given to function see here for more details: https://docs.rs/range_bounds_map/latest/range_bounds_map/#invalid-ranges"
);
}
}
fn double_comp<K, I>() -> impl FnMut(&K, &K) -> Ordering
where
K: NiceRange<I>,
I: Ord,
{
|inner_range: &K, new_range: &K| {
BoundOrd::start(new_range.start())
.cmp(&BoundOrd::start(inner_range.start()))
}
}
fn overlapping_start_comp<I, K>(start: Bound<I>) -> impl FnMut(&K) -> Ordering
where
I: Ord + Copy,
K: NiceRange<I>,
{
move |inner_range: &K| {
cmp_range_with_bound_ord(*inner_range, BoundOrd::start(start))
}
}
fn overlapping_end_comp<I, K>(end: Bound<I>) -> impl FnMut(&K) -> Ordering
where
I: Ord + Copy,
K: NiceRange<I>,
{
move |inner_range: &K| {
cmp_range_with_bound_ord(*inner_range, BoundOrd::end(end))
}
}
fn touching_start_comp<I, K>(start: Bound<I>) -> impl FnMut(&K) -> Ordering
where
I: Ord + Copy,
K: NiceRange<I>,
{
move |inner_range: &K| match (inner_range.end(), start) {
(Bound::Included(end), Bound::Excluded(start)) if end == start => {
Ordering::Equal
}
(Bound::Excluded(end), Bound::Included(start)) if end == start => {
Ordering::Equal
}
(end, start) => {
let normal_result = BoundOrd::start(start).cmp(&BoundOrd::end(end));
match normal_result {
Ordering::Equal => Ordering::Greater,
x => x,
}
}
}
}
fn touching_end_comp<I, K>(end: Bound<I>) -> impl FnMut(&K) -> Ordering
where
I: Ord + Copy,
K: NiceRange<I>,
{
move |inner_range: &K| match (end, inner_range.start()) {
(Bound::Included(end), Bound::Excluded(start)) if end == start => {
Ordering::Equal
}
(Bound::Excluded(end), Bound::Included(start)) if end == start => {
Ordering::Equal
}
(end, _start) => {
let normal_result =
BoundOrd::end(end).cmp(&BoundOrd::start(inner_range.start()));
match normal_result {
Ordering::Equal => Ordering::Less,
x => x,
}
}
}
}
pub trait NiceRange<I>: Copy {
fn start(&self) -> Bound<I>;
fn end(&self) -> Bound<I>;
}
impl<K, I> NiceRange<I> for K
where
I: Copy,
K: RangeBounds<I> + Copy,
{
fn start(&self) -> Bound<I> {
self.start_bound().cloned()
}
fn end(&self) -> Bound<I> {
self.end_bound().cloned()
}
}
impl<I, K, V> IntoIterator for RangeBoundsMap<I, K, V> {
type Item = (K, V);
type IntoIter = IntoIter<I, K, V>;
fn into_iter(self) -> Self::IntoIter {
return IntoIter {
inner: self.inner.into_iter(),
phantom: PhantomData,
};
}
}
pub struct IntoIter<I, K, V> {
inner: BTreeMapIntoIter<K, V>,
phantom: PhantomData<I>,
}
impl<I, K, V> Iterator for IntoIter<I, K, V> {
type Item = (K, V);
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
}
impl<I, K, V> Default for RangeBoundsMap<I, K, V> {
fn default() -> Self {
RangeBoundsMap {
inner: BTreeMap::default(),
phantom: PhantomData,
}
}
}
impl<I, K, V> Serialize for RangeBoundsMap<I, K, V>
where
I: Ord + Copy,
K: NiceRange<I> + Serialize,
V: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut map = serializer.serialize_map(Some(self.len()))?;
for (range_bounds, value) in self.iter() {
map.serialize_entry(range_bounds, value)?;
}
map.end()
}
}
impl<'de, I, K, V> Deserialize<'de> for RangeBoundsMap<I, K, V>
where
I: Ord + Copy,
K: NiceRange<I> + Deserialize<'de>,
V: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_map(RangeBoundsMapVisitor {
i: PhantomData,
k: PhantomData,
v: PhantomData,
})
}
}
struct RangeBoundsMapVisitor<I, K, V> {
i: PhantomData<I>,
k: PhantomData<K>,
v: PhantomData<V>,
}
impl<'de, I, K, V> Visitor<'de> for RangeBoundsMapVisitor<I, K, V>
where
I: Ord + Copy,
K: NiceRange<I> + Deserialize<'de>,
V: Deserialize<'de>,
{
type Value = RangeBoundsMap<I, K, V>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a RangeBoundsMap")
}
fn visit_map<A>(self, mut access: A) -> Result<Self::Value, A::Error>
where
A: MapAccess<'de>,
{
let mut map = RangeBoundsMap::new();
while let Some((range_bounds, value)) = access.next_entry()? {
map.insert_strict(range_bounds, value)
.map_err(|_| serde::de::Error::custom("RangeBounds overlap"))?;
}
Ok(map)
}
}
#[cfg(test)]
mod tests {
use std::ops::Bound;
use pretty_assertions::assert_eq;
use super::*;
use crate::bound_ord::BoundOrd;
use crate::test_ranges::{ee, ei, ie, ii, iu, u, ue, ui, uu, AnyRange};
use crate::utils::{config, Config, CutResult};
pub(crate) const NUMBERS: &'static [i8] = &[2, 4, 6, 8, 10];
pub(crate) const NUMBERS_DOMAIN: &'static [i8] =
&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
fn basic() -> RangeBoundsMap<i8, AnyRange, bool> {
RangeBoundsMap::from_slice_strict([
(ui(4), false),
(ee(5, 7), true),
(ii(7, 7), false),
(ie(14, 16), true),
])
.unwrap()
}
fn special() -> RangeBoundsMap<i8, MultiBounds, bool> {
RangeBoundsMap::from_slice_strict([
(mii(4, 6), false),
(mee(7, 8), true),
(mii(8, 12), false),
])
.unwrap()
}
#[derive(Debug, PartialEq, Copy, Clone)]
enum MultiBounds {
Inclusive(i8, i8),
Exclusive(i8, i8),
}
fn mii(start: i8, end: i8) -> MultiBounds {
MultiBounds::Inclusive(start, end)
}
fn mee(start: i8, end: i8) -> MultiBounds {
MultiBounds::Exclusive(start, end)
}
impl RangeBounds<i8> for MultiBounds {
fn start_bound(&self) -> Bound<&i8> {
match self {
MultiBounds::Inclusive(start, _) => Bound::Included(start),
MultiBounds::Exclusive(start, _) => Bound::Excluded(start),
}
}
fn end_bound(&self) -> Bound<&i8> {
match self {
MultiBounds::Inclusive(_, end) => Bound::Included(end),
MultiBounds::Exclusive(_, end) => Bound::Excluded(end),
}
}
}
impl TryFromBounds<i8> for MultiBounds {
fn try_from_bounds(
start_bound: Bound<i8>,
end_bound: Bound<i8>,
) -> Result<Self, TryFromBoundsError> {
match (start_bound, end_bound) {
(Bound::Included(start), Bound::Included(end)) => {
Ok(mii(start, end))
}
(Bound::Excluded(start), Bound::Excluded(end)) => {
Ok(mee(start, end))
}
_ => Err(TryFromBoundsError),
}
}
}
#[test]
fn insert_strict_tests() {
assert_insert_strict(
basic(),
(ii(0, 4), false),
Err(OverlapError),
None::<[_; 0]>,
);
assert_insert_strict(
basic(),
(ii(5, 6), false),
Err(OverlapError),
None::<[_; 0]>,
);
assert_insert_strict(
basic(),
(ee(7, 8), false),
Ok(()),
Some([
(ui(4), false),
(ee(5, 7), true),
(ii(7, 7), false),
(ee(7, 8), false),
(ie(14, 16), true),
]),
);
assert_insert_strict(
basic(),
(ii(4, 5), true),
Err(OverlapError),
None::<[_; 0]>,
);
assert_insert_strict(
basic(),
(ei(4, 5), true),
Ok(()),
Some([
(ui(4), false),
(ei(4, 5), true),
(ee(5, 7), true),
(ii(7, 7), false),
(ie(14, 16), true),
]),
);
}
fn assert_insert_strict<const N: usize>(
mut before: RangeBoundsMap<i8, AnyRange, bool>,
to_insert: (AnyRange, bool),
result: Result<(), OverlapError>,
after: Option<[(AnyRange, bool); N]>,
) {
let clone = before.clone();
assert_eq!(before.insert_strict(to_insert.0, to_insert.1), result);
match after {
Some(after) => {
assert_eq!(
before,
RangeBoundsMap::from_slice_strict(after).unwrap()
)
}
None => assert_eq!(before, clone),
}
}
#[test]
fn overlapping_tests() {
for overlap_range in all_valid_test_bounds() {
assert!(
RangeBoundsMap::<i8, AnyRange, ()>::new()
.overlapping(overlap_range)
.next()
.is_none()
);
}
for overlap_range in all_valid_test_bounds() {
for inside_range in all_valid_test_bounds() {
let mut map = RangeBoundsMap::new();
map.insert_strict(inside_range, ()).unwrap();
let mut expected_overlapping = Vec::new();
if overlaps(overlap_range, inside_range) {
expected_overlapping.push(inside_range);
}
let overlapping = map
.overlapping(overlap_range)
.map(|(key, _)| key)
.copied()
.collect::<Vec<_>>();
if overlapping != expected_overlapping {
dbg!(overlap_range, inside_range);
dbg!(overlapping, expected_overlapping);
panic!(
"Discrepency in .overlapping() with single inside range detected!"
);
}
}
}
for overlap_range in all_valid_test_bounds() {
for (inside_range1, inside_range2) in
all_non_overlapping_test_bound_entries()
{
let mut map = RangeBoundsMap::new();
map.insert_strict(inside_range1, ()).unwrap();
map.insert_strict(inside_range2, ()).unwrap();
let mut expected_overlapping = Vec::new();
if overlaps(overlap_range, inside_range1) {
expected_overlapping.push(inside_range1);
}
if overlaps(overlap_range, inside_range2) {
expected_overlapping.push(inside_range2);
}
if expected_overlapping.len() > 1 {
if BoundOrd::start(expected_overlapping[0].start())
> BoundOrd::start(expected_overlapping[1].start())
{
expected_overlapping.swap(0, 1);
}
}
let overlapping = map
.overlapping(overlap_range)
.map(|(key, _)| key)
.copied()
.collect::<Vec<_>>();
if overlapping != expected_overlapping {
dbg!(overlap_range, inside_range1, inside_range2);
dbg!(overlapping, expected_overlapping);
panic!(
"Discrepency in .overlapping() with two inside ranges detected!"
);
}
}
}
}
#[test]
fn remove_overlapping_tests() {
assert_remove_overlapping(basic(), ii(5, 5), [], None::<[_; 0]>);
assert_remove_overlapping(
basic(),
uu(),
[
(ui(4), false),
(ee(5, 7), true),
(ii(7, 7), false),
(ie(14, 16), true),
],
Some([]),
);
assert_remove_overlapping(
basic(),
ii(6, 7),
[(ee(5, 7), true), (ii(7, 7), false)],
Some([(ui(4), false), (ie(14, 16), true)]),
);
assert_remove_overlapping(
basic(),
iu(6),
[(ee(5, 7), true), (ii(7, 7), false), (ie(14, 16), true)],
Some([(ui(4), false)]),
);
}
fn assert_remove_overlapping<const N: usize, const Y: usize>(
mut before: RangeBoundsMap<i8, AnyRange, bool>,
to_remove: AnyRange,
result: [(AnyRange, bool); N],
after: Option<[(AnyRange, bool); Y]>,
) {
let clone = before.clone();
assert_eq!(
before.remove_overlapping(to_remove).collect::<Vec<_>>(),
result
);
match after {
Some(after) => {
assert_eq!(
before,
RangeBoundsMap::from_slice_strict(after).unwrap()
)
}
None => assert_eq!(before, clone),
}
}
#[test]
fn cut_tests() {
assert_cut(basic(), ii(50, 60), Ok([]), None::<[_; 0]>);
assert_cut(
basic(),
uu(),
Ok([
(ui(4), false),
(ee(5, 7), true),
(ii(7, 7), false),
(ie(14, 16), true),
]),
Some([]),
);
assert_cut(
basic(),
ui(6),
Ok([(ui(4), false), (ei(5, 6), true)]),
Some([(ee(6, 7), true), (ii(7, 7), false), (ie(14, 16), true)]),
);
assert_cut(
basic(),
iu(6),
Ok([(ie(6, 7), true), (ii(7, 7), false), (ie(14, 16), true)]),
Some([(ui(4), false), (ee(5, 6), true)]),
);
assert_cut(
special(),
mee(5, 7),
Ok([((Bound::Excluded(5), Bound::Included(6)), false)]),
Some([(mii(4, 5), false), (mee(7, 8), true), (mii(8, 12), false)]),
);
assert_cut(special(), mee(6, 7), Ok([]), None::<[_; 0]>);
assert_cut(
special(),
mii(5, 6),
Err::<[_; 0], _>(TryFromBoundsError),
None::<[_; 0]>,
);
assert_cut(
special(),
mii(6, 7),
Err::<[_; 0], _>(TryFromBoundsError),
None::<[_; 0]>,
);
assert_cut(
special(),
ie(7, 8),
Ok([((ee(7, 8)), true)]),
Some([(mii(4, 6), false), (mii(8, 12), false)]),
);
assert_cut(
special(),
mii(7, 10),
Err::<[_; 0], _>(TryFromBoundsError),
None::<[_; 0]>,
);
assert_cut(
special(),
mee(4, 6),
Ok([(ee(4, 6), false)]),
Some([
(mii(4, 4), false),
(mii(6, 6), false),
(mee(7, 8), true),
(mii(8, 12), false),
]),
);
}
fn assert_cut<const N: usize, const Y: usize, Q, I, K, V>(
mut before: RangeBoundsMap<I, K, V>,
to_cut: Q,
result: Result<[((Bound<I>, Bound<I>), V); Y], TryFromBoundsError>,
after: Option<[(K, V); N]>,
) where
I: Ord + Debug + Copy,
K: NiceRange<I> + TryFromBounds<I> + PartialEq + Debug,
Q: NiceRange<I>,
V: PartialEq + Debug + Clone,
{
let clone = before.clone();
match before.cut(to_cut) {
Ok(iter) => {
assert_eq!(iter.collect::<Vec<_>>(), result.unwrap());
}
Err(x) => {
assert_eq!(x, result.unwrap_err());
}
}
match after {
Some(after) => {
assert_eq!(
before,
RangeBoundsMap::from_slice_strict(after).unwrap()
)
}
None => assert_eq!(before, clone),
}
}
#[test]
fn gaps_tests() {
assert_gaps(basic(), ii(50, 60), [ii(50, 60)]);
assert_gaps(basic(), iu(50), [iu(50)]);
assert_gaps(basic(), ee(3, 16), [ei(4, 5), ee(7, 14)]);
assert_gaps(basic(), ei(3, 16), [ei(4, 5), ee(7, 14), ii(16, 16)]);
assert_gaps(basic(), ue(5), [ee(4, 5)]);
assert_gaps(basic(), ui(3), []);
assert_gaps(basic(), ii(5, 5), [ii(5, 5)]);
assert_gaps(basic(), ii(6, 6), []);
assert_gaps(basic(), ii(7, 7), []);
assert_gaps(basic(), ii(8, 8), [ii(8, 8)]);
}
fn assert_gaps<const N: usize>(
map: RangeBoundsMap<i8, AnyRange, bool>,
outer_range: AnyRange,
result: [AnyRange; N],
) {
assert_eq!(
map.gaps(outer_range)
.map(|(start, end)| (start, end))
.collect::<Vec<_>>(),
result
);
}
#[test]
fn insert_merge_touching_tests() {
assert_insert_merge_touching(
basic(),
(ii(0, 4), false),
Err(OverlapOrTryFromBoundsError::Overlap(OverlapError)),
None::<[_; 0]>,
);
assert_insert_merge_touching(
basic(),
(ee(7, 10), false),
Ok(ie(7, 10)),
Some([
(ui(4), false),
(ee(5, 7), true),
(ie(7, 10), false),
(ie(14, 16), true),
]),
);
assert_insert_merge_touching(
basic(),
(ee(7, 11), true),
Ok(ie(7, 11)),
Some([
(ui(4), false),
(ee(5, 7), true),
(ie(7, 11), true),
(ie(14, 16), true),
]),
);
assert_insert_merge_touching(
basic(),
(ee(12, 13), true),
Ok(ee(12, 13)),
Some([
(ui(4), false),
(ee(5, 7), true),
(ii(7, 7), false),
(ee(12, 13), true),
(ie(14, 16), true),
]),
);
assert_insert_merge_touching(
basic(),
(ee(13, 14), false),
Ok(ee(13, 16)),
Some([
(ui(4), false),
(ee(5, 7), true),
(ii(7, 7), false),
(ee(13, 16), false),
]),
);
assert_insert_merge_touching(
basic(),
(ee(7, 14), false),
Ok(ie(7, 16)),
Some([(ui(4), false), (ee(5, 7), true), (ie(7, 16), false)]),
);
assert_insert_merge_touching(
special(),
(mee(6, 7), true),
Err(OverlapOrTryFromBoundsError::TryFromBounds(
TryFromBoundsError,
)),
None::<[_; 0]>,
);
assert_insert_merge_touching(
special(),
(mii(6, 7), true),
Err(OverlapOrTryFromBoundsError::Overlap(OverlapError)),
None::<[_; 0]>,
);
assert_insert_merge_touching(
special(),
(mee(12, 15), true),
Err(OverlapOrTryFromBoundsError::TryFromBounds(
TryFromBoundsError,
)),
None::<[_; 0]>,
);
assert_insert_merge_touching(
special(),
(mii(12, 15), true),
Err(OverlapOrTryFromBoundsError::Overlap(OverlapError)),
None::<[_; 0]>,
);
}
fn assert_insert_merge_touching<const N: usize, I, K, V>(
mut before: RangeBoundsMap<I, K, V>,
to_insert: (K, V),
result: Result<K, OverlapOrTryFromBoundsError>,
after: Option<[(K, V); N]>,
) where
I: Ord + Debug + Copy,
K: NiceRange<I> + TryFromBounds<I> + PartialEq + Debug,
V: PartialEq + Debug + Clone,
{
let clone = before.clone();
assert_eq!(
before.insert_merge_touching(to_insert.0, to_insert.1),
result
);
match after {
Some(after) => {
assert_eq!(
before,
RangeBoundsMap::from_slice_strict(after).unwrap()
)
}
None => assert_eq!(before, clone),
}
}
#[test]
fn insert_merge_touching_if_values_equal_tests() {
assert_insert_merge_touching_if_values_equal(
basic(),
(ii(0, 4), false),
Err(OverlapOrTryFromBoundsError::Overlap(OverlapError)),
None::<[_; 0]>,
);
assert_insert_merge_touching_if_values_equal(
basic(),
(ee(7, 10), false),
Ok(ie(7, 10)),
Some([
(ui(4), false),
(ee(5, 7), true),
(ie(7, 10), false),
(ie(14, 16), true),
]),
);
assert_insert_merge_touching_if_values_equal(
basic(),
(ee(7, 11), true),
Ok(ee(7, 11)),
Some([
(ui(4), false),
(ee(5, 7), true),
(ii(7, 7), false),
(ee(7, 11), true),
(ie(14, 16), true),
]),
);
assert_insert_merge_touching_if_values_equal(
basic(),
(ee(12, 13), true),
Ok(ee(12, 13)),
Some([
(ui(4), false),
(ee(5, 7), true),
(ii(7, 7), false),
(ee(12, 13), true),
(ie(14, 16), true),
]),
);
assert_insert_merge_touching_if_values_equal(
basic(),
(ee(13, 14), true),
Ok(ee(13, 16)),
Some([
(ui(4), false),
(ee(5, 7), true),
(ii(7, 7), false),
(ee(13, 16), true),
]),
);
assert_insert_merge_touching_if_values_equal(
basic(),
(ee(7, 14), false),
Ok(ie(7, 14)),
Some([
(ui(4), false),
(ee(5, 7), true),
(ie(7, 14), false),
(ie(14, 16), true),
]),
);
assert_insert_merge_touching_if_values_equal(
special(),
(mee(6, 7), true),
Ok(mee(6, 7)),
Some([
(mii(4, 6), false),
(mee(6, 7), true),
(mee(7, 8), true),
(mii(8, 12), false),
]),
);
assert_insert_merge_touching_if_values_equal(
special(),
(mii(6, 7), true),
Err(OverlapOrTryFromBoundsError::Overlap(OverlapError)),
None::<[_; 0]>,
);
assert_insert_merge_touching_if_values_equal(
special(),
(mee(12, 15), false),
Err(OverlapOrTryFromBoundsError::TryFromBounds(
TryFromBoundsError,
)),
None::<[_; 0]>,
);
assert_insert_merge_touching_if_values_equal(
special(),
(mii(12, 15), true),
Err(OverlapOrTryFromBoundsError::Overlap(OverlapError)),
None::<[_; 0]>,
);
}
fn assert_insert_merge_touching_if_values_equal<const N: usize, I, K, V>(
mut before: RangeBoundsMap<I, K, V>,
to_insert: (K, V),
result: Result<K, OverlapOrTryFromBoundsError>,
after: Option<[(K, V); N]>,
) where
I: Ord + Debug + Copy,
K: NiceRange<I> + TryFromBounds<I> + PartialEq + Debug,
V: Eq + Debug + Clone,
{
let clone = before.clone();
assert_eq!(
before.insert_merge_touching_if_values_equal(
to_insert.0,
to_insert.1
),
result
);
match after {
Some(after) => {
assert_eq!(
before,
RangeBoundsMap::from_slice_strict(after).unwrap()
)
}
None => assert_eq!(before, clone),
}
}
#[test]
fn insert_merge_overlapping_tests() {
assert_insert_merge_overlapping(
basic(),
(ii(0, 2), true),
Ok(ui(4)),
Some([
(ui(4), true),
(ee(5, 7), true),
(ii(7, 7), false),
(ie(14, 16), true),
]),
);
assert_insert_merge_overlapping(
basic(),
(ie(14, 16), false),
Ok(ie(14, 16)),
Some([
(ui(4), false),
(ee(5, 7), true),
(ii(7, 7), false),
(ie(14, 16), false),
]),
);
assert_insert_merge_overlapping(
basic(),
(ii(6, 11), false),
Ok(ei(5, 11)),
Some([(ui(4), false), (ei(5, 11), false), (ie(14, 16), true)]),
);
assert_insert_merge_overlapping(
basic(),
(ii(15, 18), true),
Ok(ii(14, 18)),
Some([
(ui(4), false),
(ee(5, 7), true),
(ii(7, 7), false),
(ii(14, 18), true),
]),
);
assert_insert_merge_overlapping(
basic(),
(uu(), false),
Ok(uu()),
Some([(uu(), false)]),
);
assert_insert_merge_overlapping(
special(),
(mii(10, 18), true),
Ok(mii(8, 18)),
Some([(mii(4, 6), false), (mee(7, 8), true), (mii(8, 18), true)]),
);
assert_insert_merge_overlapping(
special(),
(mee(10, 18), true),
Err(TryFromBoundsError),
None::<[_; 0]>,
);
assert_insert_merge_overlapping(
special(),
(mee(8, 12), true),
Ok(mii(8, 12)),
Some([(mii(4, 6), false), (mee(7, 8), true), (mii(8, 12), true)]),
);
assert_insert_merge_overlapping(
special(),
(mee(7, 8), false),
Ok(mee(7, 8)),
Some([(mii(4, 6), false), (mee(7, 8), false), (mii(8, 12), false)]),
);
assert_insert_merge_overlapping(
special(),
(mii(7, 8), false),
Ok(mii(7, 12)),
Some([(mii(4, 6), false), (mii(7, 12), false)]),
);
}
fn assert_insert_merge_overlapping<const N: usize, I, K, V>(
mut before: RangeBoundsMap<I, K, V>,
to_insert: (K, V),
result: Result<K, TryFromBoundsError>,
after: Option<[(K, V); N]>,
) where
I: Ord + Debug + Copy,
K: NiceRange<I> + TryFromBounds<I> + PartialEq + Debug,
V: PartialEq + Debug + Clone,
{
let clone = before.clone();
assert_eq!(
before.insert_merge_overlapping(to_insert.0, to_insert.1),
result
);
match after {
Some(after) => {
assert_eq!(
before,
RangeBoundsMap::from_slice_strict(after).unwrap()
)
}
None => assert_eq!(before, clone),
}
}
#[test]
fn insert_merge_touching_or_overlapping_tests() {
assert_insert_merge_touching_or_overlapping(
RangeBoundsMap::from_slice_strict([(ie(1, 4), false)]).unwrap(),
(ie(0, 1), true),
Ok(ie(0, 4)),
Some([(ie(0, 4), true)]),
);
assert_insert_merge_touching_or_overlapping(
basic(),
(ii(0, 2), true),
Ok(ui(4)),
Some([
(ui(4), true),
(ee(5, 7), true),
(ii(7, 7), false),
(ie(14, 16), true),
]),
);
assert_insert_merge_touching_or_overlapping(
basic(),
(ie(14, 16), false),
Ok(ie(14, 16)),
Some([
(ui(4), false),
(ee(5, 7), true),
(ii(7, 7), false),
(ie(14, 16), false),
]),
);
assert_insert_merge_touching_or_overlapping(
basic(),
(ii(6, 11), false),
Ok(ei(5, 11)),
Some([(ui(4), false), (ei(5, 11), false), (ie(14, 16), true)]),
);
assert_insert_merge_touching_or_overlapping(
basic(),
(ii(15, 18), true),
Ok(ii(14, 18)),
Some([
(ui(4), false),
(ee(5, 7), true),
(ii(7, 7), false),
(ii(14, 18), true),
]),
);
assert_insert_merge_touching_or_overlapping(
basic(),
(uu(), false),
Ok(uu()),
Some([(uu(), false)]),
);
assert_insert_merge_touching_or_overlapping(
basic(),
(ii(7, 14), false),
Ok(ee(5, 16)),
Some([(ui(4), false), (ee(5, 16), false)]),
);
assert_insert_merge_touching_or_overlapping(
special(),
(mii(10, 18), true),
Ok(mii(8, 18)),
Some([(mii(4, 6), false), (mee(7, 8), true), (mii(8, 18), true)]),
);
assert_insert_merge_touching_or_overlapping(
special(),
(mee(10, 18), true),
Err(TryFromBoundsError),
None::<[_; 0]>,
);
assert_insert_merge_touching_or_overlapping(
special(),
(mee(8, 12), true),
Ok(mii(8, 12)),
Some([(mii(4, 6), false), (mee(7, 8), true), (mii(8, 12), true)]),
);
assert_insert_merge_touching_or_overlapping(
special(),
(mee(7, 8), false),
Err(TryFromBoundsError),
None::<[_; 0]>,
);
assert_insert_merge_touching_or_overlapping(
special(),
(mii(7, 8), false),
Ok(mii(7, 12)),
Some([(mii(4, 6), false), (mii(7, 12), false)]),
);
assert_insert_merge_touching_or_overlapping(
special(),
(mee(6, 7), true),
Err(TryFromBoundsError),
None::<[_; 0]>,
);
assert_insert_merge_touching_or_overlapping(
special(),
(mee(12, 15), true),
Err(TryFromBoundsError),
None::<[_; 0]>,
);
}
fn assert_insert_merge_touching_or_overlapping<const N: usize, I, K, V>(
mut before: RangeBoundsMap<I, K, V>,
to_insert: (K, V),
result: Result<K, TryFromBoundsError>,
after: Option<[(K, V); N]>,
) where
I: Ord + Debug + Copy,
K: NiceRange<I> + TryFromBounds<I> + PartialEq + Debug,
V: PartialEq + Debug + Clone,
{
let clone = before.clone();
assert_eq!(
before
.insert_merge_touching_or_overlapping(to_insert.0, to_insert.1),
result
);
match after {
Some(after) => {
assert_eq!(
before,
RangeBoundsMap::from_slice_strict(after).unwrap()
)
}
None => assert_eq!(before, clone),
}
}
#[test]
fn config_tests() {
assert_eq!(config(ie(1, 4), ie(6, 8)), Config::LeftFirstNonOverlapping);
assert_eq!(config(ie(1, 4), ie(2, 8)), Config::LeftFirstPartialOverlap);
assert_eq!(config(ie(1, 4), ie(2, 3)), Config::LeftContainsRight);
assert_eq!(
config(ie(6, 8), ie(1, 4)),
Config::RightFirstNonOverlapping
);
assert_eq!(
config(ie(2, 8), ie(1, 4)),
Config::RightFirstPartialOverlap
);
assert_eq!(config(ie(2, 3), ie(1, 4)), Config::RightContainsLeft);
}
#[test]
fn overlaps_tests() {
for range1 in all_valid_test_bounds() {
for range2 in all_valid_test_bounds() {
let our_answer = overlaps(range1, range2);
let mathematical_definition_of_overlap = NUMBERS_DOMAIN
.iter()
.any(|x| range1.contains(x) && range2.contains(x));
if our_answer != mathematical_definition_of_overlap {
dbg!(range1, range2);
dbg!(mathematical_definition_of_overlap, our_answer);
panic!("Discrepency in overlaps() detected!");
}
}
}
}
#[test]
fn cut_range_tests() {
for base in all_valid_test_bounds() {
for cut in all_valid_test_bounds() {
let cut_result @ CutResult {
before_cut: b,
inside_cut: i,
after_cut: a,
} = cut_range(base, cut);
let mut on_left = true;
for x in NUMBERS_DOMAIN {
let base_contains = base.contains(x);
let cut_contains = cut.contains(x);
if cut_contains {
on_left = false;
}
let invariant = match (base_contains, cut_contains) {
(false, _) => !con(b, x) && !con(i, x) && !con(a, x),
(true, false) => {
if on_left {
con(b, x) && !con(i, x) && !con(a, x)
} else {
!con(b, x) && !con(i, x) && con(a, x)
}
}
(true, true) => !con(b, x) && con(i, x) && !con(a, x),
};
if !invariant {
dbg!(base_contains);
dbg!(cut_contains);
dbg!(on_left);
dbg!(base);
dbg!(cut);
dbg!(cut_result);
dbg!(x);
panic!("Invariant Broken!");
}
}
}
}
}
fn con(x: Option<(Bound<i8>, Bound<i8>)>, point: &i8) -> bool {
match x {
Some(y) => y.contains(point),
None => false,
}
}
#[test]
fn cut_range_bounds_should_return_valid_ranges() {
let result: CutResult<i8> = cut_range(ie(3, 8), ie(5, 8));
if let Some(x) = result.before_cut {
assert!(is_valid_range(x));
}
if let Some(x) = result.inside_cut {
assert!(is_valid_range(x));
}
if let Some(x) = result.after_cut {
assert!(is_valid_range(x));
}
let result = cut_range(ie(3, 8), ie(3, 5));
if let Some(x) = result.before_cut {
assert!(is_valid_range(x));
}
if let Some(x) = result.inside_cut {
assert!(is_valid_range(x));
}
if let Some(x) = result.after_cut {
assert!(is_valid_range(x));
}
}
fn all_non_overlapping_test_bound_entries() -> Vec<(AnyRange, AnyRange)> {
let mut output = Vec::new();
for test_bounds1 in all_valid_test_bounds() {
for test_bounds2 in all_valid_test_bounds() {
if !overlaps(test_bounds1, test_bounds2) {
output.push((test_bounds1, test_bounds2));
}
}
}
return output;
}
fn all_valid_test_bounds() -> Vec<AnyRange> {
let mut output = Vec::new();
output.append(&mut all_finite_bounded_entries());
for start_bound in all_finite_bounded() {
output.push((start_bound, u()));
}
for end_bound in all_finite_bounded() {
output.push((u(), end_bound));
}
output.push(uu());
return output;
}
fn all_finite_bounded_entries() -> Vec<(Bound<i8>, Bound<i8>)> {
let mut output = Vec::new();
for i in NUMBERS {
for j in NUMBERS {
for i_ex in [false, true] {
for j_ex in [false, true] {
if j > i || (j == i && !i_ex && !j_ex) {
output.push((
finite_bound(*i, i_ex),
finite_bound(*j, j_ex),
));
}
}
}
}
}
return output;
}
fn all_finite_bounded() -> Vec<Bound<i8>> {
let mut output = Vec::new();
for i in NUMBERS {
for j in 0..=1 {
output.push(finite_bound(*i, j == 1));
}
}
return output;
}
fn finite_bound(x: i8, included: bool) -> Bound<i8> {
match included {
false => Bound::Included(x),
true => Bound::Excluded(x),
}
}
}