pub struct RangeSet<A: Array>(_);
Expand description

A set of non-overlapping ranges

let mut a: RangeSet2<i32> = RangeSet::from(10..);
let b: RangeSet2<i32> = RangeSet::from(1..5);

a |= b;
let r = !a;

A data structure to represent a set of non-overlapping ranges of element type T: RangeSetEntry. It uses a SmallVec<T> of sorted boundaries internally.

It can represent not just finite ranges but also ranges with unbounded end. Because it can represent infinite ranges, it can also represent the set of all elements, and therefore all boolean operations including negation.

Adjacent ranges will be merged.

It provides very fast operations for set operations (&, |, ^) as well as for intersection tests (is_disjoint, is_subset).

In addition to the fast set operations that produce a new range set, it also supports the equivalent in-place operations.

Complexity

Complexity is given separately for the number of comparisons and the number of copies, since sometimes you have a comparison operation that is basically free (any of the primitive types), whereas sometimes you have a comparison operation that is many orders of magnitude more expensive than a copy (long strings, arbitrary precision integers, …)

Number of comparisons

operationbestworstremark
negation1      O(N)    
unionO(log(N))O(N)binary merge
intersectionO(log(N))O(N)binary merge
differenceO(log(N))O(N)binary merge
xorO(log(N))O(N)binary merge
membershipO(log(N))O(log(N))binary search
is_disjointO(log(N))O(N)binary merge with cutoff
is_subsetO(log(N))O(N)binary merge with cutoff

Number of copies

For creating new sets, obviously there needs to be at least one copy for each element of the result set, so the complexity is always O(N). For in-place operations it gets more interesting. In case the number of elements of the result being identical to the number of existing elements, there will be no copies and no allocations.

E.g. if the result just has some of the ranges of the left hand side extended or truncated, but the same number of boundaries, there will be no allocations and no copies except for the changed boundaries themselves.

If the result has fewer boundaries than then lhs, there will be some copying but no allocations. Only if the result is larger than the capacity of the underlying vector of the lhs will there be allocations.

operationbestworst
negation1      1       
union1O(N)
intersection1O(N)
difference1O(N)
xor1O(N)

Testing

Testing is done by some simple smoke tests as well as quickcheck tests of the algebraic properties of the boolean operations.

Implementations§

source§

impl<T, A: Array<Item = T>> RangeSet<A>

source

pub fn new(boundaries: SmallVec<A>) -> Option<Self>where A::Item: Ord,

create a new range set from the given boundaries

This performs a check that the boundaries are strictly sorted. If you want to avoid this check, use new_unchecked (behind a feature flag because it is unsafe)

source

pub fn iter(&self) -> Iter<'_, T>

iterate over all ranges in this range set

source

pub fn into_inner(self) -> SmallVec<A>

get the boundaries in this range set as a SmallVec

source§

impl<T: RangeSetEntry, A: Array<Item = T>> RangeSet<A>

source

pub fn empty() -> Self

the empty range set

source

pub fn all() -> Self

a range set containing all values

source§

impl<T: RangeSetEntry + Clone, A: Array<Item = T>> RangeSet<A>

source

pub fn intersection_with(&mut self, that: &RangeSetRef<T>)

intersection in place

source

pub fn union_with(&mut self, that: &RangeSetRef<T>)

union in place

source

pub fn difference_with(&mut self, that: &RangeSetRef<T>)

difference in place

source

pub fn symmetric_difference_with(&mut self, that: &RangeSetRef<T>)

symmetric difference in place (xor)

Methods from Deref<Target = RangeSetRef<T>>§

source

pub fn split(&self, at: T) -> (&Self, &Self)where T: Ord,

Split this range set into two parts left, right at position at, so that left is identical to self for all x < at and right is identical to self for all x >= at.

More precisely: contains(left, x) == contains(ranges, x) for x < at contains(right, x) == contains(ranges, x) for x >= at

This is not the same as limiting the ranges to the left or right of at, but it is much faster. It requires just a binary search and no allocations.

source

pub fn boundaries(&self) -> &[T]

