Skip to content

Commit

Permalink
feat: add some iter types
Browse files Browse the repository at this point in the history
Signed-off-by: feathercyc <[email protected]>
  • Loading branch information
GG2002 committed Aug 20, 2024
1 parent 2caee42 commit 920d6c0
Show file tree
Hide file tree
Showing 4 changed files with 440 additions and 33 deletions.
96 changes: 65 additions & 31 deletions benches/bench.rs
Original file line number Diff line number Diff line change
@@ -1,44 +1,24 @@
use criterion::{criterion_group, criterion_main, Bencher, Criterion};
use interval_map::{Interval, IntervalMap};
use rand::{rngs::StdRng, Rng, SeedableRng};
use std::hint::black_box;

struct Rng {
state: u32,
}
impl Rng {
fn new() -> Self {
Self { state: 0x87654321 }
}

fn gen_u32(&mut self) -> u32 {
self.state ^= self.state << 13;
self.state ^= self.state >> 17;
self.state ^= self.state << 5;
self.state
}

fn gen_range_i32(&mut self, low: i32, high: i32) -> i32 {
let d = (high - low) as u32;
low + (self.gen_u32() % d) as i32
}
}

struct IntervalGenerator {
rng: Rng,
limit: i32,
rng: StdRng,
limit: u32,
}
impl IntervalGenerator {
fn new() -> Self {
const LIMIT: i32 = 100000;
const LIMIT: u32 = 1000;
Self {
rng: Rng::new(),
rng: StdRng::from_seed([0; 32]),
limit: LIMIT,
}
}

fn next(&mut self) -> Interval<i32> {
let low = self.rng.gen_range_i32(0, self.limit - 1);
let high = self.rng.gen_range_i32(low + 1, self.limit);
fn next(&mut self) -> Interval<u32> {
let low = self.rng.gen_range(0..=self.limit - 1);
let high = self.rng.gen_range(low + 1..=self.limit);
Interval::new(low, high)
}
}
Expand Down Expand Up @@ -100,14 +80,68 @@ fn bench_interval_map_insert_remove(c: &mut Criterion) {
});
}

// FilterIter helper fn
fn interval_map_filter_iter(count: usize, bench: &mut Bencher) {
let mut gen = IntervalGenerator::new();
let intervals: Vec<_> = std::iter::repeat_with(|| gen.next()).take(count).collect();
let mut map = IntervalMap::new();
for i in intervals.clone() {
map.insert(i, ());
}
bench.iter(|| {
for i in intervals.clone() {
black_box(map.filter_iter(&i).collect::<Vec<_>>());
}
});
}

// iter().filter() helper fn
fn interval_map_iter_filter(count: usize, bench: &mut Bencher) {
let mut gen = IntervalGenerator::new();
let intervals: Vec<_> = std::iter::repeat_with(|| gen.next()).take(count).collect();
let mut map = IntervalMap::new();
for i in intervals.clone() {
map.insert(i, ());
}
bench.iter(|| {
for i in intervals.clone() {
black_box(map.iter().filter(|v| v.0.overlaps(&i)).collect::<Vec<_>>());
}
});
}

fn bench_interval_map_filter_iter(c: &mut Criterion) {
c.bench_function("bench_interval_map_filter_iter_100", |b| {
interval_map_filter_iter(100, b)
});
c.bench_function("bench_interval_map_filter_iter_1000", |b| {
interval_map_filter_iter(1000, b)
});
}

fn bench_interval_map_iter_filter(c: &mut Criterion) {
c.bench_function("bench_interval_map_iter_filter_100", |b| {
interval_map_iter_filter(100, b)
});
c.bench_function("bench_interval_map_iter_filter_1000", |b| {
interval_map_iter_filter(1000, b)
});
}

fn criterion_config() -> Criterion {
Criterion::default().configure_from_args().without_plots()
}

criterion_group! {
name = benches;
name = benches_basic_op;
config = criterion_config();
targets = bench_interval_map_insert, bench_interval_map_insert_remove,
}

criterion_group! {
name = benches_iter;
config = criterion_config();
targets = bench_interval_map_insert, bench_interval_map_insert_remove
targets = bench_interval_map_filter_iter, bench_interval_map_iter_filter
}

criterion_main!(benches);
criterion_main!(benches_basic_op, benches_iter);
123 changes: 121 additions & 2 deletions src/intervalmap.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::entry::{Entry, OccupiedEntry, VacantEntry};
use crate::index::{DefaultIx, IndexType, NodeIndex};
use crate::interval::{Interval, IntervalRef};
use crate::iter::{FilterIter, IntoIter, Iter, UnsortedIter};
use crate::node::{Color, Node};

use std::collections::VecDeque;
Expand Down Expand Up @@ -69,7 +70,7 @@ where
// check for max capacity, except if we use usize
assert!(
<Ix as IndexType>::max().index() == !0
|| <NodeIndex<Ix> as IndexType>::max() != node_idx,
|| <NodeIndex<_> as IndexType>::max() != node_idx,
"Reached maximum number of nodes"
);
self.nodes.push(node);
Expand Down Expand Up @@ -126,6 +127,10 @@ where
!self.node_ref(node_idx, Node::is_sentinel)
}

