Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "iset"
version = "0.1.1"
authors = ["Timofey Prodanov <timofey.prodanov@gmail.com>"]
edition = "2018"
edition = "2021"
description = "Map and set with interval keys (x..y)."
repository = "https://github.com/tprodanov/iset"
readme = "README.md"
Expand All @@ -26,5 +26,5 @@ rand = "0.8"
serde_json = "1.0"

[features]
default = ["dot"]
default = ["dot", "serde"]
dot = []
204 changes: 158 additions & 46 deletions src/iter.rs
Original file line number Diff line number Diff line change
@@ -1,38 +1,44 @@
//! Module with various iterators over `IntervalMap` and `IntervalSet`.

use alloc::vec::Vec;
use core::ops::{Range, RangeBounds, Bound};
use core::iter::FusedIterator;
use core::mem;
use core::ops::{Bound, Range, RangeBounds};

use super::{IntervalMap, Node, IndexType, check_ordered, BitVec};
use super::{check_ordered, BitVec, IndexType, IntervalMap, Node};

fn should_go_left<T, V, Ix>(nodes: &[Node<T, V, Ix>], index: Ix, start_bound: Bound<&T>) -> bool
where T: PartialOrd + Copy,
Ix: IndexType,
where
T: PartialOrd + Copy,
Ix: IndexType,
{
if !nodes[index.get()].left.defined() {
return false;
}
let left_end = nodes[nodes[index.get()].left.get()].subtree_interval.end;
match start_bound {
Bound::Included(&value) | Bound::Excluded(&value) => left_end >= value,
Bound::Unbounded => true,
match nodes[index.get()].left {
None => false,
Some(left) => {
let left_end = nodes[left.get()].subtree_interval.end;
match start_bound {
Bound::Included(&value) | Bound::Excluded(&value) => left_end >= value,
Bound::Unbounded => true,
}
}
}
}

fn should_go_right<T, V, Ix>(nodes: &[Node<T, V, Ix>], index: Ix, end_bound: Bound<&T>) -> bool
where T: PartialOrd + Copy,
Ix: IndexType,
where
T: PartialOrd + Copy,
Ix: IndexType,
{
if !nodes[index.get()].right.defined() {
return false;
}
let right_start = nodes[nodes[index.get()].right.get()].subtree_interval.start;
match end_bound {
Bound::Included(&value) => right_start <= value,
Bound::Excluded(&value) => right_start < value,
Bound::Unbounded => true,
match nodes[index.get()].right {
None => false,
Some(right) => {
let right_start = nodes[right.get()].subtree_interval.start;
match end_bound {
Bound::Included(&value) => right_start <= value,
Bound::Excluded(&value) => right_start < value,
Bound::Unbounded => true,
}
}
}
}

Expand All @@ -45,7 +51,7 @@ impl ActionStack {
}

#[inline]
fn push(& mut self) {
fn push(&mut self) {
self.0.push(false);
self.0.push(false);
}
Expand Down Expand Up @@ -94,38 +100,44 @@ impl ActionStack {
}
}

fn move_to_next<T, V, R, Ix>(nodes: &[Node<T, V, Ix>], mut index: Ix, range: &R, stack: &mut ActionStack) -> Ix
where T: PartialOrd + Copy,
R: RangeBounds<T>,
Ix: IndexType,
fn move_to_next<T, V, R, Ix>(
nodes: &[Node<T, V, Ix>],
mut index_opt: Option<Ix>,
range: &R,
stack: &mut ActionStack,
) -> Option<Ix>
where
T: PartialOrd + Copy,
R: RangeBounds<T>,
Ix: IndexType,
{
while index.defined() {
while let Some(mut index) = index_opt {
if stack.can_go_left() {
while should_go_left(nodes, index, range.start_bound()) {
stack.go_left();
stack.push();
index = nodes[index.get()].left;
index = nodes[index.get()].left.unwrap();
}
stack.go_left();
}

if stack.can_match() {
stack.make_match();
if nodes[index.get()].interval.intersects_range(range) {
return index;
return Some(index);
}
}

if stack.can_go_right() && should_go_right(nodes, index, range.end_bound()) {
stack.go_right();
stack.push();
index = nodes[index.get()].right;
index_opt = nodes[index.get()].right;
} else {
stack.pop();
index = nodes[index.get()].parent;
index_opt = nodes[index.get()].parent;
}
}
index
None
}

/// Macro that generates Iterator over IntervalMap.
Expand All @@ -141,7 +153,7 @@ macro_rules! iterator {
R: RangeBounds<T>,
Ix: IndexType,
{
pub(crate) index: Ix,
pub(crate) index: Option<Ix>,
range: R,
nodes: &'a $( $mut_ )? [Node<T, V, Ix>],
stack: ActionStack,
Expand All @@ -164,12 +176,10 @@ macro_rules! iterator {

fn next(&mut self) -> Option<Self::Item> {
self.index = move_to_next(self.nodes, self.index, &self.range, &mut self.stack);
if !self.index.defined() {
None
} else {
let $node = & $( $mut_ )? self.nodes[self.index.get()];
Some($out)
}
self.index.map(|index| {
let $node = & $( $mut_ )? self.nodes[index.get()];
$out
})
}

fn size_hint(& self) -> (usize, Option<usize>) {
Expand Down Expand Up @@ -217,6 +227,110 @@ iterator! {
node -> unsafe { &mut *(&mut node.value as *mut V) }, { mut }
}

/*
#[doc = "Iterator over values equal to range."]
#[derive(Clone, Debug)]
pub struct EqualValues<'a, T, V, Ix>
where
T: PartialOrd + Copy,
Ix: IndexType,
{
pub(crate) index: Ix,
interval: Interval<T>,
nodes: &'a [Node<T, V, Ix>],
stack: ActionStack,
}
impl<'a, T: PartialOrd + Copy, V, Ix: IndexType> EqualValues<'a, T, V, Ix> {
pub(crate) fn new(tree: &'a IntervalMap<T, V, Ix>, interval: Interval<T>) -> Self {
check_ordered(&interval);
Self {
index: tree.root,
interval,
nodes: &tree.nodes,
stack: ActionStack::new(),
}
}
fn should_go_left(nodes: &[Node<T, V, Ix>], index: Ix, interval: &R) -> bool {
if !nodes[index.get()].left.defined() {
return false;
}
let node = &nodes[nodes[index.get()].left.get()];
match interval.cmp(&node.interval) {
Ordering::Less => true,
Ordering::Greater => false,
Ordering::Equal => true,
}
let left_end = nodes[nodes[index.get()].left.get()].subtree_interval.end;
match start_bound {
Bound::Included(&value) | Bound::Excluded(&value) => left_end >= value,
Bound::Unbounded => true,
}
}
fn should_go_right(nodes: &[Node<T, V, Ix>], index: Ix, interval: &R) -> bool {
if !nodes[index.get()].right.defined() {
return false;
}
nodes[nodes[index.get()].right.get()].interval <= interval
}

fn move_to_next(
nodes: &[Node<T, V, Ix>],
mut index: Ix,
interval: &R,
stack: &mut ActionStack,
) -> Ix
where
T: PartialOrd + Copy,
R: RangeBounds<T>,
Ix: IndexType,
{
while index.defined() {
if stack.can_go_left() {
while Self::should_go_left(nodes, index, interval) {
stack.go_left();
stack.push();
index = nodes[index.get()].left;
}
stack.go_left();
}

if stack.can_match() {
stack.make_match();
if nodes[index.get()].interval == interval {
return index;
}
}

if stack.can_go_right() && should_go_right(nodes, index, interval.end_bound()) {
stack.go_right();
stack.push();
index = nodes[index.get()].right;
} else {
stack.pop();
index = nodes[index.get()].parent;
}
}
index
}
}
impl<'a, T: PartialOrd + Copy, V, Ix: IndexType> Iterator for EqualValues<'a, T, V, Ix> {
type Item = &'a V;
fn next(&mut self) -> Option<Self::Item> {
self.index = Self::move_to_next(self.nodes, self.index, &self.interval, &mut self.stack);
if !self.index.defined() {
None
} else {
let node = &self.nodes[self.index.get()];
Some(&node.value)
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(self.nodes.len()))
}
}
impl<'a, T: PartialOrd + Copy, V, Ix: IndexType> FusedIterator for EqualValues<'a, T, V, Ix> {}
*/

/// Macro that generates IntoIterator over IntervalMap.
macro_rules! into_iterator {
(
Expand All @@ -230,7 +344,7 @@ macro_rules! into_iterator {
R: RangeBounds<T>,
Ix: IndexType,
{
index: Ix,
index: Option<Ix>,
range: R,
nodes: Vec<Node<T, V, Ix>>,
stack: ActionStack,
Expand All @@ -253,12 +367,10 @@ macro_rules! into_iterator {

fn next(&mut self) -> Option<Self::Item> {
self.index = move_to_next(&self.nodes, self.index, &self.range, &mut self.stack);
if !self.index.defined() {
None
} else {
let $node = &mut self.nodes[self.index.get()];
Some($out)
}
self.index.map(|index| {
let $node = &mut self.nodes[index.get()];
$out
})
}

fn size_hint(& self) -> (usize, Option<usize>) {
Expand Down
59 changes: 23 additions & 36 deletions src/ix.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Wrapper around integer types, used as indices within `IntervalMap` and `IntervalSet`.

use core::convert::TryInto;
use core::fmt::Display;

/// Trait for index types: used in the inner representation of [IntervalMap](../struct.IntervalMap.html) and
Expand All @@ -13,60 +14,46 @@ use core::fmt::Display;
///
/// Using smaller index types saves memory and slightly reduces running time.
pub trait IndexType: Copy + Display + Sized + Eq + Ord {
/// Undefined index. There can be no indices higher than MAX.
const MAX: Self;

/// Converts index into `usize`.
fn get(self) -> usize;

/// Creates a new index. Returns error if the `elemen_num` is too big.
fn new(element_num: usize) -> Result<Self, &'static str>;

/// Returns `true` if the index is defined.
#[inline(always)]
fn defined(self) -> bool {
self != Self::MAX
}
}

macro_rules! index_error {
(u64) => {
"Failed to insert a new element into IntervalMap/Set: number of elements is too large for u64."
};
($name:ident) => {
concat!(
"Failed to insert a new element into IntervalMap/Set: number of elements is too large for ",
stringify!($name),
", try using u64.")
};
}

macro_rules! impl_index {
($type:ident) => {
impl IndexType for $type {
const MAX: Self = core::$type::MAX;

impl IndexType for core::num::$type {
#[inline(always)]
fn get(self) -> usize {
self as usize
(self.get() - 1) as usize
}

#[inline]
fn new(element_num: usize) -> Result<Self, &'static str> {
let element_num = element_num as $type;
if element_num == core::$type::MAX {
Err(index_error!($type))
} else {
Ok(element_num as $type)
}
const ERROR_STR :&'static str=
concat!(
"Failed to insert a new element into IntervalMap/Set: number of elements is too large for ",
stringify!($type),
", try using NonZeroU64.");
let nonzero = core::num::$type::new(
element_num
.checked_add(1)
.ok_or(ERROR_STR)?
.try_into()
.map_err(|_| ERROR_STR)?,
)
.ok_or(ERROR_STR)?;
Ok(nonzero)
}
}
};
}

impl_index!(u8);
impl_index!(u16);
impl_index!(u32);
impl_index!(u64);
impl_index!(NonZeroU8);
impl_index!(NonZeroU16);
impl_index!(NonZeroU32);
impl_index!(NonZeroU64);
impl_index!(NonZeroUsize);
/// Default index type.
pub type DefaultIx = u32;
pub type DefaultIx = core::num::NonZeroU32;
Loading