Skip to content

Commit

Permalink
Allow the overlapping() function to take ranges by value
Browse files Browse the repository at this point in the history
Instead of forcing the user of the API to pass a range by reference,
which causes the resulting iterator to have a lifetime which depends on
this reference, the `Borrow` trait is used to give the user a choice to
use either a reference or pass the range by value. The lifetime of the
iterator accordingly depends on which of the two is chosen.
  • Loading branch information
xfbs committed Jan 30, 2024
1 parent b9add4f commit 252dedd
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 26 deletions.
38 changes: 29 additions & 9 deletions src/inclusive_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use super::range_wrapper::RangeInclusiveStartWrapper;
use crate::range_wrapper::RangeInclusiveEndWrapper;
use crate::std_ext::*;
use alloc::collections::BTreeMap;
use core::borrow::Borrow;
use core::cmp::Ordering;
use core::fmt::{self, Debug};
use core::iter::FromIterator;
Expand Down Expand Up @@ -527,11 +528,12 @@ where

/// Gets an iterator over all the stored ranges that are
/// either partially or completely overlapped by the given range.
pub fn overlapping<'a>(&'a self, range: &'a RangeInclusive<K>) -> Overlapping<K, V> {
pub fn overlapping<R: Borrow<RangeInclusive<K>>>(&self, range: R) -> Overlapping<K, V, R> {
// Find the first matching stored range by its _end_,
// using sneaky layering and `Borrow` implementation. (See `range_wrappers` module.)
let start_sliver =
RangeInclusiveEndWrapper::new(range.start().clone()..=range.start().clone());
let start_sliver = RangeInclusiveEndWrapper::new(
range.borrow().start().clone()..=range.borrow().start().clone(),
);
let btm_range_iter = self
.btm
.range::<RangeInclusiveEndWrapper<K>, RangeFrom<&RangeInclusiveEndWrapper<K>>>(
Expand Down Expand Up @@ -811,23 +813,26 @@ where
/// documentation for more.
///
/// [`overlapping`]: RangeInclusiveMap::overlapping
pub struct Overlapping<'a, K, V> {
query_range: &'a RangeInclusive<K>,
pub struct Overlapping<'a, K, V, R: Borrow<RangeInclusive<K>> = &'a RangeInclusive<K>> {
query_range: R,
btm_range_iter: alloc::collections::btree_map::Range<'a, RangeInclusiveStartWrapper<K>, V>,
}

// `Overlapping` is always fused. (See definition of `next` below.)
impl<'a, K, V> core::iter::FusedIterator for Overlapping<'a, K, V> where K: Ord + Clone {}
impl<'a, K, V, R: Borrow<RangeInclusive<K>>> core::iter::FusedIterator for Overlapping<'a, K, V, R> where
K: Ord + Clone
{
}

impl<'a, K, V> Iterator for Overlapping<'a, K, V>
impl<'a, K, V, R: Borrow<RangeInclusive<K>>> Iterator for Overlapping<'a, K, V, R>
where
K: Ord + Clone,
{
type Item = (&'a RangeInclusive<K>, &'a V);

fn next(&mut self) -> Option<Self::Item> {
if let Some((k, v)) = self.btm_range_iter.next() {
if k.start() <= self.query_range.end() {
if k.start() <= self.query_range.borrow().end() {
Some((&k.range, v))
} else {
// The rest of the items in the underlying iterator
Expand Down Expand Up @@ -1503,7 +1508,7 @@ mod tests {
// Overlapping tests

#[test]
fn overlapping_with_empty_map() {
fn overlapping_ref_with_empty_map() {
// 0 1 2 3 4 5 6 7 8 9
// ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌
let range_map: RangeInclusiveMap<u32, ()> = RangeInclusiveMap::new();
Expand All @@ -1517,6 +1522,21 @@ mod tests {
assert_eq!(overlapping.next(), None);
}

#[test]
fn overlapping_owned_with_empty_map() {
// 0 1 2 3 4 5 6 7 8 9
// ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌
let range_map: RangeInclusiveMap<u32, ()> = RangeInclusiveMap::new();
// 0 1 2 3 4 5 6 7 8 9
// ◌ ◆-------------◆ ◌
let query_range = 1..=8;
let mut overlapping = range_map.overlapping(query_range);
// Should not yield any items.
assert_eq!(overlapping.next(), None);
// Gaps iterator should be fused.
assert_eq!(overlapping.next(), None);
}

#[test]
fn overlapping_partial_edges_complete_middle() {
let mut range_map: RangeInclusiveMap<u32, ()> = RangeInclusiveMap::new();
Expand Down
14 changes: 9 additions & 5 deletions src/inclusive_set.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use core::borrow::Borrow;
use core::cmp::Ordering;
use core::fmt::{self, Debug};
use core::iter::FromIterator;
Expand Down Expand Up @@ -189,7 +190,7 @@ where
/// either partially or completely overlapped by the given range.
///
/// The iterator element type is `RangeInclusive<T>`.
pub fn overlapping<'a>(&'a self, range: &'a RangeInclusive<T>) -> Overlapping<T> {
pub fn overlapping<R: Borrow<RangeInclusive<T>>>(&self, range: R) -> Overlapping<T, R> {
Overlapping {
inner: self.rm.overlapping(range),
}
Expand Down Expand Up @@ -393,14 +394,17 @@ where
/// documentation for more.
///
/// [`overlapping`]: RangeInclusiveSet::overlapping
pub struct Overlapping<'a, T> {
inner: crate::inclusive_map::Overlapping<'a, T, ()>,
pub struct Overlapping<'a, T, R: Borrow<RangeInclusive<T>> = &'a RangeInclusive<T>> {
inner: crate::inclusive_map::Overlapping<'a, T, (), R>,
}

// `Overlapping` is always fused. (See definition of `next` below.)
impl<'a, T> core::iter::FusedIterator for Overlapping<'a, T> where T: Ord + Clone {}
impl<'a, T, R: Borrow<RangeInclusive<T>>> core::iter::FusedIterator for Overlapping<'a, T, R> where
T: Ord + Clone
{
}

impl<'a, T> Iterator for Overlapping<'a, T>
impl<'a, T, R: Borrow<RangeInclusive<T>>> Iterator for Overlapping<'a, T, R>
where
T: Ord + Clone,
{
Expand Down
19 changes: 12 additions & 7 deletions src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use super::range_wrapper::RangeStartWrapper;
use crate::range_wrapper::RangeEndWrapper;
use crate::std_ext::*;
use alloc::collections::BTreeMap;
use core::borrow::Borrow;
use core::cmp::Ordering;
use core::fmt::{self, Debug};
use core::iter::FromIterator;
Expand Down Expand Up @@ -177,10 +178,11 @@ where

/// Gets an iterator over all the stored ranges that are
/// either partially or completely overlapped by the given range.
pub fn overlapping<'a>(&'a self, range: &'a Range<K>) -> Overlapping<K, V> {
pub fn overlapping<R: Borrow<Range<K>>>(&self, range: R) -> Overlapping<K, V, R> {
// Find the first matching stored range by its _end_,
// using sneaky layering and `Borrow` implementation. (See `range_wrappers` module.)
let start_sliver = RangeEndWrapper::new(range.start.clone()..range.start.clone());
let start_sliver =
RangeEndWrapper::new(range.borrow().start.clone()..range.borrow().start.clone());
let btm_range_iter = self
.btm
.range::<RangeEndWrapper<K>, (Bound<&RangeEndWrapper<K>>, Bound<_>)>((
Expand Down Expand Up @@ -706,23 +708,26 @@ where
/// documentation for more.
///
/// [`overlapping`]: RangeMap::overlapping
pub struct Overlapping<'a, K, V> {
query_range: &'a Range<K>,
pub struct Overlapping<'a, K, V, R: Borrow<Range<K>> = &'a Range<K>> {
query_range: R,
btm_range_iter: alloc::collections::btree_map::Range<'a, RangeStartWrapper<K>, V>,
}

// `Overlapping` is always fused. (See definition of `next` below.)
impl<'a, K, V> core::iter::FusedIterator for Overlapping<'a, K, V> where K: Ord {}
impl<'a, K, V, R: Borrow<Range<K>>> core::iter::FusedIterator for Overlapping<'a, K, V, R> where
K: Ord
{
}

impl<'a, K, V> Iterator for Overlapping<'a, K, V>
impl<'a, K, V, R: Borrow<Range<K>>> Iterator for Overlapping<'a, K, V, R>
where
K: Ord,
{
type Item = (&'a Range<K>, &'a V);

fn next(&mut self) -> Option<Self::Item> {
if let Some((k, v)) = self.btm_range_iter.next() {
if k.start < self.query_range.end {
if k.start < self.query_range.borrow().end {
Some((&k.range, v))
} else {
// The rest of the items in the underlying iterator
Expand Down
14 changes: 9 additions & 5 deletions src/set.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use core::borrow::Borrow;
use core::cmp::Ordering;
use core::fmt::{self, Debug};
use core::iter::FromIterator;
Expand Down Expand Up @@ -163,7 +164,7 @@ where
/// either partially or completely overlapped by the given range.
///
/// The iterator element type is `&Range<T>`.
pub fn overlapping<'a>(&'a self, range: &'a Range<T>) -> Overlapping<T> {
pub fn overlapping<R: Borrow<Range<T>>>(&self, range: R) -> Overlapping<T, R> {
Overlapping {
inner: self.rm.overlapping(range),
}
Expand Down Expand Up @@ -361,14 +362,17 @@ where
/// documentation for more.
///
/// [`overlapping`]: RangeSet::overlapping
pub struct Overlapping<'a, T> {
inner: crate::map::Overlapping<'a, T, ()>,
pub struct Overlapping<'a, T, R: Borrow<Range<T>> = &'a Range<T>> {
inner: crate::map::Overlapping<'a, T, (), R>,
}

// `Overlapping` is always fused. (See definition of `next` below.)
impl<'a, T> core::iter::FusedIterator for Overlapping<'a, T> where T: Ord + Clone {}
impl<'a, T, R: Borrow<Range<T>>> core::iter::FusedIterator for Overlapping<'a, T, R> where
T: Ord + Clone
{
}

impl<'a, T> Iterator for Overlapping<'a, T>
impl<'a, T, R: Borrow<Range<T>>> Iterator for Overlapping<'a, T, R>
where
T: Ord + Clone,
{
Expand Down

0 comments on commit 252dedd

Please sign in to comment.