The boundaries of the range set, guaranteed to be strictly sorted

source

pub fn contains(&self, value: &T) -> boolwhere T: Ord,

true if the value is contained in the range set

source

pub fn is_empty(&self) -> bool

true if the range set is empty

source

pub fn is_all(&self) -> boolwhere T: RangeSetEntry,

true if the range set contains all values

source

pub fn intersects(&self, that: &RangeSetRef<T>) -> boolwhere T: Ord,

true if this range set intersects from another range set

This is just the opposite of is_disjoint, but is provided for better discoverability.

source

pub fn is_disjoint(&self, that: &RangeSetRef<T>) -> boolwhere T: Ord,

true if this range set is disjoint from another range set

source

pub fn is_subset(&self, that: &RangeSetRef<T>) -> boolwhere T: Ord,

true if this range set is a superset of another range set

A range set is considered to be a superset of itself

source

pub fn is_superset(&self, that: &RangeSetRef<T>) -> boolwhere T: Ord,

true if this range set is a subset of another range set

A range set is considered to be a subset of itself

source

pub fn iter(&self) -> Iter<'_, T>

iterate over all ranges in this range set

source

pub fn intersection<A>(&self, that: &RangeSetRef<T>) -> RangeSet<A>where A: Array<Item = T>, T: Ord + Clone,

intersection

source

pub fn union<A>(&self, that: &RangeSetRef<T>) -> RangeSet<A>where A: Array<Item = T>, T: Ord + Clone,

union

source

pub fn difference<A>(&self, that: &RangeSetRef<T>) -> RangeSet<A>where A: Array<Item = T>, T: Ord + Clone,

difference

source

pub fn symmetric_difference<A>(&self, that: &RangeSetRef<T>) -> RangeSet<A>where A: Array<Item = T>, T: Ord + Clone,

symmetric difference (xor)

Trait Implementations§

source§

impl<T, A: Array<Item = T>> AsRef<RangeSetRef<T>> for RangeSet<A>

source§

fn as_ref(&self) -> &RangeSetRef<T>

Converts this type into a shared reference of the (usually inferred) input type.
source§

impl<T: RangeSetEntry + Clone, A: Array<Item = T>> BitAnd<&RangeSet<A>> for &RangeSet<A>

compute the intersection of this range set with another, producing a new range set

∀ t ∈ T, r(t) = a(t) & b(t)

§

type Output = RangeSet<A>

The resulting type after applying the & operator.
source§

fn bitand(self, that: Self) -> Self::Output

Performs the & operation. Read more
source§

impl<T: Ord, A: Array<Item = T>> BitAndAssign<RangeSet<A>> for RangeSet<A>

source§

fn bitand_assign(&mut self, that: Self)

Performs the &= operation. Read more
source§

impl<T: RangeSetEntry + Clone, A: Array<Item = T>> BitOr<&RangeSet<A>> for &RangeSet<A>

compute the union of this range set with another, producing a new range set

∀ t ∈ T, r(t) = a(t) | b(t)

§

type Output = RangeSet<A>

The resulting type after applying the | operator.
source§

fn bitor(self, that: Self) -> Self::Output

Performs the | operation. Read more
source§

impl<T: Ord, A: Array<Item = T>> BitOrAssign<RangeSet<A>> for RangeSet<A>

source§

fn bitor_assign(&mut self, that: Self)

Performs the |= operation. Read more
source§

impl<T: RangeSetEntry + Clone, A: Array<Item = T>> BitXor<&RangeSet<A>> for &RangeSet<A>

compute the exclusive or of this range set with another, producing a new range set

∀ t ∈ T, r(t) = a(t) ^ b(t)

§

type Output = RangeSet<A>

The resulting type after applying the ^ operator.
source§

fn bitxor(self, that: Self) -> Self::Output

Performs the ^ operation. Read more
source§

impl<T: RangeSetEntry, A: Array<Item = T>> BitXorAssign<RangeSet<A>> for RangeSet<A>

source§

fn bitxor_assign(&mut self, that: Self)

