blob: 6cb3da901c98438a75d9152875b679e7093c26c0 [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use std::borrow::Borrow;
use std::cmp::{Eq, Ord, Ordering, PartialOrd};
use std::collections::BTreeMap;
use std::iter::Iterator;
use std::ops::Bound;
use std::ops::Range;
/// Keys for the map inside RangeMap.
///
/// This object holds a Range but implements the ordering traits according to
/// the start of the range. Using this struct lets us store both ends of the
/// range in the BTreeMap and recover ranges by querying for their start point.
struct RangeStart<T> {
range: Range<T>,
}
impl<T> RangeStart<T>
where
T: Clone,
{
/// Wrap the given range in a RangeStart.
///
/// Used in the BTreeMap to order the entries by the start of the range but
/// also remember the end of the range.
fn new(range: Range<T>) -> Self {
RangeStart { range }
}
/// An empty range with both endpoints at the start.
///
/// Used for queries into the BTreeMap, but never stored in the BTreeMap.
fn from_point(point: &T) -> Self {
RangeStart { range: Range { start: point.clone(), end: point.clone() } }
}
}
impl<T> Clone for RangeStart<T>
where
T: Clone,
{
fn clone(&self) -> Self {
RangeStart { range: self.range.clone() }
}
}
/// PartialEq according to the start of the Range.
impl<T> PartialEq for RangeStart<T>
where
T: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.range.start.eq(&other.range.start)
}
}
/// Eq according to the start of the Range.
impl<T> Eq for RangeStart<T> where T: Eq {}
/// PartialOrd according to the start of the Range.
impl<T> PartialOrd for RangeStart<T>
where
T: PartialOrd,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.range.start.partial_cmp(&other.range.start)
}
}
/// Ord according to the start of the Range.
impl<T> Ord for RangeStart<T>
where
T: Ord,
{
fn cmp(&self, other: &Self) -> Ordering {
self.range.start.cmp(&other.range.start)
}
}
/// A map from a range of keys to values.
///
/// At any given time, the map contains a set of non-overlapping, non-empty
/// ranges of type K that are associated with values of type V.
///
/// A given range can be split into two separate ranges if some of the
/// intermediate values are removed from the map of if another value is
/// inserted over the intermediate values. When that happens, the value
/// for the split range is cloned using the Clone trait.
///
/// Adjacent ranges are not merged. Even if the value is "the same" (for some
/// definition of "the same"), the ranges are kept separately.
///
/// Querying a point in the map returns not only the value stored at that point
/// but also the range that value occupies in the map.
pub struct RangeMap<K, V> {
map: BTreeMap<RangeStart<K>, V>,
}
impl<K, V> Default for RangeMap<K, V>
where
K: Ord + Clone,
V: Clone,
{
/// By default, a RangeMap is empty.
fn default() -> Self {
Self::new()
}
}
impl<K, V> RangeMap<K, V>
where
K: Ord + Clone,
V: Clone,
{
/// Returns an empty RangeMap.
pub fn new() -> Self {
RangeMap { map: BTreeMap::new() }
}
/// Returns the range (and associated value) that contains the given point,
/// if any.
///
/// At most one range and value can exist at a given point because the
/// ranges in the map are non-overlapping.
///
/// Empty ranges do not contain any points and therefore cannot be found
/// using this method. Rather than being stored in the map, values
/// associated with empty ranges are dropped.
pub fn get(&self, point: &K) -> Option<(&Range<K>, &V)> {
self.map
.range((Bound::Unbounded, Bound::Included(RangeStart::from_point(point))))
.next_back()
.filter(|(k, _)| k.range.contains(point))
.map(|(k, v)| (&k.range, v))
}
/// Returns the range (and associated mutable value) that contains the
/// given point, if any.
///
/// Similar to "get", but the value is returned as a mutable reference,
/// which lets the caller modify the value stored in the map.
pub fn get_mut(&mut self, point: &K) -> Option<(&Range<K>, &mut V)> {
self.map
.range_mut((Bound::Unbounded, Bound::Included(RangeStart::from_point(point))))
.next_back()
.filter(|(k, _)| k.range.contains(point))
.map(|(k, v)| (&k.range, v))
}
/// Inserts a range with the given value.
///
/// The keys included in the given range are now associated with the given
/// value. If those keys were previously associated with another value,
/// are no longer associated with that previous value.
///
/// This method can cause one or more values in the map to be dropped if
/// the all of the keys associated with those values are contained within
/// the given range.
pub fn insert(&mut self, range: Range<K>, value: V) {
if range.start < range.end {
self.remove(&range);
self.map.insert(RangeStart::new(range), value);
}
}
/// Remove the given range from the map.
///
/// The keys included in the given range are no longer associated with any
/// values.
///
/// This method can cause one or more values in the map to be dropped if
/// the all of the keys associated with those values are contained within
/// the given range.
pub fn remove(&mut self, range: &Range<K>) {
// If the given range is empty, there is nothing to do.
if range.end <= range.start {
return;
}
// Find the range (if any) that intersects the start of range.
//
// There can be at most one such range because we maintain the
// invariant that the ranges stored in the map are non-overlapping.
if let Some((old_range, v)) =
self.get(&range.start).map(|(range, v)| (range.clone(), v.clone()))
{
// Remove that range from the map.
self.remove_exact_range(&old_range);
// If the removed range extends after the end of the given range,
// re-insert the part of the old range that extends beyond the end
// of the given range.
if old_range.end > range.end {
self.insert_into_empty_range(range.end.clone()..old_range.end, v.clone());
}
// If the removed range extends before the start of the given
// range, re-insert the part of the old range that extends before
// the start of the given range.
if old_range.start < range.start {
self.insert_into_empty_range(old_range.start..range.start.clone(), v);
}
// Notice that we can end up splitting the old range into two
// separate ranges if the old range extends both beyond the given
// range and before the given range.
}
// Find the range (if any) that intersects the end of range.
//
// There can be at most one such range because we maintain the
// invariant that the ranges stored in the map are non-overlapping.
//
// We exclude the end of the given range because a range that starts
// exactly at the end of the given range does not overalp the given
// range.
if let Some((old_range, v)) = self
.map
.range((
Bound::Included(RangeStart::from_point(&range.start)),
Bound::Excluded(RangeStart::from_point(&range.end)),
))
.next_back()
.filter(|(k, _)| k.range.contains(&range.end))
.map(|(k, v)| (k.range.clone(), v.clone()))
{
// Remove that range from the map.
self.remove_exact_range(&old_range);
// If the removed range extends after the end of the given range,
// re-insert the part of the old range that extends beyond the end
// of the given range.
if old_range.end > range.end {
self.insert_into_empty_range(range.end.clone()..old_range.end, v);
}
}
// Remove any remaining ranges that are contained within the range.
//
// These ranges cannot possibly extend beyond the given range because
// we will have already removed them from the map at this point.
//
// We collect the doomed keys into a Vec to avoid mutating the map
// during the iteration.
let doomed: Vec<_> = self
.map
.range((
Bound::Included(RangeStart::from_point(&range.start)),
Bound::Excluded(RangeStart::from_point(&range.end)),
))
.map(|(k, _)| k.clone())
.collect();
for key in &doomed {
self.map.remove(key);
}
}
/// Iterate over the ranges in the map.
pub fn iter(&self) -> impl Iterator<Item = (&Range<K>, &V)> {
self.map.iter().map(|(k, value)| (&k.range, value))
}
/// Iterate over the ranges in the map, starting at the first range starting after or at the given point.
pub fn iter_starting_at(&self, point: &K) -> impl Iterator<Item = (&Range<K>, &V)> {
self.map
.range((Bound::Included(RangeStart::from_point(point)), Bound::Unbounded))
.map(|(k, value)| (&k.range, value))
}
/// Iterate over the ranges in the map that intersect the requested range.
pub fn intersection<R>(&self, range: R) -> impl Iterator<Item = (&Range<K>, &V)>
where
R: Borrow<Range<K>>,
{
let range = range.borrow();
let start = self.get(&range.start).map(|(r, _)| &r.start).unwrap_or(&range.start);
self.map
.range((
Bound::Included(RangeStart::from_point(start)),
Bound::Excluded(RangeStart::from_point(&range.end)),
))
.map(|(k, value)| (&k.range, value))
}
/// Associate the keys in the given range with the given value.
///
/// Callers must ensure that the keys in the given range are not already
/// associated with any values.
fn insert_into_empty_range(&mut self, range: Range<K>, value: V) {
self.map.insert(RangeStart::new(range), value);
}
/// Remove the given range from the map.
///
/// Callers must ensure that the exact range provided as an argument is
/// contained in the map.
fn remove_exact_range(&mut self, range: &Range<K>) {
self.map.remove(&RangeStart::new(range.clone()));
}
}
#[cfg(test)]
mod test {
use super::*;
#[::fuchsia::test]
fn test_empty() {
let mut map = RangeMap::<u32, i32>::new();
assert!(map.get(&12).is_none());
map.remove(&(10..34));
// This is a test to make sure we can handle reversed ranges
#[allow(clippy::reversed_empty_ranges)]
map.remove(&(34..10));
}
#[::fuchsia::test]
fn test_insert_into_empty() {
let mut map = RangeMap::<u32, i32>::new();
map.insert(10..34, -14);
assert_eq!((&(10..34), &-14), map.get(&12).unwrap());
assert_eq!((&(10..34), &-14), map.get(&10).unwrap());
assert_eq!((&(10..34), &mut -14), map.get_mut(&10).unwrap());
assert!(map.get(&9).is_none());
assert_eq!((&(10..34), &-14), map.get(&33).unwrap());
assert!(map.get(&34).is_none());
}
#[::fuchsia::test]
fn test_iter() {
let mut map = RangeMap::<u32, i32>::new();
map.insert(10..34, -14);
map.insert(74..92, -12);
let mut iter = map.iter();
assert_eq!(iter.next().expect("missing elem"), (&(10..34), &-14));
assert_eq!(iter.next().expect("missing elem"), (&(74..92), &-12));
assert!(iter.next().is_none());
let mut iter = map.iter_starting_at(&10);
assert_eq!(iter.next().expect("missing elem"), (&(10..34), &-14));
let mut iter = map.iter_starting_at(&11);
assert_eq!(iter.next().expect("missing elem"), (&(74..92), &-12));
let mut iter = map.iter_starting_at(&74);
assert_eq!(iter.next().expect("missing elem"), (&(74..92), &-12));
let mut iter = map.iter_starting_at(&75);
assert_eq!(iter.next(), None);
}
#[::fuchsia::test]
fn test_remove_overlapping_edge() {
let mut map = RangeMap::<u32, i32>::new();
map.insert(10..34, -14);
map.remove(&(2..11));
assert_eq!((&(11..34), &-14), map.get(&11).unwrap());
map.remove(&(33..42));
assert_eq!((&(11..33), &-14), map.get(&12).unwrap());
}
#[::fuchsia::test]
fn test_remove_middle_splits_range() {
let mut map = RangeMap::<u32, i32>::new();
map.insert(10..34, -14);
map.remove(&(15..18));
assert_eq!((&(10..15), &-14), map.get(&12).unwrap());
assert_eq!((&(18..34), &-14), map.get(&20).unwrap());
}
#[::fuchsia::test]
fn test_remove_upper_half_of_split_range_leaves_lower_range() {
let mut map = RangeMap::<u32, i32>::new();
map.insert(10..34, -14);
map.remove(&(15..18));
map.insert(2..7, -21);
map.remove(&(20..42));
assert_eq!((&(2..7), &-21), map.get(&5).unwrap());
assert_eq!((&(10..15), &-14), map.get(&12).unwrap());
}
#[::fuchsia::test]
fn test_range_map_overlapping_insert() {
let mut map = RangeMap::<u32, i32>::new();
map.insert(2..7, -21);
map.insert(5..9, -42);
map.insert(1..3, -43);
map.insert(6..8, -44);
assert_eq!((&(1..3), &-43), map.get(&2).unwrap());
assert_eq!((&(3..5), &-21), map.get(&4).unwrap());
assert_eq!((&(5..6), &-42), map.get(&5).unwrap());
assert_eq!((&(6..8), &-44), map.get(&7).unwrap());
}
#[::fuchsia::test]
fn test_intersect_single() {
let mut map = RangeMap::<u32, i32>::new();
map.insert(2..7, -10);
let mut iter = map.intersection(3..4);
assert_eq!(iter.next(), Some((&(2..7), &-10)));
assert_eq!(iter.next(), None);
let mut iter = map.intersection(2..3);
assert_eq!(iter.next(), Some((&(2..7), &-10)));
assert_eq!(iter.next(), None);
let mut iter = map.intersection(1..4);
assert_eq!(iter.next(), Some((&(2..7), &-10)));
assert_eq!(iter.next(), None);
let mut iter = map.intersection(1..2);
assert_eq!(iter.next(), None);
let mut iter = map.intersection(6..7);
assert_eq!(iter.next(), Some((&(2..7), &-10)));
assert_eq!(iter.next(), None);
}
#[::fuchsia::test]
fn test_intersect_multiple() {
let mut map = RangeMap::<u32, i32>::new();
map.insert(2..7, -10);
map.insert(7..9, -20);
map.insert(10..11, -30);
let mut iter = map.intersection(3..8);
assert_eq!(iter.next(), Some((&(2..7), &-10)));
assert_eq!(iter.next(), Some((&(7..9), &-20)));
assert_eq!(iter.next(), None);
let mut iter = map.intersection(3..11);
assert_eq!(iter.next(), Some((&(2..7), &-10)));
assert_eq!(iter.next(), Some((&(7..9), &-20)));
assert_eq!(iter.next(), Some((&(10..11), &-30)));
assert_eq!(iter.next(), None);
}
#[::fuchsia::test]
fn test_intersect_no_gaps() {
let mut map = RangeMap::<u32, i32>::new();
map.insert(0..1, -10);
map.insert(1..2, -20);
map.insert(2..3, -30);
let mut iter = map.intersection(0..3);
assert_eq!(iter.next(), Some((&(0..1), &-10)));
assert_eq!(iter.next(), Some((&(1..2), &-20)));
assert_eq!(iter.next(), Some((&(2..3), &-30)));
assert_eq!(iter.next(), None);
}
}