range_bounds_map
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()
<= itsend_bound()
[RangeBoundsSet
] is like [RangeBoundsMap
] except it
uses ()
as values, as BTreeSet
does for BTreeMap
Example using Range
s
use range_bounds_map::RangeBoundsMap;
let mut range_bounds_map = RangeBoundsMap::new();
range_bounds_map.insert(0..5, true);
range_bounds_map.insert(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
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 - The data structures are lacking a lot of useful traits, such as:
- Serde: Serialize and Deserialize
- 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 and
this pull request
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 andRangeInclusive
s as keys in it'smap
andset
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 forRange
s and notRangeInclusive
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.