2023-04-21 15:11:44 +01:00
|
|
|
# discrete_range_map
|
2022-11-27 15:08:10 +00:00
|
|
|
|
2023-04-21 15:11:44 +01:00
|
|
|
[](https://www.gnu.org/licenses/agpl-3.0.en.html)
|
|
|
|
[](https://docs.rs/discrete_range_map)
|
2022-12-12 04:28:31 +00:00
|
|
|
[](https://github.com/ripytide)
|
2023-04-21 15:11:44 +01:00
|
|
|
[](https://crates.io/crates/discrete_range_map)
|
2022-12-02 02:26:28 +00:00
|
|
|
|
2022-12-01 17:19:03 +00:00
|
|
|
<p align="center">
|
2023-04-21 15:11:44 +01:00
|
|
|
<img src="logo.png" alt="discrete_range_map_logo" width="350">
|
2022-12-01 17:19:03 +00:00
|
|
|
</p>
|
|
|
|
|
2023-04-21 15:39:56 +01:00
|
|
|
This crate provides [`DiscreteRangeMap`] and [`DiscreteRangeSet`],
|
|
|
|
Data Structures for storing non-overlapping discrete intervals based
|
2023-04-24 09:33:41 +01:00
|
|
|
off [`BTreeMap`].
|
2022-12-05 01:23:03 +00:00
|
|
|
|
2023-12-03 20:25:25 +00:00
|
|
|
`no_std` is supported and should work with the default features.
|
|
|
|
|
2023-12-27 12:58:26 +00:00
|
|
|
## `Copy` is partially required
|
2023-04-21 14:40:09 +01:00
|
|
|
|
|
|
|
Due to implementation complications with non-`Copy` types the
|
2023-12-27 12:58:26 +00:00
|
|
|
datastructures currently require both the range type and the points the
|
|
|
|
ranges are over to be `Copy`. However, the value type used when using
|
|
|
|
the [`DiscreteRangeMap`] does not have to be `Copy`. In fact the only
|
|
|
|
required traits on the value type are sometimes `Clone` or `Eq` but only
|
|
|
|
for some methods so if in doubt check a methods trait bounds.
|
2023-04-21 14:40:09 +01:00
|
|
|
|
|
|
|
## Example using an Inclusive-Exclusive range
|
2022-11-27 15:08:10 +00:00
|
|
|
|
2022-12-01 16:53:13 +00:00
|
|
|
```rust
|
2023-12-27 13:26:50 +00:00
|
|
|
use discrete_range_map::inclusive_interval::ie;
|
2023-04-21 15:11:44 +01:00
|
|
|
use discrete_range_map::DiscreteRangeMap;
|
2022-11-27 15:08:10 +00:00
|
|
|
|
2023-04-21 14:29:03 +01:00
|
|
|
let mut map = DiscreteRangeMap::new();
|
2022-11-30 16:25:17 +00:00
|
|
|
|
2023-04-21 13:28:04 +01:00
|
|
|
map.insert_strict(ie(0, 5), true);
|
|
|
|
map.insert_strict(ie(5, 10), false);
|
2022-11-28 03:50:31 +00:00
|
|
|
|
2023-04-21 13:28:04 +01:00
|
|
|
assert_eq!(map.overlaps(ie(-2, 12)), true);
|
|
|
|
assert_eq!(map.contains_point(20), false);
|
|
|
|
assert_eq!(map.contains_point(5), true);
|
2022-12-01 16:53:13 +00:00
|
|
|
```
|
2022-11-28 05:07:58 +00:00
|
|
|
|
2023-04-21 14:53:59 +01:00
|
|
|
## Example using a custom range type
|
2022-11-28 20:42:22 +00:00
|
|
|
|
2022-12-01 16:53:13 +00:00
|
|
|
```rust
|
2023-12-03 20:25:25 +00:00
|
|
|
use std::ops::{Bound, RangeBounds};
|
|
|
|
|
2023-12-27 13:26:50 +00:00
|
|
|
use discrete_range_map::inclusive_interval::ie;
|
2023-05-16 16:59:57 +01:00
|
|
|
use discrete_range_map::{
|
2023-12-27 12:53:16 +00:00
|
|
|
DiscreteFinite, DiscreteRangeMap, InclusiveInterval,
|
|
|
|
InclusiveRange,
|
2023-05-16 16:59:57 +01:00
|
|
|
};
|
2022-11-27 15:08:10 +00:00
|
|
|
|
2023-04-21 13:28:04 +01:00
|
|
|
#[derive(Debug, Copy, Clone)]
|
2022-12-01 16:53:13 +00:00
|
|
|
enum Reservation {
|
2023-12-27 12:53:16 +00:00
|
|
|
// Start, End (Inclusive-Inclusive)
|
|
|
|
Finite(i8, i8),
|
|
|
|
// Start (Inclusive-Infinity)
|
|
|
|
Infinite(i8),
|
2022-12-01 16:53:13 +00:00
|
|
|
}
|
|
|
|
|
2023-12-03 20:25:25 +00:00
|
|
|
// First, we need to implement InclusiveRange
|
|
|
|
impl InclusiveRange<i8> for Reservation {
|
2023-12-27 12:53:16 +00:00
|
|
|
fn start(&self) -> i8 {
|
|
|
|
match self {
|
|
|
|
Reservation::Finite(start, _) => *start,
|
|
|
|
Reservation::Infinite(start) => *start,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn end(&self) -> i8 {
|
|
|
|
match self {
|
|
|
|
Reservation::Finite(_, end) => *end,
|
|
|
|
Reservation::Infinite(_) => i8::MAX,
|
|
|
|
}
|
|
|
|
}
|
2023-05-16 16:59:57 +01:00
|
|
|
}
|
|
|
|
|
2023-12-03 20:25:25 +00:00
|
|
|
// Second, we need to implement From<InclusiveInterval<i8>>
|
|
|
|
impl From<InclusiveInterval<i8>> for Reservation {
|
2023-12-27 12:53:16 +00:00
|
|
|
fn from(value: InclusiveInterval<i8>) -> Self {
|
|
|
|
if value.end == i8::MAX {
|
|
|
|
Reservation::Infinite(value.start)
|
|
|
|
} else {
|
|
|
|
Reservation::Finite(
|
|
|
|
value.start,
|
|
|
|
value.end.up().unwrap(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
2022-12-01 16:53:13 +00:00
|
|
|
}
|
|
|
|
|
2023-04-21 14:29:03 +01:00
|
|
|
// Next we can create a custom typed DiscreteRangeMap
|
|
|
|
let reservation_map = DiscreteRangeMap::from_slice_strict([
|
2023-12-27 12:53:16 +00:00
|
|
|
(Reservation::Finite(10, 20), "Ferris".to_string()),
|
|
|
|
(Reservation::Infinite(21), "Corro".to_string()),
|
2022-12-01 16:53:13 +00:00
|
|
|
])
|
|
|
|
.unwrap();
|
|
|
|
|
2023-04-21 13:28:04 +01:00
|
|
|
for (reservation, name) in reservation_map.overlapping(ie(16, 17))
|
2022-12-01 16:53:13 +00:00
|
|
|
{
|
2023-12-27 12:53:16 +00:00
|
|
|
println!(
|
|
|
|
"{name} has reserved {reservation:?} inside the range 16..17"
|
|
|
|
);
|
2022-12-01 16:53:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (reservation, name) in reservation_map.iter() {
|
2023-12-27 12:53:16 +00:00
|
|
|
println!("{name} has reserved {reservation:?}");
|
2022-12-01 16:53:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
assert_eq!(
|
2023-12-27 12:53:16 +00:00
|
|
|
reservation_map.overlaps(Reservation::Infinite(0)),
|
|
|
|
true
|
2022-12-01 16:53:13 +00:00
|
|
|
);
|
|
|
|
```
|
|
|
|
|
2023-12-27 12:53:16 +00:00
|
|
|
## Key Understandings and Philosophies
|
2023-04-21 14:19:40 +01:00
|
|
|
|
|
|
|
### Discrete-ness
|
|
|
|
|
|
|
|
This crate is designed to work with [`Discrete`] types as compared to
|
|
|
|
[`Continuous`] types. For example, `u8` is a `Discrete` type, but
|
|
|
|
`String` is a `Continuous` if you try to parse it as a decimal value.
|
|
|
|
|
|
|
|
The reason for this is that common [`interval-Mathematics`] operations
|
2023-12-27 12:48:24 +00:00
|
|
|
differ depending on whether the underlying type is `Discrete` or
|
2023-04-21 14:19:40 +01:00
|
|
|
`Continuous`. For example `5..=6` touches `7..=8` since integers are
|
|
|
|
`Discrete` but `5.0..=6.0` does **not** touch `7.0..=8.0` since the
|
|
|
|
value `6.5` exists.
|
|
|
|
|
2023-12-27 14:47:06 +00:00
|
|
|
Importantly, this also makes Inclusive/Exclusive ended ranges really
|
|
|
|
easy to work with as they can be losslessly converted between one
|
|
|
|
another. For example, `3..6` is equivalent to `3..=5`.
|
|
|
|
|
2023-04-21 14:19:40 +01:00
|
|
|
### Finite-ness
|
|
|
|
|
2023-12-27 12:48:24 +00:00
|
|
|
At the moment this crate is also designed to work only with [`Finite`]
|
|
|
|
types such as `u8` or `i128`, but not with `Infinite` types such as
|
|
|
|
[`BigInt`] from the [`num_bigint`] crate. This is because the
|
|
|
|
[`get_entry_at_point()`] method would not be able to return anything
|
|
|
|
from an empty map if the type was an infinite type such as `BigInt`
|
|
|
|
since it has no maximum value.
|
2023-04-21 14:19:40 +01:00
|
|
|
|
2023-12-27 12:48:24 +00:00
|
|
|
A handy trick you can use to pretend to have infinite types when you
|
|
|
|
don't expect to reach to top end of your type is to use [`Actual
|
|
|
|
Infinity`] to pretend you have an `Infinity`. For example, if you were
|
|
|
|
using `u8` as your point type then you could create a wrapper type such
|
|
|
|
as this:
|
|
|
|
|
|
|
|
```rust
|
|
|
|
use std::cmp::Ordering;
|
|
|
|
|
|
|
|
use discrete_range_map::DiscreteFinite;
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
|
|
enum WithInfinity<T> {
|
2023-12-27 12:53:16 +00:00
|
|
|
Finite(T),
|
|
|
|
Infinity,
|
2023-12-27 12:48:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> Ord for WithInfinity<T>
|
|
|
|
where
|
2023-12-27 12:53:16 +00:00
|
|
|
T: Ord,
|
2023-12-27 12:48:24 +00:00
|
|
|
{
|
2023-12-27 12:53:16 +00:00
|
|
|
fn cmp(&self, other: &Self) -> Ordering {
|
|
|
|
match (self, other) {
|
|
|
|
(
|
|
|
|
WithInfinity::Finite(x),
|
|
|
|
WithInfinity::Finite(y),
|
|
|
|
) => x.cmp(y),
|
|
|
|
(WithInfinity::Finite(_), WithInfinity::Infinity) => {
|
|
|
|
Ordering::Less
|
|
|
|
}
|
|
|
|
(WithInfinity::Infinity, WithInfinity::Finite(_)) => {
|
|
|
|
Ordering::Greater
|
|
|
|
}
|
|
|
|
(WithInfinity::Infinity, WithInfinity::Infinity) => {
|
|
|
|
Ordering::Equal
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-12-27 12:48:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> PartialOrd for WithInfinity<T>
|
|
|
|
where
|
2023-12-27 12:53:16 +00:00
|
|
|
T: Ord,
|
2023-12-27 12:48:24 +00:00
|
|
|
{
|
2023-12-27 12:53:16 +00:00
|
|
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
|
|
Some(self.cmp(other))
|
|
|
|
}
|
2023-12-27 12:48:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> DiscreteFinite for WithInfinity<T>
|
|
|
|
where
|
2023-12-27 12:53:16 +00:00
|
|
|
T: DiscreteFinite,
|
2023-12-27 12:48:24 +00:00
|
|
|
{
|
2023-12-27 12:53:16 +00:00
|
|
|
const MIN: Self = WithInfinity::Finite(T::MIN);
|
|
|
|
const MAX: Self = WithInfinity::Infinity;
|
|
|
|
|
|
|
|
fn up(self) -> Option<Self>
|
|
|
|
where
|
|
|
|
Self: Sized,
|
|
|
|
{
|
|
|
|
match self {
|
|
|
|
WithInfinity::Finite(x) => match x.up() {
|
|
|
|
Some(y) => Some(WithInfinity::Finite(y)),
|
|
|
|
None => Some(WithInfinity::Infinity),
|
|
|
|
},
|
|
|
|
WithInfinity::Infinity => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn down(self) -> Option<Self>
|
|
|
|
where
|
|
|
|
Self: Sized,
|
|
|
|
{
|
|
|
|
match self {
|
|
|
|
WithInfinity::Finite(x) => {
|
|
|
|
Some(WithInfinity::Finite(x.down()?))
|
|
|
|
}
|
|
|
|
WithInfinity::Infinity => {
|
|
|
|
Some(WithInfinity::Finite(T::MAX))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-12-27 12:48:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// And then you this means you can be explicit with when
|
|
|
|
// Infinity is encountered such as when it might be
|
|
|
|
// returned by `get_entry_at_point()`, for example:
|
|
|
|
|
|
|
|
use discrete_range_map::{DiscreteRangeMap, InclusiveInterval};
|
|
|
|
|
|
|
|
let map: DiscreteRangeMap<
|
2023-12-27 12:53:16 +00:00
|
|
|
WithInfinity<u8>,
|
|
|
|
InclusiveInterval<WithInfinity<u8>>,
|
|
|
|
bool,
|
2023-12-27 12:48:24 +00:00
|
|
|
> = DiscreteRangeMap::new();
|
|
|
|
|
|
|
|
let mut gap = map.get_entry_at_point(WithInfinity::Finite(4));
|
|
|
|
|
|
|
|
assert_eq!(
|
2023-12-27 12:53:16 +00:00
|
|
|
gap,
|
|
|
|
Err(InclusiveInterval {
|
|
|
|
start: WithInfinity::Finite(0),
|
|
|
|
end: WithInfinity::Infinity,
|
|
|
|
})
|
2023-12-27 12:48:24 +00:00
|
|
|
);
|
|
|
|
```
|
2022-12-01 16:53:13 +00:00
|
|
|
|
2023-04-06 19:07:58 +01:00
|
|
|
### Invalid Ranges
|
2023-03-31 17:37:26 +01:00
|
|
|
|
2023-12-27 12:48:24 +00:00
|
|
|
Within this crate, not all ranges are considered valid ranges. The
|
|
|
|
definition of the validity of a range used within this crate is that a
|
|
|
|
range is only valid if it contains at least one value of the underlying
|
|
|
|
domain.
|
2023-03-31 17:37:26 +01:00
|
|
|
|
2023-12-27 12:48:24 +00:00
|
|
|
For example, `4..6` is considered valid as it contains the values `4`
|
|
|
|
and `5`, however, `4..4` is considered invalid as it contains no
|
|
|
|
values. Another example of invalid range are those whose start values
|
|
|
|
are greater than their end values. such as `5..2` or `100..=40`.
|
2023-03-31 17:37:26 +01:00
|
|
|
|
2023-04-06 19:02:52 +01:00
|
|
|
Here are a few examples of ranges and whether they are valid:
|
2023-03-31 17:37:26 +01:00
|
|
|
|
2023-04-21 14:19:40 +01:00
|
|
|
| range | valid |
|
|
|
|
| -------------------------------------- | ----- |
|
|
|
|
| 0..=0 | YES |
|
|
|
|
| 0..0 | NO |
|
|
|
|
| 0..1 | YES |
|
|
|
|
| 9..8 | NO |
|
2023-12-27 12:48:24 +00:00
|
|
|
| (Bound::Excluded(3), Bound::Excluded(4)) | NO |
|
2023-04-21 14:19:40 +01:00
|
|
|
| 400..=400 | YES |
|
2023-03-31 17:37:26 +01:00
|
|
|
|
2022-12-12 03:58:51 +00:00
|
|
|
### Overlap
|
2022-12-01 16:53:13 +00:00
|
|
|
|
2023-04-06 19:02:52 +01:00
|
|
|
Two ranges are "overlapping" if there exists a point that is contained
|
2023-12-27 14:54:54 +00:00
|
|
|
within both ranges. For example, `2..4` and `2..6` overlap but `2..4`
|
|
|
|
and `4..8` do not.
|
2022-12-12 03:58:51 +00:00
|
|
|
|
|
|
|
### Touching
|
|
|
|
|
2023-04-06 19:02:52 +01:00
|
|
|
Two ranges are "touching" if they do not overlap and 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`.
|
2022-12-01 16:53:13 +00:00
|
|
|
|
2023-03-31 17:37:26 +01:00
|
|
|
### Further Reading
|
|
|
|
|
2023-04-06 19:02:52 +01:00
|
|
|
See Wikipedia's article on mathematical Intervals:
|
2023-03-31 17:37:26 +01:00
|
|
|
<https://en.wikipedia.org/wiki/Interval_(mathematics)>
|
|
|
|
|
2023-12-27 12:53:16 +00:00
|
|
|
## Features
|
2023-12-03 20:25:25 +00:00
|
|
|
|
2023-12-27 12:53:16 +00:00
|
|
|
This crate currently has no features
|
|
|
|
|
|
|
|
## Credit
|
2022-12-01 16:53:13 +00:00
|
|
|
|
2023-12-27 12:48:24 +00:00
|
|
|
Lots of my inspiration came from the [`rangemap`] crate.
|
2023-04-06 19:02:52 +01:00
|
|
|
|
2023-12-27 12:48:24 +00:00
|
|
|
The BTreeMap implementation ([`btree_monstrousity`]) used under the
|
|
|
|
hood was inspired and forked from the [`copse`] crate.
|
2022-12-01 16:53:13 +00:00
|
|
|
|
2023-12-27 12:53:16 +00:00
|
|
|
## Name Change
|
2023-04-21 14:53:59 +01:00
|
|
|
|
2023-12-27 12:48:24 +00:00
|
|
|
This crate was previously named [`range_bounds_map`] it was renamed
|
|
|
|
around about 2023-04-24 due to it no longer being an accurate name.
|
2023-04-21 15:33:24 +01:00
|
|
|
|
2023-12-27 12:53:16 +00:00
|
|
|
## Similar Crates
|
2022-12-01 16:53:13 +00:00
|
|
|
|
|
|
|
Here are some relevant crates I found whilst searching around the
|
2023-12-27 12:48:24 +00:00
|
|
|
topic area, beware my biases when reading:
|
2022-12-01 16:53:13 +00:00
|
|
|
|
|
|
|
- <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).
|
2023-01-04 03:52:37 +00:00
|
|
|
- <https://docs.rs/btree-range-map>
|
2022-12-01 16:53:13 +00:00
|
|
|
- <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
|
2023-04-06 14:22:33 +01:00
|
|
|
for [`Range`]s and not [`RangeInclusive`]s. And also no fancy
|
|
|
|
merging functions.
|
2022-12-01 16:53:13 +00:00
|
|
|
- <https://docs.rs/unbounded-interval-tree>
|
2023-04-21 14:48:45 +01:00
|
|
|
A data structure based off of a 2007 published paper! It supports
|
|
|
|
any range as keys, unfortunately, it is implemented with a
|
|
|
|
non-balancing `Box<Node>` based tree, however it also supports
|
|
|
|
overlapping ranges which my library does not.
|
2022-12-01 16:53:13 +00:00
|
|
|
- <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.
|
2023-12-27 12:48:24 +00:00
|
|
|
- <https://docs.rs/rust-lapper>
|
|
|
|
Another sort-of immutable (can insert but its very expensive)
|
|
|
|
interval datastructure optimised for lots of intervals of the same
|
|
|
|
size such as their staple usecase of genomic datasets.
|
|
|
|
- <https://docs.rs/store-interval-tree>
|
|
|
|
An interval tree very similar to this crate and `rangemap` with many
|
|
|
|
of the same methods (and lots of doc examples!) except using a custom
|
|
|
|
in-house self-balancing tree implementation. It is not exactly clear
|
|
|
|
from my reading of the docs whether they support overlapping intervals
|
|
|
|
or not. On the one hand their examples show overlapping intervals but
|
|
|
|
then their `insert()` method says "if interval already exists,
|
|
|
|
interval will be ignored", so perhaps it allows overlapping but not
|
|
|
|
duplicate intervals? A bit of an odd choice in my opinion.
|
|
|
|
- <https://docs.rs/bio> and <https://docs.rs/rudac>
|
|
|
|
Both essentially identical to `store-interval-tree` as it looks like
|
|
|
|
`store-interval-tree` is a fork of `rudac`'s interval tree. `bio` in
|
|
|
|
particular seems targeted at bioinfographics.
|
2022-12-01 16:53:13 +00:00
|
|
|
|
|
|
|
[`btreemap`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html
|
2023-12-27 12:48:24 +00:00
|
|
|
[`btree_monstrousity`]: https://github.com/ripytide/btree_monstrousity
|
2022-12-01 16:53:13 +00:00
|
|
|
[`range`]: https://doc.rust-lang.org/std/ops/struct.Range.html
|
|
|
|
[`rangemap`]: https://docs.rs/rangemap/latest/rangemap/
|
|
|
|
[`rangeinclusive`]: https://doc.rust-lang.org/std/ops/struct.RangeInclusive.html
|
2023-04-06 19:02:52 +01:00
|
|
|
[`copse`]: https://github.com/eggyal/copse
|
2023-04-21 14:19:40 +01:00
|
|
|
[`discrete`]: https://en.wikipedia.org/wiki/Discrete_mathematics
|
|
|
|
[`continuous`]: https://en.wikipedia.org/wiki/List_of_continuity-related_mathematical_topics
|
|
|
|
[`interval-mathematics`]: https://en.wikipedia.org/wiki/Interval_(mathematics)
|
|
|
|
[`actual infinity`]: https://en.wikipedia.org/wiki/Actual_infinity
|
2023-04-21 14:25:11 +01:00
|
|
|
[`finite`]: https://en.wiktionary.org/wiki/finite#Adjective
|
2023-04-21 15:33:24 +01:00
|
|
|
[`range_bounds_map`]: https://docs.rs/range_bounds_map
|
2023-12-27 12:48:24 +00:00
|
|
|
[`bigint`]: https://docs.rs/num-bigint/latest/num_bigint/struct.BigInt.html
|
|
|
|
[`num_bigint`]: https://docs.rs/num-bigint
|
|
|
|
[`get_entry_at_point()`]: https://docs.rs/discrete_range_map/latest/discrete_range_map/discrete_range_map/struct.DiscreteRangeMap.html#method.get_entry_at_point
|
2023-12-27 13:00:23 +00:00
|
|
|
[`DiscreteRangeMap`]: https://docs.rs/discrete_range_map/latest/discrete_range_map/discrete_range_map/struct.DiscreteRangeMap.html#
|
|
|
|
[`DiscreteRangeSet`]: https://docs.rs/discrete_range_map/latest/discrete_range_map/discrete_range_set/struct.DiscreteRangeSet.html#
|