made IncludedInterval helper methods apart of the trait to make them more flexible and fixed doctests

This commit is contained in:
ripytide
2023-06-18 09:02:55 +01:00
parent bae726a324
commit eb7f93fa61
7 changed files with 210 additions and 172 deletions
Generated
+1 -1
View File
@@ -36,7 +36,7 @@ checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
[[package]] [[package]]
name = "discrete_range_map" name = "discrete_range_map"
version = "0.4.2" version = "0.4.3"
dependencies = [ dependencies = [
"btree_monstrousity", "btree_monstrousity",
"either", "either",
+99 -69
View File
@@ -21,6 +21,7 @@ use std::cmp::Ordering;
use std::fmt::{self, Debug}; use std::fmt::{self, Debug};
use std::iter::once; use std::iter::once;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::ops::RangeBounds;
use btree_monstrousity::btree_map::{ use btree_monstrousity::btree_map::{
IntoIter as BTreeMapIntoIter, SearchBoundCustom, IntoIter as BTreeMapIntoIter, SearchBoundCustom,
@@ -33,7 +34,7 @@ use serde::ser::SerializeSeq;
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::discrete_finite::DiscreteFinite; use crate::discrete_finite::DiscreteFinite;
use crate::interval::Interval; use crate::interval::InclusiveInterval;
use crate::utils::{cmp_point_with_range, cut_range, is_valid_range, overlaps}; use crate::utils::{cmp_point_with_range, cut_range, is_valid_range, overlaps};
/// An ordered map of non-overlapping ranges based on [`BTreeMap`]. /// An ordered map of non-overlapping ranges based on [`BTreeMap`].
@@ -90,7 +91,7 @@ pub struct OverlapError;
impl<I, K, V> DiscreteRangeMap<I, K, V> impl<I, K, V> DiscreteRangeMap<I, K, V>
where where
I: Ord + Copy + DiscreteFinite, I: Ord + Copy + DiscreteFinite,
K: FiniteRange<I> + Copy + From<Interval<I>>, K: InclusiveRange<I> + Copy + From<InclusiveInterval<I>>,
{ {
/// Returns `true` if the given range overlaps any of the /// Returns `true` if the given range overlaps any of the
/// other ranges in the map, and `false` if not. /// other ranges in the map, and `false` if not.
@@ -118,7 +119,7 @@ where
/// ``` /// ```
pub fn overlaps<Q>(&self, range: Q) -> bool pub fn overlaps<Q>(&self, range: Q) -> bool
where where
Q: FiniteRange<I> + Copy, Q: InclusiveRange<I> + Copy,
{ {
invalid_range_panic(range); invalid_range_panic(range);
@@ -158,7 +159,7 @@ where
range: Q, range: Q,
) -> impl DoubleEndedIterator<Item = (&K, &V)> ) -> impl DoubleEndedIterator<Item = (&K, &V)>
where where
Q: FiniteRange<I> + Copy, Q: InclusiveRange<I> + Copy,
{ {
invalid_range_panic(range); invalid_range_panic(range);
@@ -206,7 +207,7 @@ where
range: Q, range: Q,
) -> impl DoubleEndedIterator<Item = (&K, &mut V)> ) -> impl DoubleEndedIterator<Item = (&K, &mut V)>
where where
Q: FiniteRange<I> + Copy, Q: InclusiveRange<I> + Copy,
{ {
invalid_range_panic(range); invalid_range_panic(range);
@@ -315,7 +316,7 @@ where
.get_key_value(overlapping_comp(point)) .get_key_value(overlapping_comp(point))
.ok_or_else(|| K::from(self.get_gap_at_raw(point))) .ok_or_else(|| K::from(self.get_gap_at_raw(point)))
} }
fn get_gap_at_raw(&self, point: I) -> Interval<I> { fn get_gap_at_raw(&self, point: I) -> InclusiveInterval<I> {
let lower = self let lower = self
.inner .inner
.upper_bound(overlapping_comp(point), SearchBoundCustom::Included); .upper_bound(overlapping_comp(point), SearchBoundCustom::Included);
@@ -323,7 +324,7 @@ where
.inner .inner
.lower_bound(overlapping_comp(point), SearchBoundCustom::Included); .lower_bound(overlapping_comp(point), SearchBoundCustom::Included);
Interval { InclusiveInterval {
start: lower start: lower
.key() .key()
.map_or(I::MIN, |lower| lower.end().up().unwrap()), .map_or(I::MIN, |lower| lower.end().up().unwrap()),
@@ -371,7 +372,7 @@ where
range: Q, range: Q,
) -> impl Iterator<Item = (K, V)> + '_ ) -> impl Iterator<Item = (K, V)> + '_
where where
Q: FiniteRange<I> + Copy + 'a, Q: InclusiveRange<I> + Copy + 'a,
{ {
invalid_range_panic(range); invalid_range_panic(range);
@@ -435,7 +436,7 @@ where
range: Q, range: Q,
) -> impl Iterator<Item = (K, V)> + '_ ) -> impl Iterator<Item = (K, V)> + '_
where where
Q: FiniteRange<I> + Copy + 'a, Q: InclusiveRange<I> + Copy + 'a,
V: Clone, V: Clone,
{ {
invalid_range_panic(range); invalid_range_panic(range);
@@ -466,7 +467,7 @@ where
single_overlapping_range: K, single_overlapping_range: K,
) -> impl Iterator<Item = (K, V)> ) -> impl Iterator<Item = (K, V)>
where where
Q: FiniteRange<I> + Copy, Q: InclusiveRange<I> + Copy,
V: Clone, V: Clone,
{ {
invalid_range_panic(range); invalid_range_panic(range);
@@ -494,7 +495,7 @@ where
right_overlapping: Option<K>, right_overlapping: Option<K>,
) -> impl Iterator<Item = (K, V)> + '_ ) -> impl Iterator<Item = (K, V)> + '_
where where
Q: FiniteRange<I> + Copy + 'a, Q: InclusiveRange<I> + Copy + 'a,
V: Clone, V: Clone,
{ {
invalid_range_panic(range); invalid_range_panic(range);
@@ -547,7 +548,7 @@ where
.into_iter() .into_iter()
.chain(self.remove_overlapping(range).map(|(key, value)| { .chain(self.remove_overlapping(range).map(|(key, value)| {
( (
K::from(Interval { K::from(InclusiveInterval {
start: key.start(), start: key.start(),
end: key.end(), end: key.end(),
}), }),
@@ -587,7 +588,7 @@ where
/// ``` /// ```
pub fn gaps<'a, Q>(&'a self, outer_range: Q) -> impl Iterator<Item = K> + '_ pub fn gaps<'a, Q>(&'a self, outer_range: Q) -> impl Iterator<Item = K> + '_
where where
Q: FiniteRange<I> + Copy + 'a, Q: InclusiveRange<I> + Copy + 'a,
{ {
invalid_range_panic(outer_range); invalid_range_panic(outer_range);
@@ -636,7 +637,7 @@ where
let inner_gaps = overlapping let inner_gaps = overlapping
.tuple_windows() .tuple_windows()
.map(|(first, second)| { .map(|(first, second)| {
K::from(Interval { K::from(InclusiveInterval {
start: first.1.up().unwrap(), start: first.1.up().unwrap(),
end: second.0.down().unwrap(), end: second.0.down().unwrap(),
}) })
@@ -678,7 +679,7 @@ where
/// ``` /// ```
pub fn contains_range<Q>(&self, range: Q) -> bool pub fn contains_range<Q>(&self, range: Q) -> bool
where where
Q: FiniteRange<I> + Copy, Q: InclusiveRange<I> + Copy,
{ {
invalid_range_panic(range); invalid_range_panic(range);
@@ -749,15 +750,17 @@ where
let matching_end = get_end(self, &value); let matching_end = get_end(self, &value);
let returning = match (matching_start, matching_end) { let returning = match (matching_start, matching_end) {
(Some(matching_start), Some(matching_end)) => K::from(Interval { (Some(matching_start), Some(matching_end)) => {
start: matching_start.start(), K::from(InclusiveInterval {
end: matching_end.end(), start: matching_start.start(),
}), end: matching_end.end(),
(Some(matching_start), None) => K::from(Interval { })
}
(Some(matching_start), None) => K::from(InclusiveInterval {
start: matching_start.start(), start: matching_start.start(),
end: range.end(), end: range.end(),
}), }),
(None, Some(matching_end)) => K::from(Interval { (None, Some(matching_end)) => K::from(InclusiveInterval {
start: range.start(), start: range.start(),
end: matching_end.end(), end: matching_end.end(),
}), }),
@@ -1210,9 +1213,9 @@ impl<I, K, V> DiscreteRangeMap<I, K, V> {
/// ///
/// # Examples /// # Examples
/// ``` /// ```
/// use discrete_range_map::{DiscreteRangeMap, Interval}; /// use discrete_range_map::{DiscreteRangeMap, InclusiveInterval};
/// ///
/// let map: DiscreteRangeMap<i8, Interval<i8>, bool> = /// let map: DiscreteRangeMap<i8, InclusiveInterval<i8>, bool> =
/// DiscreteRangeMap::new(); /// DiscreteRangeMap::new();
/// ``` /// ```
pub fn new() -> Self { pub fn new() -> Self {
@@ -1359,7 +1362,7 @@ impl<I, K, V> DiscreteRangeMap<I, K, V> {
fn invalid_range_panic<Q, I>(range: Q) fn invalid_range_panic<Q, I>(range: Q)
where where
Q: FiniteRange<I>, Q: InclusiveRange<I>,
I: Ord, I: Ord,
{ {
if !is_valid_range(range) { if !is_valid_range(range) {
@@ -1371,7 +1374,7 @@ where
fn double_comp<K, I>() -> impl FnMut(&K, &K) -> Ordering fn double_comp<K, I>() -> impl FnMut(&K, &K) -> Ordering
where where
K: FiniteRange<I>, K: InclusiveRange<I>,
I: Ord + DiscreteFinite, I: Ord + DiscreteFinite,
{ {
|inner_range: &K, new_range: &K| new_range.start().cmp(&inner_range.start()) |inner_range: &K, new_range: &K| new_range.start().cmp(&inner_range.start())
@@ -1379,14 +1382,14 @@ where
fn overlapping_comp<I, K>(point: I) -> impl FnMut(&K) -> Ordering fn overlapping_comp<I, K>(point: I) -> impl FnMut(&K) -> Ordering
where where
I: Ord + Copy, I: Ord + Copy,
K: FiniteRange<I> + Copy, K: InclusiveRange<I> + Copy,
{ {
move |inner_range: &K| cmp_point_with_range(point, *inner_range) move |inner_range: &K| cmp_point_with_range(point, *inner_range)
} }
fn touching_start_comp<I, K>(start: I) -> impl FnMut(&K) -> Ordering fn touching_start_comp<I, K>(start: I) -> impl FnMut(&K) -> Ordering
where where
I: Ord + Copy + DiscreteFinite, I: Ord + Copy + DiscreteFinite,
K: FiniteRange<I>, K: InclusiveRange<I>,
{ {
move |inner_range: &K| match inner_range.end().up() { move |inner_range: &K| match inner_range.end().up() {
Some(touching_position) => start.cmp(&touching_position), Some(touching_position) => start.cmp(&touching_position),
@@ -1396,7 +1399,7 @@ where
fn touching_end_comp<I, K>(end: I) -> impl FnMut(&K) -> Ordering fn touching_end_comp<I, K>(end: I) -> impl FnMut(&K) -> Ordering
where where
I: Ord + Copy + DiscreteFinite, I: Ord + Copy + DiscreteFinite,
K: FiniteRange<I>, K: InclusiveRange<I>,
{ {
move |inner_range: &K| match inner_range.start().down() { move |inner_range: &K| match inner_range.start().down() {
Some(touching_position) => end.cmp(&touching_position), Some(touching_position) => end.cmp(&touching_position),
@@ -1404,10 +1407,37 @@ where
} }
} }
/// A range that has Finite **Inclusive** end-points. /// A range that has **Inclusive** end-points.
pub trait FiniteRange<I> { pub trait InclusiveRange<I>: RangeBounds<I> {
fn start(&self) -> I; fn start(&self) -> I;
fn end(&self) -> I; fn end(&self) -> I;
///requires that self comes before other and they don't overlap
fn touches_ordered(&self, other: &Self) -> bool
where
I: DiscreteFinite + Ord,
{
self.end() == other.start().down().unwrap()
}
///requires that self comes before other
fn overlaps_ordered(&self, other: &Self) -> bool
where
I: DiscreteFinite + Ord,
{
self.contains(&other.start()) || self.contains(&other.end())
}
///requires that self comes before other
fn merge_ordered(&self, other: &Self) -> Self
where
Self: From<InclusiveInterval<I>>,
{
Self::from(InclusiveInterval {
start: self.start(),
end: other.end(),
})
}
} }
// Trait Impls ========================== // Trait Impls ==========================
@@ -1470,7 +1500,7 @@ where
impl<'de, I, K, V> Deserialize<'de> for DiscreteRangeMap<I, K, V> impl<'de, I, K, V> Deserialize<'de> for DiscreteRangeMap<I, K, V>
where where
I: Ord + Copy + DiscreteFinite, I: Ord + Copy + DiscreteFinite,
K: FiniteRange<I> + Copy + From<Interval<I>> + Deserialize<'de>, K: InclusiveRange<I> + Copy + From<InclusiveInterval<I>> + Deserialize<'de>,
V: Deserialize<'de>, V: Deserialize<'de>,
{ {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
@@ -1494,7 +1524,7 @@ struct DiscreteRangeMapVisitor<I, K, V> {
impl<'de, I, K, V> Visitor<'de> for DiscreteRangeMapVisitor<I, K, V> impl<'de, I, K, V> Visitor<'de> for DiscreteRangeMapVisitor<I, K, V>
where where
I: Ord + Copy + DiscreteFinite, I: Ord + Copy + DiscreteFinite,
K: FiniteRange<I> + Copy + From<Interval<I>> + Deserialize<'de>, K: InclusiveRange<I> + Copy + From<InclusiveInterval<I>> + Deserialize<'de>,
V: Deserialize<'de>, V: Deserialize<'de>,
{ {
type Value = DiscreteRangeMap<I, K, V>; type Value = DiscreteRangeMap<I, K, V>;
@@ -1531,7 +1561,7 @@ mod tests {
pub(crate) const NUMBERS_DOMAIN: &'static [i8] = pub(crate) const NUMBERS_DOMAIN: &'static [i8] =
&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
fn basic() -> DiscreteRangeMap<i8, Interval<i8>, bool> { fn basic() -> DiscreteRangeMap<i8, InclusiveInterval<i8>, bool> {
DiscreteRangeMap::from_slice_strict([ DiscreteRangeMap::from_slice_strict([
(ui(4), false), (ui(4), false),
(ee(5, 7), true), (ee(5, 7), true),
@@ -1540,7 +1570,7 @@ mod tests {
]) ])
.unwrap() .unwrap()
} }
fn basic_slice() -> [(Interval<i8>, bool); 4] { fn basic_slice() -> [(InclusiveInterval<i8>, bool); 4] {
[ [
(ui(4), false), (ui(4), false),
(ee(5, 7), true), (ee(5, 7), true),
@@ -1583,10 +1613,10 @@ mod tests {
); );
} }
fn assert_insert_strict<const N: usize>( fn assert_insert_strict<const N: usize>(
mut before: DiscreteRangeMap<i8, Interval<i8>, bool>, mut before: DiscreteRangeMap<i8, InclusiveInterval<i8>, bool>,
to_insert: (Interval<i8>, bool), to_insert: (InclusiveInterval<i8>, bool),
result: Result<(), OverlapError>, result: Result<(), OverlapError>,
after: [(Interval<i8>, bool); N], after: [(InclusiveInterval<i8>, bool); N],
) { ) {
assert_eq!(before.insert_strict(to_insert.0, to_insert.1), result); assert_eq!(before.insert_strict(to_insert.0, to_insert.1), result);
assert_eq!(before, DiscreteRangeMap::from_slice_strict(after).unwrap()) assert_eq!(before, DiscreteRangeMap::from_slice_strict(after).unwrap())
@@ -1598,7 +1628,7 @@ mod tests {
for overlap_range in all_valid_test_bounds() { for overlap_range in all_valid_test_bounds() {
//you can't overlap nothing //you can't overlap nothing
assert!( assert!(
DiscreteRangeMap::<i8, Interval<i8>, ()>::new() DiscreteRangeMap::<i8, InclusiveInterval<i8>, ()>::new()
.overlapping(overlap_range) .overlapping(overlap_range)
.next() .next()
.is_none() .is_none()
@@ -1702,10 +1732,10 @@ mod tests {
); );
} }
fn assert_remove_overlapping<const N: usize, const Y: usize>( fn assert_remove_overlapping<const N: usize, const Y: usize>(
mut before: DiscreteRangeMap<i8, Interval<i8>, bool>, mut before: DiscreteRangeMap<i8, InclusiveInterval<i8>, bool>,
to_remove: Interval<i8>, to_remove: InclusiveInterval<i8>,
result: [(Interval<i8>, bool); N], result: [(InclusiveInterval<i8>, bool); N],
after: [(Interval<i8>, bool); Y], after: [(InclusiveInterval<i8>, bool); Y],
) { ) {
assert_eq!( assert_eq!(
before.remove_overlapping(to_remove).collect::<Vec<_>>(), before.remove_overlapping(to_remove).collect::<Vec<_>>(),
@@ -1752,10 +1782,10 @@ mod tests {
); );
} }
fn assert_cut<const N: usize, const Y: usize>( fn assert_cut<const N: usize, const Y: usize>(
mut before: DiscreteRangeMap<i8, Interval<i8>, bool>, mut before: DiscreteRangeMap<i8, InclusiveInterval<i8>, bool>,
to_cut: Interval<i8>, to_cut: InclusiveInterval<i8>,
result: [(Interval<i8>, bool); Y], result: [(InclusiveInterval<i8>, bool); Y],
after: [(Interval<i8>, bool); N], after: [(InclusiveInterval<i8>, bool); N],
) { ) {
assert_eq!(before.cut(to_cut).collect::<Vec<_>>(), result); assert_eq!(before.cut(to_cut).collect::<Vec<_>>(), result);
assert_eq!(before, DiscreteRangeMap::from_slice_strict(after).unwrap()); assert_eq!(before, DiscreteRangeMap::from_slice_strict(after).unwrap());
@@ -1791,9 +1821,9 @@ mod tests {
); );
} }
fn assert_gaps<const N: usize>( fn assert_gaps<const N: usize>(
map: DiscreteRangeMap<i8, Interval<i8>, bool>, map: DiscreteRangeMap<i8, InclusiveInterval<i8>, bool>,
outer_range: Interval<i8>, outer_range: InclusiveInterval<i8>,
result: [Interval<i8>; N], result: [InclusiveInterval<i8>; N],
) { ) {
assert_eq!(map.gaps(outer_range).collect::<Vec<_>>(), result); assert_eq!(map.gaps(outer_range).collect::<Vec<_>>(), result);
} }
@@ -1841,10 +1871,10 @@ mod tests {
); );
} }
fn assert_insert_merge_touching<const N: usize>( fn assert_insert_merge_touching<const N: usize>(
mut before: DiscreteRangeMap<i8, Interval<i8>, bool>, mut before: DiscreteRangeMap<i8, InclusiveInterval<i8>, bool>,
to_insert: (Interval<i8>, bool), to_insert: (InclusiveInterval<i8>, bool),
result: Result<Interval<i8>, OverlapError>, result: Result<InclusiveInterval<i8>, OverlapError>,
after: [(Interval<i8>, bool); N], after: [(InclusiveInterval<i8>, bool); N],
) { ) {
assert_eq!( assert_eq!(
before.insert_merge_touching(to_insert.0, to_insert.1), before.insert_merge_touching(to_insert.0, to_insert.1),
@@ -1897,10 +1927,10 @@ mod tests {
); );
} }
fn assert_insert_merge_touching_if_values_equal<const N: usize>( fn assert_insert_merge_touching_if_values_equal<const N: usize>(
mut before: DiscreteRangeMap<i8, Interval<i8>, bool>, mut before: DiscreteRangeMap<i8, InclusiveInterval<i8>, bool>,
to_insert: (Interval<i8>, bool), to_insert: (InclusiveInterval<i8>, bool),
result: Result<Interval<i8>, OverlapError>, result: Result<InclusiveInterval<i8>, OverlapError>,
after: [(Interval<i8>, bool); N], after: [(InclusiveInterval<i8>, bool); N],
) { ) {
assert_eq!( assert_eq!(
before.insert_merge_touching_if_values_equal( before.insert_merge_touching_if_values_equal(
@@ -1961,10 +1991,10 @@ mod tests {
); );
} }
fn assert_insert_merge_overlapping<const N: usize>( fn assert_insert_merge_overlapping<const N: usize>(
mut before: DiscreteRangeMap<i8, Interval<i8>, bool>, mut before: DiscreteRangeMap<i8, InclusiveInterval<i8>, bool>,
to_insert: (Interval<i8>, bool), to_insert: (InclusiveInterval<i8>, bool),
result: Interval<i8>, result: InclusiveInterval<i8>,
after: [(Interval<i8>, bool); N], after: [(InclusiveInterval<i8>, bool); N],
) { ) {
assert_eq!( assert_eq!(
before.insert_merge_overlapping(to_insert.0, to_insert.1), before.insert_merge_overlapping(to_insert.0, to_insert.1),
@@ -2037,10 +2067,10 @@ mod tests {
); );
} }
fn assert_insert_merge_touching_or_overlapping<const N: usize>( fn assert_insert_merge_touching_or_overlapping<const N: usize>(
mut before: DiscreteRangeMap<i8, Interval<i8>, bool>, mut before: DiscreteRangeMap<i8, InclusiveInterval<i8>, bool>,
to_insert: (Interval<i8>, bool), to_insert: (InclusiveInterval<i8>, bool),
result: Interval<i8>, result: InclusiveInterval<i8>,
after: [(Interval<i8>, bool); N], after: [(InclusiveInterval<i8>, bool); N],
) { ) {
assert_eq!( assert_eq!(
before before
@@ -2138,7 +2168,7 @@ mod tests {
} }
} }
} }
fn con(x: Option<Interval<i8>>, point: &i8) -> bool { fn con(x: Option<InclusiveInterval<i8>>, point: &i8) -> bool {
match x { match x {
Some(y) => contains_point(y, *point), Some(y) => contains_point(y, *point),
None => false, None => false,
@@ -2172,7 +2202,7 @@ mod tests {
// Test Helper Functions // Test Helper Functions
//====================== //======================
fn all_non_overlapping_test_bound_entries() fn all_non_overlapping_test_bound_entries()
-> Vec<(Interval<i8>, Interval<i8>)> { -> Vec<(InclusiveInterval<i8>, InclusiveInterval<i8>)> {
let mut output = Vec::new(); let mut output = Vec::new();
for test_bounds1 in all_valid_test_bounds() { for test_bounds1 in all_valid_test_bounds() {
for test_bounds2 in all_valid_test_bounds() { for test_bounds2 in all_valid_test_bounds() {
@@ -2185,12 +2215,12 @@ mod tests {
return output; return output;
} }
fn all_valid_test_bounds() -> Vec<Interval<i8>> { fn all_valid_test_bounds() -> Vec<InclusiveInterval<i8>> {
let mut output = Vec::new(); let mut output = Vec::new();
for i in NUMBERS { for i in NUMBERS {
for j in NUMBERS { for j in NUMBERS {
if i <= j { if i <= j {
output.push(Interval { start: *i, end: *j }); output.push(InclusiveInterval { start: *i, end: *j });
} }
} }
} }
+11 -11
View File
@@ -7,9 +7,9 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::discrete_finite::DiscreteFinite; use crate::discrete_finite::DiscreteFinite;
use crate::discrete_range_map::{ use crate::discrete_range_map::{
FiniteRange, IntoIter as DiscreteRangeMapIntoIter, InclusiveRange, IntoIter as DiscreteRangeMapIntoIter,
}; };
use crate::interval::Interval; use crate::interval::InclusiveInterval;
use crate::{DiscreteRangeMap, OverlapError}; use crate::{DiscreteRangeMap, OverlapError};
/// An ordered set of non-overlapping ranges based on [`DiscreteRangeMap`]. /// An ordered set of non-overlapping ranges based on [`DiscreteRangeMap`].
@@ -31,12 +31,12 @@ pub struct DiscreteRangeSet<I, K> {
impl<I, K> DiscreteRangeSet<I, K> impl<I, K> DiscreteRangeSet<I, K>
where where
I: Ord + Copy + DiscreteFinite, I: Ord + Copy + DiscreteFinite,
K: FiniteRange<I> + Copy + From<Interval<I>>, K: InclusiveRange<I> + Copy + From<InclusiveInterval<I>>,
{ {
/// See [`DiscreteRangeMap::overlaps()`] for more details. /// See [`DiscreteRangeMap::overlaps()`] for more details.
pub fn overlaps<Q>(&self, range: Q) -> bool pub fn overlaps<Q>(&self, range: Q) -> bool
where where
Q: FiniteRange<I> + Copy, Q: InclusiveRange<I> + Copy,
{ {
self.inner.overlaps(range) self.inner.overlaps(range)
} }
@@ -46,7 +46,7 @@ where
range: Q, range: Q,
) -> impl DoubleEndedIterator<Item = &K> ) -> impl DoubleEndedIterator<Item = &K>
where where
Q: FiniteRange<I> + Copy, Q: InclusiveRange<I> + Copy,
{ {
self.inner.overlapping(range).map(first) self.inner.overlapping(range).map(first)
} }
@@ -64,28 +64,28 @@ where
range: Q, range: Q,
) -> impl Iterator<Item = K> + '_ ) -> impl Iterator<Item = K> + '_
where where
Q: FiniteRange<I> + Copy + 'a, Q: InclusiveRange<I> + Copy + 'a,
{ {
self.inner.remove_overlapping(range).map(first) self.inner.remove_overlapping(range).map(first)
} }
/// See [`DiscreteRangeMap::cut()`] for more details. /// See [`DiscreteRangeMap::cut()`] for more details.
pub fn cut<'a, Q>(&'a mut self, range: Q) -> impl Iterator<Item = K> + '_ pub fn cut<'a, Q>(&'a mut self, range: Q) -> impl Iterator<Item = K> + '_
where where
Q: FiniteRange<I> + Copy + 'a, Q: InclusiveRange<I> + Copy + 'a,
{ {
self.inner.cut(range).map(first) self.inner.cut(range).map(first)
} }
/// See [`DiscreteRangeMap::gaps()`] for more details. /// See [`DiscreteRangeMap::gaps()`] for more details.
pub fn gaps<'a, Q>(&'a self, range: Q) -> impl Iterator<Item = K> + '_ pub fn gaps<'a, Q>(&'a self, range: Q) -> impl Iterator<Item = K> + '_
where where
Q: FiniteRange<I> + Copy + 'a, Q: InclusiveRange<I> + Copy + 'a,
{ {
self.inner.gaps(range) self.inner.gaps(range)
} }
/// See [`DiscreteRangeMap::contains_range()`] for more details. /// See [`DiscreteRangeMap::contains_range()`] for more details.
pub fn contains_range<Q>(&self, range: Q) -> bool pub fn contains_range<Q>(&self, range: Q) -> bool
where where
Q: FiniteRange<I> + Copy, Q: InclusiveRange<I> + Copy,
{ {
self.inner.contains_range(range) self.inner.contains_range(range)
} }
@@ -218,7 +218,7 @@ where
impl<'de, I, K> Deserialize<'de> for DiscreteRangeSet<I, K> impl<'de, I, K> Deserialize<'de> for DiscreteRangeSet<I, K>
where where
I: Ord + Copy + DiscreteFinite, I: Ord + Copy + DiscreteFinite,
K: FiniteRange<I> + Copy + From<Interval<I>> + Deserialize<'de>, K: InclusiveRange<I> + Copy + From<InclusiveInterval<I>> + Deserialize<'de>,
{ {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
@@ -239,7 +239,7 @@ struct DiscreteRangeSetVisitor<I, K> {
impl<'de, I, K> Visitor<'de> for DiscreteRangeSetVisitor<I, K> impl<'de, I, K> Visitor<'de> for DiscreteRangeSetVisitor<I, K>
where where
I: Ord + Copy + DiscreteFinite, I: Ord + Copy + DiscreteFinite,
K: FiniteRange<I> + Copy + From<Interval<I>> + Deserialize<'de>, K: InclusiveRange<I> + Copy + From<InclusiveInterval<I>> + Deserialize<'de>,
{ {
type Value = DiscreteRangeSet<I, K>; type Value = DiscreteRangeSet<I, K>;
+16 -25
View File
@@ -17,44 +17,35 @@ You should have received a copy of the GNU Affero General Public License
along with discrete_range_map. If not, see <https://www.gnu.org/licenses/>. along with discrete_range_map. If not, see <https://www.gnu.org/licenses/>.
*/ */
use crate::discrete_range_map::FiniteRange; use std::ops::{Bound, RangeBounds};
use serde::{Deserialize, Serialize};
use crate::discrete_range_map::InclusiveRange;
use crate::DiscreteFinite; use crate::DiscreteFinite;
///both ends are always included #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct InclusiveInterval<I> {
pub struct Interval<I> {
pub start: I, pub start: I,
pub end: I, pub end: I,
} }
impl<I> Interval<I> impl<I> InclusiveInterval<I> where I: Ord + DiscreteFinite + Copy {}
impl<I> RangeBounds<I> for InclusiveInterval<I>
where where
I: Ord + DiscreteFinite + Copy, I: Copy,
{ {
pub fn contains(&self, point: I) -> bool { fn start_bound(&self) -> Bound<&I> {
point >= self.start && point <= self.end Bound::Included(&self.start)
} }
///requires that self comes before other and they don't overlap fn end_bound(&self) -> Bound<&I> {
pub fn touches_ordered(&self, other: &Self) -> bool { Bound::Included(&self.end)
self.end == other.start.down().unwrap()
}
///requires that self comes before other
pub fn overlaps_ordered(&self, other: &Self) -> bool {
self.contains(other.start) || self.contains(other.end)
}
///requires that self comes before other
pub fn merge_ordered(self, other: &Self) -> Self {
Interval {
start: self.start,
end: other.end,
}
} }
} }
impl<I> FiniteRange<I> for Interval<I> impl<I> InclusiveRange<I> for InclusiveInterval<I>
where where
I: Copy, I: Copy,
{ {
+35 -18
View File
@@ -46,21 +46,40 @@ along with discrete_range_map. If not, see <https://www.gnu.org/licenses/>.
//! ## Example using a custom range type //! ## Example using a custom range type
//! //!
//! ```rust //! ```rust
//! use std::ops::{Bound, RangeBounds};
//! use discrete_range_map::test_ranges::ie; //! use discrete_range_map::test_ranges::ie;
//! use discrete_range_map::{ //! use discrete_range_map::{
//! DiscreteFinite, DiscreteRangeMap, FiniteRange, Interval, //! DiscreteFinite, DiscreteRangeMap, InclusiveInterval,
//! InclusiveRange,
//! }; //! };
//! //!
//! #[derive(Debug, Copy, Clone)] //! #[derive(Debug, Copy, Clone)]
//! enum Reservation { //! enum Reservation {
//! // Start, End (Inclusive-Exclusive) //! // Start, End (Inclusive-Inclusive)
//! Finite(i8, i8), //! Finite(i8, i8),
//! // Start (Inclusive-Forever) //! // Start (Inclusive-Infinity)
//! Infinite(i8), //! Infinite(i8),
//! } //! }
//! //!
//! // First, we need to implement FiniteRange //! // First, we need to implement RangeBounds since its a super-trait
//! impl FiniteRange<i8> for Reservation { //! // of InclusiveRange
//! impl RangeBounds<i8> for Reservation {
//! fn start_bound(&self) -> Bound<&i8> {
//! match self {
//! Reservation::Finite(start, _) => Bound::Included(start),
//! Reservation::Infinite(start) => Bound::Included(start),
//! }
//! }
//! fn end_bound(&self) -> Bound<&i8> {
//! match self {
//! Reservation::Finite(_, end) => Bound::Included(end),
//! Reservation::Infinite(_) => Bound::Included(&i8::MAX),
//! }
//! }
//! }
//!
//! // First, we need to implement InclusiveRange
//! impl InclusiveRange<i8> for Reservation {
//! fn start(&self) -> i8 { //! fn start(&self) -> i8 {
//! match self { //! match self {
//! Reservation::Finite(start, _) => *start, //! Reservation::Finite(start, _) => *start,
@@ -69,23 +88,21 @@ along with discrete_range_map. If not, see <https://www.gnu.org/licenses/>.
//! } //! }
//! fn end(&self) -> i8 { //! fn end(&self) -> i8 {
//! match self { //! match self {
//! //the end is exclusive so we take off 1 with checking //! Reservation::Finite(_, end) => *end,
//! //for compile time error overflow detection
//! Reservation::Finite(_, end) => end.down().unwrap(),
//! Reservation::Infinite(_) => i8::MAX, //! Reservation::Infinite(_) => i8::MAX,
//! } //! }
//! } //! }
//! } //! }
//! //!
//! // Second, we need to implement From<Interval<i8>> //! // Second, we need to implement From<InclusiveInterval<i8>>
//! impl From<Interval<i8>> for Reservation { //! impl From<InclusiveInterval<i8>> for Reservation {
//! fn from(bounds: Interval<i8>) -> Self { //! fn from(value: InclusiveInterval<i8>) -> Self {
//! if bounds.end == i8::MAX { //! if value.end == i8::MAX {
//! Reservation::Infinite(bounds.start) //! Reservation::Infinite(value.start)
//! } else { //! } else {
//! Reservation::Finite( //! Reservation::Finite(
//! bounds.start, //! value.start,
//! bounds.end.up().unwrap(), //! value.end.up().unwrap(),
//! ) //! )
//! } //! }
//! } //! }
@@ -94,7 +111,7 @@ along with discrete_range_map. If not, see <https://www.gnu.org/licenses/>.
//! // Next we can create a custom typed DiscreteRangeMap //! // Next we can create a custom typed DiscreteRangeMap
//! let reservation_map = DiscreteRangeMap::from_slice_strict([ //! let reservation_map = DiscreteRangeMap::from_slice_strict([
//! (Reservation::Finite(10, 20), "Ferris".to_string()), //! (Reservation::Finite(10, 20), "Ferris".to_string()),
//! (Reservation::Infinite(20), "Corro".to_string()), //! (Reservation::Infinite(21), "Corro".to_string()),
//! ]) //! ])
//! .unwrap(); //! .unwrap();
//! //!
@@ -277,7 +294,7 @@ pub mod discrete_range_set;
pub use crate::discrete_finite::DiscreteFinite; pub use crate::discrete_finite::DiscreteFinite;
pub use crate::discrete_range_map::{ pub use crate::discrete_range_map::{
DiscreteRangeMap, FiniteRange, OverlapError, DiscreteRangeMap, InclusiveRange, OverlapError,
}; };
pub use crate::discrete_range_set::DiscreteRangeSet; pub use crate::discrete_range_set::DiscreteRangeSet;
pub use crate::interval::Interval; pub use crate::interval::InclusiveInterval;
+17 -17
View File
@@ -1,26 +1,26 @@
use crate::discrete_finite::DiscreteFinite; use crate::discrete_finite::DiscreteFinite;
use crate::interval::Interval; use crate::interval::InclusiveInterval;
pub fn uu() -> Interval<i8> { pub fn uu() -> InclusiveInterval<i8> {
Interval { InclusiveInterval {
start: i8::MIN, start: i8::MIN,
end: i8::MAX, end: i8::MAX,
} }
} }
pub fn ui(x: i8) -> Interval<i8> { pub fn ui(x: i8) -> InclusiveInterval<i8> {
Interval { InclusiveInterval {
start: i8::MIN, start: i8::MIN,
end: x, end: x,
} }
} }
pub fn ue(x: i8) -> Interval<i8> { pub fn ue(x: i8) -> InclusiveInterval<i8> {
Interval { InclusiveInterval {
start: i8::MIN, start: i8::MIN,
end: x.down().unwrap(), end: x.down().unwrap(),
} }
} }
pub fn iu(x: i8) -> Interval<i8> { pub fn iu(x: i8) -> InclusiveInterval<i8> {
Interval { InclusiveInterval {
start: x, start: x,
end: i8::MAX, end: i8::MAX,
} }
@@ -28,23 +28,23 @@ pub fn iu(x: i8) -> Interval<i8> {
//fn eu(x: i8) -> TestBounds { //fn eu(x: i8) -> TestBounds {
//(Bound::Excluded(x), Bound::Unbounded) //(Bound::Excluded(x), Bound::Unbounded)
//} //}
pub fn ii(x1: i8, x2: i8) -> Interval<i8> { pub fn ii(x1: i8, x2: i8) -> InclusiveInterval<i8> {
Interval { start: x1, end: x2 } InclusiveInterval { start: x1, end: x2 }
} }
pub fn ie(x1: i8, x2: i8) -> Interval<i8> { pub fn ie(x1: i8, x2: i8) -> InclusiveInterval<i8> {
Interval { InclusiveInterval {
start: x1, start: x1,
end: x2.down().unwrap(), end: x2.down().unwrap(),
} }
} }
pub fn ei(x1: i8, x2: i8) -> Interval<i8> { pub fn ei(x1: i8, x2: i8) -> InclusiveInterval<i8> {
Interval { InclusiveInterval {
start: x1.up().unwrap(), start: x1.up().unwrap(),
end: x2, end: x2,
} }
} }
pub fn ee(x1: i8, x2: i8) -> Interval<i8> { pub fn ee(x1: i8, x2: i8) -> InclusiveInterval<i8> {
Interval { InclusiveInterval {
start: x1.up().unwrap(), start: x1.up().unwrap(),
end: x2.down().unwrap(), end: x2.down().unwrap(),
} }
+31 -31
View File
@@ -20,13 +20,13 @@ along with discrete_range_map. If not, see <https://www.gnu.org/licenses/>.
use std::cmp::Ordering; use std::cmp::Ordering;
use crate::discrete_finite::DiscreteFinite; use crate::discrete_finite::DiscreteFinite;
use crate::discrete_range_map::FiniteRange; use crate::discrete_range_map::InclusiveRange;
use crate::interval::Interval; use crate::interval::InclusiveInterval;
pub(crate) fn cmp_point_with_range<I, K>(point: I, range: K) -> Ordering pub(crate) fn cmp_point_with_range<I, K>(point: I, range: K) -> Ordering
where where
I: Ord, I: Ord,
K: FiniteRange<I>, K: InclusiveRange<I>,
{ {
if point < range.start() { if point < range.start() {
Ordering::Less Ordering::Less
@@ -49,8 +49,8 @@ pub(crate) enum Config {
} }
pub(crate) fn config<I, A, B>(a: A, b: B) -> Config pub(crate) fn config<I, A, B>(a: A, b: B) -> Config
where where
A: FiniteRange<I> + Copy, A: InclusiveRange<I> + Copy,
B: FiniteRange<I> + Copy, B: InclusiveRange<I> + Copy,
I: Ord, I: Ord,
{ {
if a.start() < b.start() { if a.start() < b.start() {
@@ -71,21 +71,21 @@ where
} }
enum SortedConfig<I> { enum SortedConfig<I> {
NonOverlapping(Interval<I>, Interval<I>), NonOverlapping(InclusiveInterval<I>, InclusiveInterval<I>),
PartialOverlap(Interval<I>, Interval<I>), PartialOverlap(InclusiveInterval<I>, InclusiveInterval<I>),
Swallowed(Interval<I>, Interval<I>), Swallowed(InclusiveInterval<I>, InclusiveInterval<I>),
} }
fn sorted_config<I, A, B>(a: A, b: B) -> SortedConfig<I> fn sorted_config<I, A, B>(a: A, b: B) -> SortedConfig<I>
where where
A: FiniteRange<I> + Copy, A: InclusiveRange<I> + Copy,
B: FiniteRange<I> + Copy, B: InclusiveRange<I> + Copy,
I: Ord, I: Ord,
{ {
let ae = Interval { let ae = InclusiveInterval {
start: a.start(), start: a.start(),
end: a.end(), end: a.end(),
}; };
let be = Interval { let be = InclusiveInterval {
start: b.start(), start: b.start(),
end: b.end(), end: b.end(),
}; };
@@ -106,7 +106,7 @@ where
pub(crate) fn contains_point<I, A>(range: A, point: I) -> bool pub(crate) fn contains_point<I, A>(range: A, point: I) -> bool
where where
A: FiniteRange<I>, A: InclusiveRange<I>,
I: Ord, I: Ord,
{ {
cmp_point_with_range(point, range).is_eq() cmp_point_with_range(point, range).is_eq()
@@ -114,14 +114,14 @@ where
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct CutResult<I> { pub(crate) struct CutResult<I> {
pub(crate) before_cut: Option<Interval<I>>, pub(crate) before_cut: Option<InclusiveInterval<I>>,
pub(crate) inside_cut: Option<Interval<I>>, pub(crate) inside_cut: Option<InclusiveInterval<I>>,
pub(crate) after_cut: Option<Interval<I>>, pub(crate) after_cut: Option<InclusiveInterval<I>>,
} }
pub(crate) fn cut_range<I, B, C>(base: B, cut: C) -> CutResult<I> pub(crate) fn cut_range<I, B, C>(base: B, cut: C) -> CutResult<I>
where where
B: FiniteRange<I> + Copy, B: InclusiveRange<I> + Copy,
C: FiniteRange<I> + Copy, C: InclusiveRange<I> + Copy,
I: Ord + Copy + DiscreteFinite, I: Ord + Copy + DiscreteFinite,
{ {
let mut result = CutResult { let mut result = CutResult {
@@ -132,34 +132,34 @@ where
match config(base, cut) { match config(base, cut) {
Config::LeftFirstNonOverlapping => { Config::LeftFirstNonOverlapping => {
result.before_cut = Some(Interval { result.before_cut = Some(InclusiveInterval {
start: base.start(), start: base.start(),
end: base.end(), end: base.end(),
}); });
} }
Config::LeftFirstPartialOverlap => { Config::LeftFirstPartialOverlap => {
result.before_cut = Some(Interval { result.before_cut = Some(InclusiveInterval {
start: base.start(), start: base.start(),
end: cut.start().down().unwrap(), end: cut.start().down().unwrap(),
}); });
result.inside_cut = Some(Interval { result.inside_cut = Some(InclusiveInterval {
start: cut.start(), start: cut.start(),
end: base.end(), end: base.end(),
}); });
} }
Config::LeftContainsRight => { Config::LeftContainsRight => {
result.before_cut = Some(Interval { result.before_cut = Some(InclusiveInterval {
start: base.start(), start: base.start(),
end: cut.start().down().unwrap(), end: cut.start().down().unwrap(),
}); });
result.inside_cut = Some(Interval { result.inside_cut = Some(InclusiveInterval {
start: cut.start(), start: cut.start(),
end: cut.end(), end: cut.end(),
}); });
//if cut is already max then we don't need to have an //if cut is already max then we don't need to have an
//after_cut //after_cut
if let Some(upped_end) = cut.end().up() { if let Some(upped_end) = cut.end().up() {
result.after_cut = Some(Interval { result.after_cut = Some(InclusiveInterval {
start: upped_end, start: upped_end,
end: base.end(), end: base.end(),
}); });
@@ -167,23 +167,23 @@ where
} }
Config::RightFirstNonOverlapping => { Config::RightFirstNonOverlapping => {
result.after_cut = Some(Interval { result.after_cut = Some(InclusiveInterval {
start: base.start(), start: base.start(),
end: base.end(), end: base.end(),
}); });
} }
Config::RightFirstPartialOverlap => { Config::RightFirstPartialOverlap => {
result.after_cut = Some(Interval { result.after_cut = Some(InclusiveInterval {
start: cut.end().up().unwrap(), start: cut.end().up().unwrap(),
end: base.end(), end: base.end(),
}); });
result.inside_cut = Some(Interval { result.inside_cut = Some(InclusiveInterval {
start: base.start(), start: base.start(),
end: cut.end(), end: cut.end(),
}); });
} }
Config::RightContainsLeft => { Config::RightContainsLeft => {
result.inside_cut = Some(Interval { result.inside_cut = Some(InclusiveInterval {
start: base.start(), start: base.start(),
end: base.end(), end: base.end(),
}); });
@@ -201,15 +201,15 @@ where
pub(crate) fn is_valid_range<I, K>(range: K) -> bool pub(crate) fn is_valid_range<I, K>(range: K) -> bool
where where
I: Ord, I: Ord,
K: FiniteRange<I>, K: InclusiveRange<I>,
{ {
range.start() <= range.end() range.start() <= range.end()
} }
pub(crate) fn overlaps<I, A, B>(a: A, b: B) -> bool pub(crate) fn overlaps<I, A, B>(a: A, b: B) -> bool
where where
A: FiniteRange<I> + Copy, A: InclusiveRange<I> + Copy,
B: FiniteRange<I> + Copy, B: InclusiveRange<I> + Copy,
I: Ord, I: Ord,
{ {
!matches!(sorted_config(a, b), SortedConfig::NonOverlapping(_, _)) !matches!(sorted_config(a, b), SortedConfig::NonOverlapping(_, _))