wrote all of bound.rs docs and added examples n stuff to set.rs
This commit is contained in:
Generated
+25
@@ -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",
|
||||
]
|
||||
|
||||
@@ -7,3 +7,6 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
either = "1.8.0"
|
||||
|
||||
[dev-dependencies]
|
||||
ordered-float = "3.4.0"
|
||||
|
||||
@@ -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
|
||||
|
||||
+32
-4
@@ -20,20 +20,44 @@ along with range_bounds_map. If not, see <https://www.gnu.org/licenses/>.
|
||||
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<T> {
|
||||
/// 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<T> StartBound<T> {
|
||||
//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<T> {
|
||||
match self {
|
||||
//flipping is unnecessary
|
||||
@@ -48,6 +72,10 @@ impl<T> StartBound<T> {
|
||||
|
||||
impl<T> Eq for StartBound<T> 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<T> PartialOrd for StartBound<T>
|
||||
where
|
||||
|
||||
+2
-4
@@ -32,7 +32,6 @@ along with range_bounds_map. If not, see <https://www.gnu.org/licenses/>.
|
||||
//!
|
||||
//! ```
|
||||
//! # 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 <https://www.gnu.org/licenses/>.
|
||||
//! # 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 <https://www.gnu.org/licenses/>.
|
||||
//! 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
|
||||
|
||||
+18
-15
@@ -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<Q>(&self, search_range_bounds: &Q) -> bool
|
||||
@@ -77,6 +77,8 @@ where
|
||||
where
|
||||
Q: RangeBounds<I>,
|
||||
{
|
||||
//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<Item = (&K, &V)> {
|
||||
self.starts.iter().map(|(_, (key, value))| (key, value))
|
||||
}
|
||||
|
||||
+73
-2
@@ -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<f32>,
|
||||
/// end: NotNan<f32>,
|
||||
/// }
|
||||
/// # impl ExEx {
|
||||
/// # fn new(start: f32, end: f32) -> ExEx {
|
||||
/// # ExEx {
|
||||
/// # start: NotNan::new(start).unwrap(),
|
||||
/// # end: NotNan::new(end).unwrap(),
|
||||
/// # }
|
||||
/// # }
|
||||
/// # }
|
||||
///
|
||||
/// // Implement RangeBounds<f32> on our new type
|
||||
/// impl RangeBounds<NotNan<f32>> for ExEx {
|
||||
/// fn start_bound(&self) -> Bound<&NotNan<f32>> {
|
||||
/// Bound::Excluded(&self.start)
|
||||
/// }
|
||||
/// fn end_bound(&self) -> Bound<&NotNan<f32>> {
|
||||
/// 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<I, K> {
|
||||
map: RangeBoundsMap<I, K, ()>,
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user