add new insert_* function and changed Errors to be more specific

This commit is contained in:
ripytide 2022-12-05 00:44:24 +00:00
parent 27b5680564
commit 23e0b49332
5 changed files with 365 additions and 419 deletions

View File

@ -19,6 +19,20 @@ maintaining two invariants:
[`RangeBoundsSet`] is like [`RangeBoundsMap`] except it
uses `()` as values, as [`BTreeSet`] does for [`BTreeMap`]
## Key Definitions:
### Overlap
Two `RangeBounds` are "overlapping" if there exists a point that is
contained within both `RangeBounds`.
### Touching
Two `RangeBounds` are "touching" if they do not overlap but
there exists no value between them. For example, `2..4` and
`4..6` are touching but `2..4` and `6..8` are not, neither are
`2..6` and `4..8`.
## Example using [`Range`]s
```rust
@ -111,6 +125,9 @@ Issue (or even open a new one) and I'd be happy to implement it.
To summarise:
- Some overly strict Trait-Bounds on some functions due to `impl`
level `Trait-Bounds` rather than specific `function` level
`Trait-Bounds`
- No coalescing/merge insert functions, yet
- Missing some functions common to BTreeMap and BTreeSet like:
- `clear()`

View File

@ -17,179 +17,7 @@ You should have received a copy of the GNU General Public License
along with range_bounds_map. If not, see <https://www.gnu.org/licenses/>.
*/
//! This crate provides [`RangeBoundsMap`] and [`RangeBoundsSet`].
//!
//! [`RangeBoundsMap`] is similar to [`BTreeMap`] except [`RangeBoundsMap`]
//! uses any type that implements the [`RangeBounds`] trait as keys, while
//! maintaining two invariants:
//!
//! - No two keys may overlap
//! - A keys' [`start_bound()`] <= its [`end_bound()`]
//!
//! [`RangeBoundsSet`] is like [`RangeBoundsMap`] except it
//! uses `()` as values, as [`BTreeSet`] does for [`BTreeMap`]
//!
//! ## Example using [`Range`]s
//!
//! ```rust
//! use range_bounds_map::RangeBoundsMap;
//!
//! let mut range_bounds_map = RangeBoundsMap::new();
//!
//! range_bounds_map.insert_platonic(0..5, true);
//! range_bounds_map.insert_platonic(5..10, false);
//!
//! assert_eq!(range_bounds_map.overlaps(&(-2..12)), true);
//! assert_eq!(range_bounds_map.contains_point(&20), false);
//! assert_eq!(range_bounds_map.contains_point(&5), true);
//! ```
//!
//! ## Example using a custom [`RangeBounds`] type
//!
//! ```rust
//! use std::ops::{Bound, RangeBounds};
//!
//! use range_bounds_map::RangeBoundsMap;
//!
//! #[derive(Debug)]
//! enum Reservation {
//! // Start, End (Inclusive-Inclusive)
//! Finite(u8, u8),
//! // Start (Exclusive)
//! Infinite(u8),
//! }
//!
//! // First, we need to implement RangeBounds
//! impl RangeBounds<u8> for Reservation {
//! fn start_bound(&self) -> Bound<&u8> {
//! match self {
//! Reservation::Finite(start, _) => {
//! Bound::Included(start)
//! }
//! Reservation::Infinite(start) => {
//! Bound::Excluded(start)
//! }
//! }
//! }
//! fn end_bound(&self) -> Bound<&u8> {
//! match self {
//! Reservation::Finite(_, end) => Bound::Included(end),
//! Reservation::Infinite(_) => Bound::Unbounded,
//! }
//! }
//! }
//!
//! // Next we can create a custom typed RangeBoundsMap
//! let reservation_map = RangeBoundsMap::try_from([
//! (Reservation::Finite(10, 20), "Ferris".to_string()),
//! (Reservation::Infinite(20), "Corro".to_string()),
//! ])
//! .unwrap();
//!
//! for (reservation, name) in reservation_map.overlapping(&(16..17))
//! {
//! println!(
//! "{name} has reserved {reservation:?} inside the range 16..17"
//! );
//! }
//!
//! for (reservation, name) in reservation_map.iter() {
//! println!("{name} has reserved {reservation:?}");
//! }
//!
//! assert_eq!(
//! reservation_map.overlaps(&Reservation::Infinite(0)),
//! true
//! );
//! ```
//!
//! # How
//!
//! 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 is wrapped
//! around the [`start_bound()`]s so that we can apply our custom [`Ord`]
//! implementation onto all the [`start_bound()`]s.
//!
//! # Improvements/Caveats
//!
//! There are a few issues I can think of with this implementation,
//! each of them are documented as GitHub Issues. If you would like
//! any of these features added, drop a comment in a respective GitHub
//! Issue (or even open a new one) and I'd be happy to implement it.
//!
//! To summarise:
//!
//! - No coalescing/merge insert functions, yet
//! - No `gaps()` iterator function, yet
//! - Missing some functions common to BTreeMap and BTreeSet like:
//! - `clear()`
//! - `is_subset()`
//! - etc... a bunch more
//! - Sub-optimal use of unnecessary `cloned()` just to placate the borrow checker
//! - Use TryFrom<(Bound, Bound)> instead of [`TryFromBounds`] (relys on
//! upstream to impl)
//! - The data structures are lacking a lot of useful traits, such as:
//! - FromIterator
//! - IntoIterator
//! - Probably a bunch more
//!
//! # Credit
//!
//! I originally came up with the `StartBound`: [`Ord`] bodge on my
//! own, however, I later stumbled across [`rangemap`] which also used
//! a `StartBound`: [`Ord`] bodge. [`rangemap`] then became my main
//! source of inspiration. The aim for my library was to become a more
//! generic superset of [`rangemap`], following from
//! [this issue](https://github.com/jeffparsons/rangemap/issues/56) and
//! [this pull request](https://github.com/jeffparsons/rangemap/pull/57)
//! in which I changed [`rangemap`]'s [`RangeMap`] to use
//! [`RangeBounds`]s as keys before I realized it might be easier and
//! simpler to just write it all from scratch. Which ended up working
//! really well with some simplifications I made which ended up
//! resulting in much less code (~600 lines over `rangemap`'s ~2700)
//!
//! # Similar Crates
//!
//! Here are some relevant crates I found whilst searching around the
//! topic area:
//!
//! - <https://docs.rs/rangemap>
//! Very similar to this crate but can only use [`Range`]s and
//! [`RangeInclusive`]s as keys in it's `map` and `set` structs (separately).
//! - <https://docs.rs/ranges>
//! Cool library for fully-generic ranges (unlike std::ops ranges), along
//! with a `Ranges` datastructure for storing them (Vec-based
//! unfortunately)
//! - <https://docs.rs/intervaltree>
//! Allows overlapping intervals but is immutable unfortunately
//! - <https://docs.rs/nonoverlapping_interval_tree>
//! Very similar to rangemap except without a `gaps()` function and only
//! for [`Range`]s and not [`RangeInclusive`]s. And also no fancy coalescing
//! functions.
//! - <https://docs.rs/unbounded-interval-tree>
//! A data structure based off of a 2007 published paper! It supports any
//! RangeBounds as keys too, except it is implemented with a non-balancing
//! `Box<Node>` based tree, however it also supports overlapping
//! RangeBounds which my library does not.
//! - <https://docs.rs/rangetree>
//! I'm not entirely sure what this library is or isn't, but it looks like
//! a custom red-black tree/BTree implementation used specifically for a
//! Range Tree. Interesting but also quite old (5 years) and uses
//! unsafe.
//!
//! [`btreemap`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html
//! [`btreeset`]: https://doc.rust-lang.org/std/collections/struct.BTreeSet.html
//! [`rangebounds`]: https://doc.rust-lang.org/std/ops/trait.RangeBounds.html
//! [`start_bound()`]: https://doc.rust-lang.org/std/ops/trait.RangeBounds.html#tymethod.start_bound
//! [`end_bound()`]: https://doc.rust-lang.org/std/ops/trait.RangeBounds.html#tymethod.end_bound
//! [`range`]: https://doc.rust-lang.org/std/ops/struct.Range.html
//! [`range()`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html#method.range
//! [`rangemap`]: https://docs.rs/rangemap/latest/rangemap/
//! [`rangeinclusivemap`]: https://docs.rs/rangemap/latest/rangemap/inclusive_map/struct.RangeInclusiveMap.html#
//! [`rangeinclusive`]: https://doc.rust-lang.org/std/ops/struct.RangeInclusive.html
//! [`Ord`]: https://doc.rust-lang.org/std/cmp/trait.Ord.html
//! todo
#![feature(is_some_and)]
#![feature(let_chains)]
@ -197,11 +25,12 @@ along with range_bounds_map. If not, see <https://www.gnu.org/licenses/>.
#![allow(clippy::needless_return)]
pub(crate) mod bounds;
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::{
CutError, InsertPlatonicError, RangeBoundsMap,
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;

View File

@ -121,21 +121,23 @@ where
starts: BTreeMap<StartBound<I>, (K, V)>,
}
/// An error type to returned from the [`RangeBoundsMap::insert_platonic()`] function.
///
/// Its returned if you you try to insert a `RangeBounds` that
/// overlaps another `RangeBounds`.
/// An error type to represent a `RangeBounds` overlapping another
/// `RangeBounds` when it should not have.
#[derive(PartialEq, Debug)]
pub struct InsertPlatonicError;
pub struct OverlapError;
/// An error type to returned from the [`RangeBoundsMap::cut()`].
///
/// Its returned if when cutting out a `RangeBounds` from a map you
/// need to change the inner `RangeBounds`'s start and end `Bound`s to
/// different `Bound`s that the underlying `K`: `RangeBounds` type
/// can't handle.
/// An error type to represent a failed [`TryFromBounds`] within a
/// method.
#[derive(PartialEq, Debug)]
pub struct CutError;
pub struct TryFromBoundsError;
/// An error type to represent either an [`OverlapError`] or a
/// [`TryFromBoundsError`].
#[derive(PartialEq, Debug)]
pub enum OverlapOrTryFromBoundsError {
Overlap(OverlapError),
TryFromBounds(TryFromBoundsError),
}
impl<I, K, V> RangeBoundsMap<I, K, V>
where
@ -175,23 +177,23 @@ where
self.starts.len()
}
/// Adds a new (`RangeBounds` `Value`) pair to the map without
/// Adds a new (`RangeBounds`, `Value`) pair to the map without
/// modifying other entries.
///
/// If the new `RangeBounds` overlaps one or more `RangeBounds`
/// already in the map then [`InsertPlatonicError`]
/// is returned and the map is not updated.
/// already in the map rather than just touching then an
/// [`OverlapError`] is returned and the map is not updated.
///
/// # Examples
/// ```
/// use range_bounds_map::{InsertPlatonicError, RangeBoundsMap};
/// use range_bounds_map::{OverlapError, RangeBoundsMap};
///
/// let mut range_bounds_map = RangeBoundsMap::new();
///
/// assert_eq!(range_bounds_map.insert_platonic(5..10, 9), Ok(()));
/// assert_eq!(
/// range_bounds_map.insert_platonic(5..10, 2),
/// Err(InsertPlatonicError)
/// Err(OverlapError)
/// );
/// assert_eq!(range_bounds_map.len(), 1);
/// ```
@ -199,9 +201,9 @@ where
&mut self,
range_bounds: K,
value: V,
) -> Result<(), InsertPlatonicError> {
) -> Result<(), OverlapError> {
if self.overlaps(&range_bounds) {
return Err(InsertPlatonicError);
return Err(OverlapError);
}
//optimisation fix this without cloning
@ -510,14 +512,14 @@ where
/// Cuts a given `RangeBounds` out of the map.
///
/// If the remaining `RangeBounds` left after the cut are not able
/// to be created with the [`TryFromBounds`] trait then a
/// [`TryFromBoundsError`] will be returned.
///
/// `V` must implement `Clone` as if you try to cut out the center
/// of a `RangeBounds` in the map it will split into two different
/// (`RangeBounds`, `Value`) pairs using `Clone`.
///
/// If the remaining `RangeBounds` left after the cut are not able
/// to be converted into the `K` type with the [`TryFromBounds`]
/// trait then a [`CutError`] will be returned.
///
/// # Examples
/// ```
/// use range_bounds_map::{CutError, RangeBoundsMap};
@ -535,12 +537,9 @@ where
///
/// assert_eq!(base.cut(&(2..40)), Ok(()));
/// assert_eq!(base, after_cut);
/// assert_eq!(
/// base.cut(&(60..=80)),
/// Err(CutError)
/// );
/// assert_eq!(base.cut(&(60..=80)), Err(CutError));
/// ```
pub fn cut<Q>(&mut self, range_bounds: &Q) -> Result<(), CutError>
pub fn cut<Q>(&mut self, range_bounds: &Q) -> Result<(), TryFromBoundsError>
where
Q: RangeBounds<I>,
K: TryFromBounds<I>,
@ -556,17 +555,20 @@ where
// optimisation don't clone the value when only changing the
// RangeBounds via CutResult::Single()
let mut attempt_insert_platonic = |(start_bound, end_bound),
value|
-> Result<(), CutError> {
match K::try_from_bounds(start_bound, end_bound).ok_or(CutError) {
Ok(key) => {
self.insert_platonic(key, value).unwrap();
return Ok(());
let mut attempt_insert_platonic =
|(start_bound, end_bound),
value|
-> Result<(), TryFromBoundsError> {
match K::try_from_bounds(start_bound, end_bound)
.ok_or(TryFromBoundsError)
{
Ok(key) => {
self.insert_platonic(key, value).unwrap();
return Ok(());
}
Err(cut_error) => return Err(cut_error),
}
Err(cut_error) => return Err(cut_error),
}
};
};
match first_last {
(Some(first), Some(last)) => {
@ -709,6 +711,107 @@ where
// Soooo clean and mathematical 🥰!
self.gaps(range_bounds).next().is_none()
}
/// Adds a new (`RangeBounds`, `Value`) pair to the map and
/// coalesces into other `RangeBounds` in the map which touch it.
///
/// If the new `RangeBounds` overlaps one or more `RangeBounds`
/// already in the map rather than just touching then an
/// [`OverlapError`] is returned and the map is not updated.
///
/// If the coalesced `RangeBounds` cannot be created with the
/// [`TryFromBounds`] trait then a [`TryFromBoundsError`] will be
/// returned.
///
/// # Examples
/// ```
/// use range_bounds_map::{
/// OverlapOrTryFromBoundsError, RangeBoundsMap,
/// };
///
/// let mut range_bounds_map = RangeBoundsMap::new();
///
/// todo!()
/// ```
pub fn insert_coalesce_touching(
&mut self,
range_bounds: K,
value: V,
) -> Result<(), OverlapOrTryFromBoundsError> {
todo!()
}
/// Adds a new (`RangeBounds`, `Value`) pair to the map and
/// coalesces into other `RangeBounds` in the map which overlap
/// it.
///
/// If the coalesced `RangeBounds` cannot be created with the
/// [`TryFromBounds`] trait then a [`TryFromBoundsError`] will be
/// returned.
///
/// # Examples
/// ```
/// use range_bounds_map::{RangeBoundsMap, TryFromBoundsError};
///
/// let mut range_bounds_map = RangeBoundsMap::new();
/// todo!()
/// ```
pub fn insert_coalesce_overlapping(
&mut self,
range_bounds: K,
value: V,
) -> Result<(), TryFromBoundsError> {
todo!()
}
/// Adds a new (`RangeBounds`, `Value`) pair to the map and
/// coalesces into other `RangeBounds` in the map which touch or
/// overlap it.
///
/// If the coalesced `RangeBounds` cannot be created with the
/// [`TryFromBounds`] trait then a [`TryFromBoundsError`] will be
/// returned.
///
/// # Examples
/// ```
/// use range_bounds_map::{RangeBoundsMap, TryFromBoundsError};
///
/// let mut range_bounds_map = RangeBoundsMap::new();
/// todo!()
/// ```
pub fn insert_coalesce_touching_or_overlapping(
&mut self,
range_bounds: K,
value: V,
) -> Result<(), TryFromBoundsError> {
todo!()
}
/// Adds a new (`RangeBounds`, `Value`) pair to the map and
/// overwrites any other `RangeBounds` that overlap the new
/// `RangeBounds`.
///
/// This is equivalent to using [`RangeBoundsMap::cut()`]
/// followed by [`RangeBoundsMap::insert_platonic()`].
///
/// If the remaining `RangeBounds` left after the cut are not able
/// to be created with the [`TryFromBounds`] trait then a
/// [`TryFromBoundsError`] will be returned.
///
/// # Examples
/// ```
/// use range_bounds_map::{RangeBoundsMap, TryFromBoundsError};
///
/// let mut range_bounds_map = RangeBoundsMap::new();
/// todo!()
/// ```
pub fn overwrite(
&mut self,
range_bounds: K,
value: V,
) -> Result<(), TryFromBoundsError> {
todo!()
}
}
impl<const N: usize, I, K, V> TryFrom<[(K, V); N]> for RangeBoundsMap<I, K, V>
@ -716,7 +819,7 @@ where
K: RangeBounds<I>,
I: Ord + Clone,
{
type Error = InsertPlatonicError;
type Error = OverlapError;
fn try_from(pairs: [(K, V); N]) -> Result<Self, Self::Error> {
let mut range_bounds_map = RangeBoundsMap::new();
for (range_bounds, value) in pairs {
@ -851,237 +954,212 @@ fn flip_bound<I>(bound: Bound<&I>) -> Bound<&I> {
}
}
#[cfg(test)]
mod tests {
use std::ops::{Bound, Range, RangeBounds};
//#[cfg(test)]
//mod tests {
//use std::ops::{Bound, Range, RangeBounds};
use super::*;
use crate::bounds::StartBound;
use crate::RangeBoundsSet;
//use super::*;
//use crate::bounds::StartBound;
//use crate::RangeBoundsSet;
type TestBounds = (Bound<u8>, Bound<u8>);
//type TestBounds = (Bound<u8>, Bound<u8>);
//only every other number to allow mathematical_overlapping_definition
//to test between bounds in finite using smaller intervalled finite
pub(crate) const NUMBERS: &'static [u8] = &[2, 4, 6, 8, 10];
//go a bit around on either side to compensate for Unbounded
pub(crate) const NUMBERS_DOMAIN: &'static [u8] =
&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
////only every other number to allow mathematical_overlapping_definition
////to test between bounds in finite using smaller intervalled finite
//pub(crate) const NUMBERS: &'static [u8] = &[2, 4, 6, 8, 10];
////go a bit around on either side to compensate for Unbounded
//pub(crate) const NUMBERS_DOMAIN: &'static [u8] =
//&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
#[test]
fn mass_overlaps_test() {
for range_bounds1 in all_valid_test_bounds() {
for range_bounds2 in all_valid_test_bounds() {
let our_answer = overlaps(&range_bounds1, &range_bounds2);
//#[test]
//fn mass_overlaps_test() {
//for range_bounds1 in all_valid_test_bounds() {
//for range_bounds2 in all_valid_test_bounds() {
//let our_answer = overlaps(&range_bounds1, &range_bounds2);
let mathematical_definition_of_overlap =
NUMBERS_DOMAIN.iter().any(|x| {
range_bounds1.contains(x) && range_bounds2.contains(x)
});
//let mathematical_definition_of_overlap =
//NUMBERS_DOMAIN.iter().any(|x| {
//range_bounds1.contains(x) && range_bounds2.contains(x)
//});
if our_answer != mathematical_definition_of_overlap {
dbg!(range_bounds1, range_bounds2);
dbg!(mathematical_definition_of_overlap, our_answer);
panic!("Discrepency in .overlaps() detected!");
}
}
}
}
//if our_answer != mathematical_definition_of_overlap {
//dbg!(range_bounds1, range_bounds2);
//dbg!(mathematical_definition_of_overlap, our_answer);
//panic!("Discrepency in .overlaps() detected!");
//}
#[test]
fn mass_overlapping_test() {
//case zero
for overlap_range in all_valid_test_bounds() {
//you can't overlap nothing
assert!(
RangeBoundsSet::<u8, Range<u8>>::new()
.overlapping(&overlap_range)
.next()
.is_none()
);
}
//#[test]
//fn mass_overlapping_test() {
////case zero
//for overlap_range in all_valid_test_bounds() {
////you can't overlap nothing
//assert!(
//RangeBoundsSet::<u8, Range<u8>>::new()
//.overlapping(&overlap_range)
//.next()
//.is_none()
//);
//}
//case one
for overlap_range in all_valid_test_bounds() {
for inside_range in all_valid_test_bounds() {
let mut range_bounds_set = RangeBoundsSet::new();
range_bounds_set.insert_platonic(inside_range).unwrap();
////case one
//for overlap_range in all_valid_test_bounds() {
//for inside_range in all_valid_test_bounds() {
//let mut range_bounds_set = RangeBoundsSet::new();
//range_bounds_set.insert_platonic(inside_range).unwrap();
let mut expected_overlapping = Vec::new();
if overlaps(&overlap_range, &inside_range) {
expected_overlapping.push(inside_range);
}
//let mut expected_overlapping = Vec::new();
//if overlaps(&overlap_range, &inside_range) {
//expected_overlapping.push(inside_range);
//}
let overlapping = range_bounds_set
.overlapping(&overlap_range)
.copied()
.collect::<Vec<_>>();
//let overlapping = range_bounds_set
//.overlapping(&overlap_range)
//.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!"
);
}
}
}
//if overlapping != expected_overlapping {
//dbg!(overlap_range, inside_range);
//dbg!(overlapping, expected_overlapping);
//panic!(
//"Discrepency in .overlapping() with single inside range detected!"
//);
//}
//case two
for overlap_range in all_valid_test_bounds() {
for (inside_range1, inside_range2) in
all_non_overlapping_test_bound_pairs()
{
let mut range_bounds_set = RangeBoundsSet::new();
range_bounds_set.insert_platonic(inside_range1).unwrap();
range_bounds_set.insert_platonic(inside_range2).unwrap();
////case two
//for overlap_range in all_valid_test_bounds() {
//for (inside_range1, inside_range2) in
//all_non_overlapping_test_bound_pairs()
//{
//let mut range_bounds_set = RangeBoundsSet::new();
//range_bounds_set.insert_platonic(inside_range1).unwrap();
//range_bounds_set.insert_platonic(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);
}
//make our expected_overlapping the correct order
if expected_overlapping.len() > 1 {
if StartBound::from(expected_overlapping[0].start_bound())
> StartBound::from(
expected_overlapping[1].start_bound(),
) {
expected_overlapping.swap(0, 1);
}
}
//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);
//}
////make our expected_overlapping the correct order
//if expected_overlapping.len() > 1 {
//if StartBound::from(expected_overlapping[0].start_bound())
//> StartBound::from(
//expected_overlapping[1].start_bound(),
//) {
//expected_overlapping.swap(0, 1);
//}
let overlapping = range_bounds_set
.overlapping(&overlap_range)
.copied()
.collect::<Vec<_>>();
//let overlapping = range_bounds_set
//.overlapping(&overlap_range)
//.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!"
);
}
}
}
}
//if overlapping != expected_overlapping {
//dbg!(overlap_range, inside_range1, inside_range2);
//dbg!(overlapping, expected_overlapping);
//panic!(
//"Discrepency in .overlapping() with two inside ranges detected!"
//);
//}
impl<I> CutResult<I> {
fn contains(&self, point: &I) -> bool
where
I: PartialOrd,
{
match self {
CutResult::Nothing => false,
CutResult::Single(range_bounds) => range_bounds.contains(point),
CutResult::Double(first_range_bounds, second_range_bounds) => {
first_range_bounds.contains(point)
|| second_range_bounds.contains(point)
}
}
}
}
#[test]
fn mass_cut_range_bounds_tests() {
for base in all_valid_test_bounds() {
for cut in all_valid_test_bounds() {
let cut_result = cut_range_bounds(&base, &cut);
//impl<I> CutResult<I> {
//fn contains(&self, point: &I) -> bool
//where
//I: PartialOrd,
//{
//match self {
//CutResult::Nothing => false,
//CutResult::Single(range_bounds) => range_bounds.contains(point),
//CutResult::Double(first_range_bounds, second_range_bounds) => {
//first_range_bounds.contains(point)
//|| second_range_bounds.contains(point)
//}
//#[test]
//fn mass_cut_range_bounds_tests() {
//for base in all_valid_test_bounds() {
//for cut in all_valid_test_bounds() {
//let cut_result = cut_range_bounds(&base, &cut);
// The definition of a cut is: A && NOT B
for x in NUMBERS_DOMAIN {
let result_contains = cut_result.contains(x);
let base_contains = base.contains(x);
let cut_contains = cut.contains(x);
//// The definition of a cut is: A && NOT B
//for x in NUMBERS_DOMAIN {
//let result_contains = cut_result.contains(x);
//let base_contains = base.contains(x);
//let cut_contains = cut.contains(x);
let invariant =
result_contains == (base_contains && !cut_contains);
//let invariant =
//result_contains == (base_contains && !cut_contains);
if !invariant {
dbg!(result_contains);
dbg!(base_contains);
dbg!(cut_contains);
//if !invariant {
//dbg!(result_contains);
//dbg!(base_contains);
//dbg!(cut_contains);
dbg!(base);
dbg!(cut);
dbg!(cut_result);
//dbg!(base);
//dbg!(cut);
//dbg!(cut_result);
dbg!(x);
//dbg!(x);
panic!("Invariant Broken!");
}
}
}
}
}
//panic!("Invariant Broken!");
//}
fn all_non_overlapping_test_bound_pairs() -> Vec<(TestBounds, TestBounds)> {
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));
}
}
}
//fn all_non_overlapping_test_bound_pairs() -> Vec<(TestBounds, TestBounds)> {
//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;
}
//return output;
//}
fn all_valid_test_bounds() -> Vec<TestBounds> {
let mut output = Vec::new();
//fn all_valid_test_bounds() -> Vec<TestBounds> {
//let mut output = Vec::new();
//bounded-bounded
output.append(&mut all_finite_bounded_pairs());
//bounded-unbounded
for start_bound in all_finite_bounded() {
output.push((start_bound, Bound::Unbounded));
}
//unbounded-bounded
for end_bound in all_finite_bounded() {
output.push((Bound::Unbounded, end_bound));
}
//unbounded-unbounded
output.push((Bound::Unbounded, Bound::Unbounded));
////bounded-bounded
//output.append(&mut all_finite_bounded_pairs());
////bounded-unbounded
//for start_bound in all_finite_bounded() {
//output.push((start_bound, Bound::Unbounded));
//}
////unbounded-bounded
//for end_bound in all_finite_bounded() {
//output.push((Bound::Unbounded, end_bound));
//}
////unbounded-unbounded
//output.push((Bound::Unbounded, Bound::Unbounded));
return output;
}
//return output;
//}
fn all_finite_bounded_pairs() -> Vec<(Bound<u8>, Bound<u8>)> {
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_pairs() -> Vec<(Bound<u8>, Bound<u8>)> {
//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<u8>> {
let mut output = Vec::new();
for i in NUMBERS {
for j in 0..=1 {
output.push(finite_bound(*i, j == 1));
}
}
return output;
}
//fn all_finite_bounded() -> Vec<Bound<u8>> {
//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: u8, included: bool) -> Bound<u8> {
match included {
false => Bound::Included(x),
true => Bound::Excluded(x),
}
}
}
//fn finite_bound(x: u8, included: bool) -> Bound<u8> {
//match included {
//false => Bound::Included(x),
//true => Bound::Excluded(x),
//}

View File

@ -1,3 +1,22 @@
/*
Copyright 2022 James Forster
This file is part of range_bounds_map.
range_bounds_map is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
range_bounds_map is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with range_bounds_map. If not, see <https://www.gnu.org/licenses/>.
*/
use std::ops::{
Bound, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo,
RangeToInclusive,

View File

@ -1,6 +1,9 @@
- check documentation to remove mentions of insert without the naming
modifier
- remove test is_valid_range_bounds and use the same one the module
uses
- write more tests for more complicated functions
- write docs for everything again