From f70c1d0669bd559eb88b97e9cb3d2d61dd20b532 Mon Sep 17 00:00:00 2001 From: ripytide Date: Mon, 28 Nov 2022 20:42:22 +0000 Subject: [PATCH] wrote all of bound.rs docs and added examples n stuff to set.rs --- Cargo.lock | 25 ++++++++++++++ Cargo.toml | 3 ++ README.md | 2 ++ src/bounds.rs | 36 +++++++++++++++++--- src/lib.rs | 6 ++-- src/range_bounds_map.rs | 33 +++++++++--------- src/range_bounds_set.rs | 75 +++++++++++++++++++++++++++++++++++++++-- 7 files changed, 155 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 254a6c9..36220c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,15 +2,40 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + [[package]] name = "either" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "ordered-float" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d84eb1409416d254e4a9c8fa56cc24701755025b458f0fcd8e59e1f5f40c23bf" +dependencies = [ + "num-traits", +] + [[package]] name = "range_bounds_map" version = "0.0.1" dependencies = [ "either", + "ordered-float", ] diff --git a/Cargo.toml b/Cargo.toml index a1b4627..4bf5748 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,3 +7,6 @@ edition = "2021" [dependencies] either = "1.8.0" + +[dev-dependencies] +ordered-float = "3.4.0" diff --git a/README.md b/README.md index b7b7e0f..225697d 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,8 @@ - turn overlaps back into a trait to make it public, mabye +- review caveats again + - run cargo fmt - run and fix cargo clippy - take a look around idiomatic rust for a bit first diff --git a/src/bounds.rs b/src/bounds.rs index 444bedb..0ffcec5 100644 --- a/src/bounds.rs +++ b/src/bounds.rs @@ -20,20 +20,44 @@ along with range_bounds_map. If not, see . use std::cmp::Ordering; use std::ops::Bound; +/// An Ord newtype of [`Bound`] specific to [`start_bound()`]. +/// +/// This type is used to circumvent [`BTreeMap`]s (and rust collections +/// in general) lack of methods for searching with custom +/// [`comparator`] functions and/or it's lack of a [`Cursor`]-like +/// API +/// +/// [`start_bound()`]: https://doc.rust-lang.org/std/ops/trait.RangeBounds.html#tymethod.start_bound +/// [`BTreeMap`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html +/// [`comparator`]: https://stackoverflow.com/q/34028324 +/// [`Cursor`]: https://github.com/rust-lang/rfcs/issues/1778 #[derive(PartialEq, Debug)] pub(crate) enum StartBound { + /// Mirror of [`Bound::Included`] Included(T), + /// Mirror of [`Bound::Excluded`] Excluded(T), + /// Mirror of [`Bound::Unbounded`] Unbounded, - //workaround types used only as ends_bounds in meta-bound - //StartBound range searches in overlapping() (non need for - //reverseIncluded as it would be equivalent to normal included) + /// Workaround type used to represent [`Bound::Excluded`] in [`end_bound()`] in meta-bound + /// [`BTreeMap::range`] searches in [`crate::RangeBoundsMap::overlapping()`] + /// + /// [`end_bound()`]: https://doc.rust-lang.org/std/ops/trait.RangeBounds.html#tymethod.end_bound + /// [`BTreeMap::range`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html#method.range ReverseExcluded(T), + /// Workaround type used to represent [`Bound::Unbounded`] in [`end_bound()`] in meta-bound + /// [`BTreeMap::range`] searches in [`crate::RangeBoundsMap::overlapping()`] + /// + /// [`end_bound()`]: https://doc.rust-lang.org/std/ops/trait.RangeBounds.html#tymethod.end_bound + /// [`BTreeMap::range`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html#method.range ReverseUnbounded, } impl StartBound { - //when using this as an end value in a range search + /// Converts the [`StartBound`] to the appropriate type for use as + /// an [`end_bound()`] in a range search + /// + /// [`end_bound()`]: https://doc.rust-lang.org/std/ops/trait.RangeBounds.html#tymethod.end_bound pub(crate) fn as_end_bound(self) -> StartBound { match self { //flipping is unnecessary @@ -48,6 +72,10 @@ impl StartBound { impl Eq for StartBound where T: PartialEq {} +/// The [`PartialOrd`] implementaion with the goal of allowing the use +/// of [`BTreeMap::range`] on [`StartBound`]s +/// +/// [`BTreeMap::range`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html#method.range #[rustfmt::skip] impl PartialOrd for StartBound where diff --git a/src/lib.rs b/src/lib.rs index e6f9a98..251a2ea 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,7 +32,6 @@ along with range_bounds_map. If not, see . //! //! ``` //! # use range_bounds_map::RangeBoundsMap; -//! //! let mut range_bounds_map = RangeBoundsMap::new(); //! //! range_bounds_map.insert(0..5, true); @@ -48,7 +47,6 @@ along with range_bounds_map. If not, see . //! # use std::ops::RangeBounds; //! # use std::ops::Bound; //! # use range_bounds_map::RangeBoundsMap; -//! //! #[derive(Debug)] //! enum Reservation { //! // Start, End (Inclusive-Inclusive) @@ -97,8 +95,8 @@ along with range_bounds_map. If not, see . //! Most of the [`RangeBounds`]-specific methods on [`RangeBoundsMap`] //! utilize the [`RangeBoundsMap::overlapping()`] method which //! internally uses [`BTreeMap`]'s [`range()`] function. To allow -//! using [`range()`] for this purpose a newtype wrapper wrapped -//! around the [`start_bound()`]s so that we apply our custom [`Ord`] +//! using [`range()`] for this purpose a newtype wrapper is wrapped +//! around the [`start_bound()`]s so that we can apply our custom [`Ord`] //! implementation onto all the [`start_bound()`]s. //! //! # Improvements/Caveats diff --git a/src/range_bounds_map.rs b/src/range_bounds_map.rs index fc140b9..c9f9772 100644 --- a/src/range_bounds_map.rs +++ b/src/range_bounds_map.rs @@ -60,7 +60,7 @@ where } pub fn contains_point(&self, point: &I) -> bool { - self.get(point).is_some() + self.get_at_point(point).is_some() } pub fn overlaps(&self, search_range_bounds: &Q) -> bool @@ -77,6 +77,8 @@ where where Q: RangeBounds, { + //todo panic on invalid search range + //optimisation fix this without cloning let start = StartBound::from(search_range_bounds.start_bound().cloned()); @@ -123,23 +125,13 @@ where ); } - pub fn get(&self, point: &I) -> Option<&V> { - self.get_key_value(point).map(|(_, value)| value) + pub fn get_at_point(&self, point: &I) -> Option<&V> { + self.get_key_value_at_point(point).map(|(_, value)| value) } - pub fn get_key_value(&self, point: &I) -> Option<(&K, &V)> { - //a zero-range included-included range is equivalent to a point - return self - .overlapping(&( - Bound::Included(point.clone()), - Bound::Included(point.clone()), - )) - .next(); - } - - pub fn get_mut(&mut self, point: &I) -> Option<&mut V> { + pub fn get_at_point_mut(&mut self, point: &I) -> Option<&mut V> { if let Some(overlapping_start_bound) = - self.get_key_value(point).map(|(key, _)| key.start_bound()) + self.get_key_value_at_point(point).map(|(key, _)| key.start_bound()) { return self .starts @@ -150,6 +142,17 @@ where return None; } + pub fn get_key_value_at_point(&self, point: &I) -> Option<(&K, &V)> { + //a zero-range included-included range is equivalent to a point + return self + .overlapping(&( + Bound::Included(point.clone()), + Bound::Included(point.clone()), + )) + .next(); + } + + pub fn iter(&self) -> impl Iterator { self.starts.iter().map(|(_, (key, value))| (key, value)) } diff --git a/src/range_bounds_set.rs b/src/range_bounds_set.rs index 04b8f29..d28122a 100644 --- a/src/range_bounds_set.rs +++ b/src/range_bounds_set.rs @@ -21,6 +21,77 @@ use std::ops::RangeBounds; use crate::range_bounds_map::RangeBoundsMap; +/// An ordered set of [`RangeBounds`] based on [`BTreeSet`] +/// +/// # Examples +/// ``` +/// # use range_bounds_map::RangeBoundsSet; +/// let mut visits = RangeBoundsSet::new(); +/// +/// // Add some ranges +/// visits.insert(4..8); +/// visits.insert(8..18); +/// visits.insert(20..100); +/// +/// // Check if a point is contained in the set +/// if visits.contains_point(&0) { +/// println!("No visit at the beginning ;("); +/// } +/// +/// // Iterate over the ranges overlapping another range +/// for visit in visits.overlapping(&(2..=8)) { +/// println!("{visit:?}"); +/// } +/// ``` +/// Example using a custom [`RangeBounds`] type: +/// ``` +/// # use std::ops::Bound; +/// # use std::ops::RangeBounds; +/// # use ordered_float::NotNan; +/// # use range_bounds_map::RangeBoundsSet; +/// // An Exlusive-Exlusive range of [`f32`]s not provided by any +/// // std::ops ranges +/// // We use [`ordered_float::NotNan`]s as the inner type must be Ord +/// // similar to a normal [`BTreeSet`] +/// struct ExEx { +/// start: NotNan, +/// end: NotNan, +/// } +/// # impl ExEx { +/// # fn new(start: f32, end: f32) -> ExEx { +/// # ExEx { +/// # start: NotNan::new(start).unwrap(), +/// # end: NotNan::new(end).unwrap(), +/// # } +/// # } +/// # } +/// +/// // Implement RangeBounds on our new type +/// impl RangeBounds> for ExEx { +/// fn start_bound(&self) -> Bound<&NotNan> { +/// Bound::Excluded(&self.start) +/// } +/// fn end_bound(&self) -> Bound<&NotNan> { +/// Bound::Excluded(&self.start) +/// } +/// } +/// +/// // Now we can make a [`RangeBoundsSet`] of [`ExEx``]s +/// let mut set = RangeBoundsSet::new(); +/// +/// set.insert(ExEx::new(0.0, 5.0)); +/// set.insert(ExEx::new(5.0, 7.5)); +/// +/// assert!(NotNan::new(5.0).unwrap() < NotNan::new(5.0).unwrap()); +/// panic!(); +/// +/// assert_eq!(set.contains_point(&(NotNan::new(5.0).unwrap())), false); +/// assert_eq!(set.contains_point(&(NotNan::new(7.0).unwrap())), true); +/// assert_eq!(set.contains_point(&(NotNan::new(7.5).unwrap())), false); +/// ``` +/// +/// [`RangeBounds`]: https://doc.rust-lang.org/std/collections/struct.BTreeSet.html +/// [`BTreeSet`]: https://doc.rust-lang.org/std/collections/struct.BTreeSet.html pub struct RangeBoundsSet { map: RangeBoundsMap, } @@ -61,8 +132,8 @@ where .map(|(key, _)| key) } - pub fn get(&self, point: &I) -> Option<&K> { - self.map.get_key_value(point).map(|(key, _)| key) + pub fn get_at_point(&self, point: &I) -> Option<&K> { + self.map.get_key_value_at_point(point).map(|(key, _)| key) } pub fn contains_point(&self, point: &I) -> bool {