diff --git a/src/lib.rs b/src/lib.rs index 88bb21b..230a0c4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -235,12 +235,12 @@ pub(crate) mod helpers; pub mod test_ranges; pub mod range_bounds_map; -//pub mod range_bounds_set; +pub mod range_bounds_set; pub mod try_from_bounds; pub use crate::range_bounds_map::{ OverlapError, OverlapOrTryFromBoundsError, RangeBoundsMap, TryFromBoundsError, }; -//pub use crate::range_bounds_set::RangeBoundsSet; +pub use crate::range_bounds_set::RangeBoundsSet; pub use crate::try_from_bounds::TryFromBounds; diff --git a/src/range_bounds_map.rs b/src/range_bounds_map.rs index 4a68ddb..a5deab5 100644 --- a/src/range_bounds_map.rs +++ b/src/range_bounds_map.rs @@ -23,7 +23,9 @@ use std::iter::once; use std::marker::PhantomData; use std::ops::{Bound, RangeBounds}; -use btree_monstrousity::btree_map::SearchBoundCustom; +use btree_monstrousity::btree_map::{ + IntoIter as BTreeMapIntoIter, SearchBoundCustom, +}; use btree_monstrousity::BTreeMap; use either::Either; use itertools::Itertools; @@ -288,10 +290,10 @@ where /// ``` /// use std::ops::Range; /// - /// use range_bounds_map::test_ranges::TestBounds; + /// use range_bounds_map::test_ranges::AnyRange; /// use range_bounds_map::RangeBoundsMap; /// - /// let map: RangeBoundsMap = + /// let map: RangeBoundsMap = /// RangeBoundsMap::new(); /// ``` pub fn new() -> Self { @@ -365,6 +367,8 @@ where where Q: NiceRange, { + invalid_range_panic(range); + self.overlapping(range).next().is_some() } @@ -405,9 +409,7 @@ where where Q: NiceRange, { - if !is_valid_range(range) { - panic!("Invalid RangeBounds!"); - } + invalid_range_panic(range); let lower_comp = overlapping_start_comp(range.start()); let upper_comp = overlapping_end_comp(range.end()); @@ -569,8 +571,8 @@ where /// ); /// /// assert_eq!( - /// map.iter().collect::>(), - /// [(&(ie(8, 100)), &false)] + /// map.into_iter().collect::>(), + /// [(ie(8, 100), false)] /// ); /// ``` pub fn remove_overlapping<'a, Q>( @@ -580,6 +582,8 @@ where where Q: NiceRange + 'a, { + invalid_range_panic(range); + //optimisation, switch to BTreeMap::drain_range if it ever gets //implemented return self @@ -652,6 +656,8 @@ where K: TryFromBounds, V: Clone, { + invalid_range_panic(range); + let start_comp = overlapping_start_comp(range.start()); let end_comp = overlapping_end_comp(range.end()); @@ -666,7 +672,7 @@ where Ok(Either::Right(self.cut_non_single_overlapping(range, left_overlapping, right_overlapping)?)) } } - pub fn cut_single_overlapping( + fn cut_single_overlapping( &mut self, range: Q, single_overlapping_range: K, @@ -679,6 +685,8 @@ where K: TryFromBounds, 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)?), @@ -703,7 +711,7 @@ where Ok(once((cut_result.inside_cut.unwrap(), value))) } - pub fn cut_non_single_overlapping<'a, Q>( + fn cut_non_single_overlapping<'a, Q>( &'a mut self, range: Q, left_overlapping: Option, @@ -717,6 +725,8 @@ where K: TryFromBounds, V: Clone, { + invalid_range_panic(range); + let before_config = match left_overlapping { Some(before) => { let cut_result = cut_range(before, range); @@ -832,6 +842,8 @@ where where Q: NiceRange + 'a, { + invalid_range_panic(outer_range); + // I'm in love with how clean/mindblowing this entire function is let overlapping = self .overlapping(outer_range) @@ -907,6 +919,8 @@ where where Q: NiceRange, { + invalid_range_panic(range); + // Soooo clean and mathematical 🥰! self.gaps(range).next().is_none() } @@ -941,6 +955,8 @@ where range: K, value: V, ) -> Result<(), OverlapError> { + invalid_range_panic(range); + if self.overlaps(range) { return Err(OverlapError); } @@ -969,6 +985,8 @@ where R1: FnOnce(&mut Self), R2: FnOnce(&mut Self), { + invalid_range_panic(range); + let matching_start = get_start(self); let matching_end = get_end(self); @@ -1049,8 +1067,8 @@ where /// ); /// /// assert_eq!( - /// map.iter().collect::>(), - /// [(&ie(1, 6), &true), (&ie(10, 16), &false)] + /// map.into_iter().collect::>(), + /// [(ie(1, 6), true), (ie(10, 16), false)] /// ); /// ``` pub fn insert_merge_touching( @@ -1061,6 +1079,8 @@ where where K: TryFromBounds, { + invalid_range_panic(range); + if self.overlaps(range) { return Err(OverlapOrTryFromBoundsError::Overlap(OverlapError)); } @@ -1139,12 +1159,8 @@ where /// ); /// /// assert_eq!( - /// map.iter().collect::>(), - /// [ - /// (&ie(-4, 1), &true), - /// (&ie(1, 8), &true), - /// (&ie(10, 16), &false) - /// ] + /// map.into_iter().collect::>(), + /// [(ie(-4, 1), true), (ie(1, 8), true), (ie(10, 16), false)] /// ); /// ``` pub fn insert_merge_overlapping( @@ -1155,6 +1171,8 @@ where where K: TryFromBounds, { + invalid_range_panic(range); + self.insert_merge_with_comps( range, value, @@ -1224,8 +1242,8 @@ where /// ); /// /// assert_eq!( - /// map.iter().collect::>(), - /// [(&ie(-4, 8), &true), (&ie(10, 16), &false)] + /// map.into_iter().collect::>(), + /// [(ie(-4, 8), true), (ie(10, 16), false)] /// ); /// ``` pub fn insert_merge_touching_or_overlapping( @@ -1236,6 +1254,8 @@ where where K: TryFromBounds, { + invalid_range_panic(range); + self.insert_merge_with_comps( range, value, @@ -1299,12 +1319,8 @@ where /// assert_eq!(map.insert_overwrite(ie(4, 6), true), Ok(())); /// /// assert_eq!( - /// map.iter().collect::>(), - /// [ - /// (&ie(2, 4), &false), - /// (&ie(4, 6), &true), - /// (&ie(6, 8), &false) - /// ] + /// map.into_iter().collect::>(), + /// [(ie(2, 4), false), (ie(4, 6), true), (ie(6, 8), false)] /// ); /// ``` pub fn insert_overwrite( @@ -1316,6 +1332,8 @@ where K: TryFromBounds, V: Clone, { + invalid_range_panic(range); + let _ = self.cut(range)?; self.insert_unchecked(range, value); @@ -1377,6 +1395,18 @@ where } } +// Helper Functions ========================== + +fn invalid_range_panic(range: Q) +where + Q: NiceRange, + I: Ord, +{ + if !is_valid_range(range) { + panic!("Invalid RangeBounds!"); + } +} + fn double_comp() -> impl FnMut(&K, &K) -> Ordering where K: NiceRange, @@ -1479,6 +1509,38 @@ where } } +// Trait Impls ========================== + +impl IntoIterator for RangeBoundsMap +{ + type Item = (K, V); + type IntoIter = IntoIter; + fn into_iter(self) -> Self::IntoIter { + return IntoIter { + inner: self.inner.into_iter(), + phantom: PhantomData, + }; + } +} +/// An owning iterator over the entries of a [`RangeBoundsMap`]. +/// +/// This `struct` is created by the [`into_iter`] method on +/// [`RangeBoundsMap`] (provided by the [`IntoIterator`] trait). See +/// its documentation for more. +/// +/// [`into_iter`]: IntoIterator::into_iter +/// [`IntoIterator`]: core::iter::IntoIterator +pub struct IntoIter { + inner: BTreeMapIntoIter, + phantom: PhantomData, +} +impl Iterator for IntoIter { + type Item = (K, V); + fn next(&mut self) -> Option { + self.inner.next() + } +} + #[cfg(test)] mod tests { use std::ops::Bound; @@ -2358,8 +2420,7 @@ mod tests { // Test Helper Functions //====================== - fn all_non_overlapping_test_bound_entries() -> Vec<(AnyRange, AnyRange)> - { + 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() { diff --git a/src/range_bounds_set.rs b/src/range_bounds_set.rs index 9d1f2f9..2c25e2d 100644 --- a/src/range_bounds_set.rs +++ b/src/range_bounds_set.rs @@ -1,4 +1,206 @@ -#[trivial] +use std::ops::Bound; + +use crate::range_bounds_map::{IntoIter as RangeBoundsMapIntoIter, NiceRange}; +use crate::{ + OverlapError, OverlapOrTryFromBoundsError, RangeBoundsMap, TryFromBounds, + TryFromBoundsError, +}; + +/// An ordered set of non-overlapping [`RangeBounds`] based on [`RangeBoundsMap`]. +/// +/// `I` is the generic type parameter for the [`Ord`] type the `K` +/// type is [`RangeBounds`] over. +/// +/// `K` is the generic type parameter for the [`RangeBounds`] +/// implementing type in the set. +/// +/// See [`RangeBoundsMap`] for more details. +/// +/// [`RangeBounds`]: https://doc.rust-lang.org/std/ops/trait.RangeBounds.html +pub struct RangeBoundsSet { + inner: RangeBoundsMap, +} + +impl RangeBoundsSet +where + I: Ord + Copy, + K: NiceRange, +{ + /// See [`RangeBoundsMap::new()`] for more details. + pub fn new() -> Self { + RangeBoundsSet { + inner: RangeBoundsMap::new(), + } + } + /// See [`RangeBoundsMap::len()`] for more details. + pub fn len(&self) -> usize { + self.inner.len() + } + /// See [`RangeBoundsMap::is_empty()`] for more details. + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } + /// See [`RangeBoundsMap::overlaps()`] for more details. + pub fn overlaps(&self, range: Q) -> bool + where + Q: NiceRange, + { + self.inner.overlaps(range) + } + /// See [`RangeBoundsMap::overlapping()`] for more details. + pub fn overlapping( + &self, + range: Q, + ) -> impl DoubleEndedIterator + where + Q: NiceRange, + { + self.inner.overlapping(range).map(first) + } + /// See [`RangeBoundsMap::contains_point()`] for more details. + pub fn contains_point(&self, point: I) -> bool { + self.inner.contains_point(point) + } + /// See [`RangeBoundsMap::iter()`] for more details. + pub fn iter(&self) -> impl DoubleEndedIterator { + self.inner.iter().map(first) + } + /// See [`RangeBoundsMap::remove_overlapping()`] for more details. + pub fn remove_overlapping<'a, Q>( + &'a mut self, + range: Q, + ) -> impl Iterator + '_ + where + Q: NiceRange + 'a, + { + self.inner.remove_overlapping(range).map(first) + } + /// See [`RangeBoundsMap::cut()`] for more details. + pub fn cut<'a, Q>( + &'a mut self, + range: Q, + ) -> Result< + impl Iterator, Bound)> + '_, + TryFromBoundsError, + > + where + Q: NiceRange + 'a, + K: TryFromBounds, + { + self.inner.cut(range).map(|x| x.map(first)) + } + /// See [`RangeBoundsMap::gaps()`] for more details. + pub fn gaps<'a, Q>( + &'a self, + range: Q, + ) -> impl Iterator, Bound)> + '_ + where + Q: NiceRange + 'a, + { + self.inner.gaps(range) + } + /// See [`RangeBoundsMap::contains_range()`] for more details. + pub fn contains_range(&self, range: Q) -> bool + where + Q: NiceRange, + { + self.inner.contains_range(range) + } + /// See [`RangeBoundsMap::insert_strict()`] for more details. + pub fn insert_strict(&mut self, range: K) -> Result<(), OverlapError> { + self.inner.insert_strict(range, ()) + } + /// See [`RangeBoundsMap::insert_merge_touching()`] for more details. + pub fn insert_merge_touching( + &mut self, + range: K, + ) -> Result + where + K: TryFromBounds, + { + self.inner.insert_merge_touching(range, ()) + } + /// See [`RangeBoundsMap::insert_merge_overlapping()`] for more details. + pub fn insert_merge_overlapping( + &mut self, + range: K, + ) -> Result + where + K: TryFromBounds, + { + self.inner.insert_merge_overlapping(range, ()) + } + /// See [`RangeBoundsMap::insert_merge_touching_or_overlapping()`] for more details. + pub fn insert_merge_touching_or_overlapping( + &mut self, + range: K, + ) -> Result + where + K: TryFromBounds, + { + self.inner.insert_merge_touching_or_overlapping(range, ()) + } + /// See [`RangeBoundsMap::insert_overwrite()`] for more details. + pub fn insert_overwrite( + &mut self, + range: K, + ) -> Result<(), TryFromBoundsError> + where + K: TryFromBounds, + { + self.inner.insert_overwrite(range, ()) + } + /// See [`RangeBoundsMap::first_entry()`] for more details. + pub fn first(&self) -> Option<&K> { + self.inner.first_entry().map(first) + } + /// See [`RangeBoundsMap::last_entry()`] for more details. + pub fn last(&self) -> Option<&K> { + self.inner.last_entry().map(first) + } + /// See [`RangeBoundsMap::from_slice_strict()`] for more details. + pub fn from_slice_strict( + slice: [K; N], + ) -> Result, OverlapError> { + let mut set = RangeBoundsSet::new(); + for range in slice { + set.insert_strict(range)?; + } + return Ok(set); + } +} + +// Helper Functions ========================== + fn first((a, _): (A, B)) -> A { a } + +// Trait Impls ========================== + +impl IntoIterator for RangeBoundsSet { + type Item = K; + type IntoIter = IntoIter; + fn into_iter(self) -> Self::IntoIter { + return IntoIter { + inner: self.inner.into_iter(), + }; + } +} +/// An owning iterator over the entries of a [`RangeBoundsSet`]. +/// +/// This `struct` is created by the [`into_iter`] method on +/// [`RangeBoundsSet`] (provided by the [`IntoIterator`] trait). See +/// its documentation for more. +/// +/// [`into_iter`]: IntoIterator::into_iter +/// [`IntoIterator`]: core::iter::IntoIterator +pub struct IntoIter { + inner: RangeBoundsMapIntoIter, +} +impl Iterator for IntoIter { + type Item = K; + fn next(&mut self) -> Option { + self.inner.next().map(first) + } +}