/// When `interval_map.len() < Self::BFS_MIN_THRESHOLD`, directly traversing the inner vec of `interval_map`
/// is faster than BFS.
const BFS_MIN_THRESHOLD: usize = 20;

/// Find all intervals in the map that overlaps with the given interval.
///
/// # Note
Expand All @@ -146,10 +151,45 @@ where
/// ```
#[inline]
pub fn find_all_overlap(&self, interval: &Interval<T>) -> Vec<(&Interval<T>, &V)> {
if self.node_ref(self.root, Node::is_sentinel) {
return Vec::new();
}
if self.len() > Self::BFS_MIN_THRESHOLD {
self.find_all_overlap_inner(self.root, interval)
} else {
self.unsorted_iter()
.filter(|v| v.0.overlaps(interval))
.collect()
}
}

/// Find all intervals in the map that overlaps with the given interval.
///
/// # Note
/// This method's returned data is ordered. Generally, it's much slower than `find_all_overlap`.
///
/// # Example
/// ```rust
/// use interval_map::{Interval, IntervalMap};
///
/// let mut map = IntervalMap::new();
/// map.insert(Interval::new(1, 3), ());
/// map.insert(Interval::new(2, 4), ());
/// map.insert(Interval::new(6, 7), ());
/// map.insert(Interval::new(7, 11), ());
/// assert_eq!(map.find_all_overlap(&Interval::new(2, 7)).len(), 3);
/// map.remove(&Interval::new(1, 3));
/// assert_eq!(map.find_all_overlap(&Interval::new(2, 7)).len(), 2);
/// ```
#[inline]
pub fn find_all_overlap_ordered<'a>(
&'a self,
interval: &'a Interval<T>,
) -> Vec<(&Interval<T>, &V)> {
if self.node_ref(self.root, Node::is_sentinel) {
Vec::new()
} else {
self.find_all_overlap_inner(self.root, interval)
self.filter_iter(interval).collect()
}
}

Expand Down Expand Up @@ -189,6 +229,70 @@ where
.map(|idx| self.node_mut(idx, Node::value_mut))
}

/// Get an iterator over the entries of the map, sorted by key.
#[inline]
#[must_use]
pub fn iter(&self) -> Iter<'_, T, V, Ix> {
Iter::new(self)
}

/// Get an iterator over the entries of the map, unsorted.
#[inline]
pub fn unsorted_iter(&self) -> UnsortedIter<T, V, Ix> {
UnsortedIter::new(self)
}

/// Get an iterator over the entries that overlap the `query`, sorted by key.
///
/// # Panics
///
/// The method panics when `query` contains a value that cannot be compared.
#[inline]
pub fn filter_iter<'a, 'b: 'a>(&'a self, query: &'b Interval<T>) -> FilterIter<T, V, Ix> {
FilterIter::new(self, query)
}

/// Return true if the interval tree's key cover the entire given interval.
///
/// # Example
/// ```rust
/// use interval_map::{Interval, IntervalMap};
///
/// let mut map = IntervalMap::new();
/// map.insert(Interval::new(3, 5), 0);
/// map.insert(Interval::new(5, 8), 1);
/// map.insert(Interval::new(9, 12), 1);
/// assert!(map.contains(&Interval::new(4, 6)));
/// assert!(!map.contains(&Interval::new(7, 10)));
/// ```
#[inline]
pub fn contains(&self, interval: &Interval<T>) -> bool {
let mut max_end: Option<&T> = None;
let mut min_begin: Option<&T> = None;

let mut continuous = true;
self.filter_iter(interval).find(|v| {
if min_begin.is_none() {
min_begin = Some(&v.0.low);
max_end = Some(&v.0.high);
return false;
}
if max_end.map(|mv| mv < &v.0.low).unwrap() {
continuous = false;
return true;
}
if max_end.map(|mv| mv < &v.0.high).unwrap() {
max_end = Some(&v.0.high);
}
false
});

continuous
&& min_begin.is_some()
&& max_end.map(|mv| mv >= &interval.high).unwrap()
&& min_begin.map(|mv| mv <= &interval.low).unwrap()
}

/// Get the given key's corresponding entry in the map for in-place manipulation.
///
/// # Example
Expand Down Expand Up @@ -241,6 +345,21 @@ where
}
}

impl<T, V, Ix> IntoIterator for IntervalMap<T, V, Ix>
where
T: Ord,
Ix: IndexType,
{
type Item = (Interval<T>, V);

type IntoIter = IntoIter<T, V, Ix>;

/// Get an into iterator over the entries of the map, sorted by key.
fn into_iter(self) -> Self::IntoIter {
IntoIter::new(self)
}
}

impl<T, V> IntervalMap<T, V>
where
T: Ord,
Expand Down
Loading

0 comments on commit 920d6c0

Please sign in to comment.