Performs the ^= operation. Read more
source§

impl<T, A: Array<Item = T>> Borrow<RangeSetRef<T>> for RangeSet<A>

source§

fn borrow(&self) -> &RangeSetRef<T>

Immutably borrows from an owned value. Read more
source§

impl<A: Array> Clone for RangeSet<A>where A::Item: Clone,

source§

fn clone(&self) -> Self

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<T: Debug, A: Array<Item = T>> Debug for RangeSet<A>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<T, A: Array<Item = T>> Deref for RangeSet<A>

§

type Target = RangeSetRef<T>

The resulting type after dereferencing.
source§

fn deref(&self) -> &Self::Target

Dereferences the value.
source§

impl<T: RangeSetEntry, A: Array<Item = T>> From<Range<T>> for RangeSet<A>

source§

fn from(value: Range<T>) -> Self

Converts to this type from the input type.
source§

impl<T: RangeSetEntry, A: Array<Item = T>> From<RangeFrom<T>> for RangeSet<A>

source§

fn from(value: RangeFrom<T>) -> Self

Converts to this type from the input type.
source§

impl<T: RangeSetEntry, A: Array<Item = T>> From<RangeSetRange<T>> for RangeSet<A>

source§

fn from(value: RangeSetRange<T>) -> Self

Converts to this type from the input type.
source§

impl<T: RangeSetEntry, A: Array<Item = T>> From<RangeTo<T>> for RangeSet<A>

source§

fn from(value: RangeTo<T>) -> Self

Converts to this type from the input type.
source§

impl<T: RangeSetEntry, A: Array<Item = T>> From<bool> for RangeSet<A>

source§

fn from(value: bool) -> Self

Converts to this type from the input type.
source§

impl<T: RangeSetEntry + Clone, A: Array<Item = T>> Not for &RangeSet<A>

compute the negation of this range set

∀ t ∈ T, r(t) = !a(t)

§

type Output = RangeSet<A>

The resulting type after applying the ! operator.
source§

fn not(self) -> Self::Output

Performs the unary ! operation. Read more
source§

impl<T: RangeSetEntry + Clone, A: Array<Item = T>> Not for RangeSet<A>

compute the negation of this range set

∀ t ∈ T, r(t) = !a(t)

§

type Output = RangeSet<A>

The resulting type after applying the ! operator.
source§

fn not(self) -> Self::Output

Performs the unary ! operation. Read more
source§

impl<A: Array, R: AsRef<RangeSetRef<A::Item>>> PartialEq<R> for RangeSet<A>where A::Item: RangeSetEntry,

source§

fn eq(&self, that: &R) -> bool

This method tests for self and other values to be equal, and is used by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
source§

impl<T: RangeSetEntry + Clone, A: Array<Item = T>> Sub<&RangeSet<A>> for &RangeSet<A>

compute the difference of this range set with another, producing a new range set

∀ t ∈ T, r(t) = a(t) & !b(t)

§

type Output = RangeSet<A>

The resulting type after applying the - operator.
source§

fn sub(self, that: Self) -> Self::Output

Performs the - operation. Read more
source§

impl<T: Ord, A: Array<Item = T>> SubAssign<RangeSet<A>> for RangeSet<A>

source§

fn sub_assign(&mut self, that: Self)

Performs the -= operation. Read more
source§

impl<A: Array> Eq for RangeSet<A>where A::Item: Eq + RangeSetEntry,

Auto Trait Implementations§

§

impl<A> RefUnwindSafe for RangeSet<A>where A: RefUnwindSafe, <A as Array>::Item: RefUnwindSafe,

§

impl<A> Send for RangeSet<A>where <A as Array>::Item: Send,

§

impl<A> Sync for RangeSet<A>where A: Sync,

§

impl<A> Unpin for RangeSet<A>where A: Unpin,

§

impl<A> UnwindSafe for RangeSet<A>where A: UnwindSafe, <A as Array>::Item: RefUnwindSafe,

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for Twhere U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> ToOwned for Twhere T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for Twhere U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.