This crate provides [DiscreteRangeMap
] and [DiscreteRangeSet
],
Data Structures for storing non-overlapping discrete intervals based
off [BTreeMap
].
Copy
Due to implementation complications with non-Copy
types the
datastructures currently require both the range type and the points
the ranges are over to be Copy
.
```rust use discreterangemap::testranges::ie; use discreterange_map::DiscreteRangeMap;
let mut map = DiscreteRangeMap::new();
map.insertstrict(ie(0, 5), true); map.insertstrict(ie(5, 10), false);
asserteq!(map.overlaps(ie(-2, 12)), true); asserteq!(map.containspoint(20), false); asserteq!(map.contains_point(5), true); ```
```rust use discreterangemap::testranges::ie; use discreterange_map::{ DiscreteFinite, DiscreteFiniteBounds, DiscreteRangeMap, FiniteRange, };
enum Reservation { // Start, End (Inclusive-Exclusive) Finite(i8, i8), // Start (Inclusive-Forever) Infinite(i8), }
// First, we need to implement FiniteRange
impl FiniteRange
// Second, we need to implement From
// Next we can create a custom typed DiscreteRangeMap let reservationmap = DiscreteRangeMap::fromslicestrict([ (Reservation::Finite(10, 20), "Ferris".tostring()), (Reservation::Infinite(20), "Corro".to_string()), ]) .unwrap();
for (reservation, name) in reservation_map.overlapping(ie(16, 17)) { println!( "{name} has reserved {reservation:?} inside the range 16..17" ); }
for (reservation, name) in reservation_map.iter() { println!("{name} has reserved {reservation:?}"); }
asserteq!( reservationmap.overlaps(Reservation::Infinite(0)), true ); ```
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
differ depending on wether the underlying type is Discrete
or
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.
This crate is also designed to work with [Finite
] types since it is
much easier to implement and it is not restrictive to users since you
can still represent Infinite
numbers in Finite
types paradoxically
using the concept of [Actual Infinity
].
For example you could define Infinite
for u8
as u8::MAX
or if
you still want to use u8::MAX
as a Finite
number you could define
a wrapper type for u8
that adds an [Actual Infinity
] value to the
u8
set.
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.
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
.
Here are a few examples of ranges and whether they are valid:
| range | valid | | -------------------------------------- | ----- | | 0..=0 | YES | | 0..0 | NO | | 0..1 | YES | | 9..8 | NO | | (Bound::Exluded(3), Bound::Exluded(4)) | NO | | 400..=400 | YES |
Two ranges are "overlapping" if there exists a point that is contained within both ranges.
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
.
When a range "merges" other ranges it absorbs them to become larger.
See Wikipedia's article on mathematical Intervals: https://en.wikipedia.org/wiki/Interval_(mathematics)
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.
Later I then undid the [Ord
] bodge and switched to my own full-code
port of [BTreeMap
], inspired and forked from [copse
], for it's
increased flexibility.
The aim for this 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.
It is however worth noting the library eventually expanded and evolved from it's origins.
This crate was previously named [range_bounds_map
].
Here are some relevant crates I found whilst searching around the topic area:
Range
]s and
[RangeInclusive
]s as keys in it's map
and set
structs (separately).Ranges
datastructure for storing them (Vec-based
unfortunately)gaps()
function and only
for [Range
]s and not [RangeInclusive
]s. And also no fancy
merging functions.Box<Node>
based tree, however it also supports
overlapping ranges which my library does not.