#![deny(missing_docs)]
#![cfg_attr(coverage_nightly, feature(coverage_attribute))]
#![cfg_attr(not(test), no_std)]
extern crate alloc;
use smallvec::SmallVec;
mod complement;
mod intersection;
mod intersection_iterator;
pub mod iterator_wrapper;
mod normalize;
mod overloads;
mod primitive_endpoint;
mod range_case;
mod range_vec;
mod slice_sequence;
mod union;
mod union_iterator;
pub use range_case::RangeCase;
pub use range_vec::RangeVec;
pub use normalize::is_normalized;
pub use normalize::normalize_vec;
pub use complement::complement_vec;
pub use intersection::intersect_vec;
pub use union::union_vec;
pub const INLINE_SIZE: usize = if cfg!(feature = "inline_storage") {
2
} else {
0
};
type Backing<T> = SmallVec<[(T, T); INLINE_SIZE]>;
pub trait Endpoint: Copy {
fn min_value() -> Self;
fn max_value() -> Self;
fn is_valid(self) -> bool;
fn cmp_end(self, other: Self) -> core::cmp::Ordering;
#[inline(always)]
fn next_after(self) -> Option<Self> {
self.increase_toward(Self::max_value())
}
#[inline(always)]
fn prev_before(self) -> Option<Self> {
self.decrease_toward(Self::min_value())
}
fn decrease_toward(self, other: Self) -> Option<Self>;
fn increase_toward(self, other: Self) -> Option<Self>;
#[doc(hidden)]
#[inline(always)]
fn cmp_range(left: (Self, Self), right: (Self, Self)) -> core::cmp::Ordering {
match left.0.cmp_end(right.0) {
core::cmp::Ordering::Equal => left.1.cmp_end(right.1),
any => any,
}
}
#[doc(hidden)]
#[inline(always)]
fn bot_end(self, other: Self) -> Self {
core::cmp::min_by(self, other, |x, y| Self::cmp_end(*x, *y))
}
#[doc(hidden)]
#[inline(always)]
fn top_end(self, other: Self) -> Self {
core::cmp::max_by(self, other, |x, y| Self::cmp_end(*x, *y))
}
}
type Pair<T> = (T, T);
mod private {
pub trait Sealed {}
}
pub trait ClosedRange: Copy + private::Sealed {
#[doc(hidden)]
type EndT: Endpoint;
#[doc(hidden)]
fn get(self) -> Pair<Self::EndT>;
}
pub trait NormalizedRangeIter: private::Sealed + Iterator<Item: ClosedRange> {
#[inline(always)]
#[must_use]
fn into_empty_flag(mut self) -> bool
where
Self: Sized,
{
self.next().is_none()
}
#[inline(always)]
#[must_use]
fn into_inhabited_flag(self) -> bool
where
Self: Sized,
{
!self.into_empty_flag()
}
#[must_use]
fn eqv(
mut self,
other: impl IntoNormalizedRangeIter<Item: ClosedRange<EndT = ClosedRangeEnd<Self::Item>>>,
) -> bool
where
Self: Sized,
{
use core::cmp::Ordering;
let mut other = other.into_iter();
loop {
match (self.next(), other.next()) {
(Some(a), Some(b)) => {
if Endpoint::cmp_range(a.get(), b.get()) != Ordering::Equal {
return false;
}
}
(None, None) => return true,
_ => return false,
}
}
}
#[inline(always)]
#[must_use]
fn complement(self) -> complement::ComplementIterator<Self>
where
Self: Sized,
{
complement::ComplementIterator::new(self)
}
#[inline(always)]
#[must_use]
fn intersect_vec<'a>(
self,
other: &'a RangeVec<ClosedRangeEnd<Self::Item>>,
) -> intersection::IntersectionIterator<'a, Self>
where
Self: 'a + Sized,
{
unsafe { crate::intersection::intersect(self, other) }
}
#[inline(always)]
#[must_use]
fn intersect<Other>(
self,
other: Other,
) -> intersection_iterator::LinearIntersectionIterator<
ClosedRangeEnd<Self::Item>,
Self,
<Other as IntoIterator>::IntoIter,
>
where
Self: Sized,
Other: IntoNormalizedRangeIter<Item: ClosedRange<EndT = ClosedRangeEnd<Self::Item>>>,
{
intersection_iterator::LinearIntersectionIterator::new(self, other.into_iter())
}
#[inline(always)]
#[must_use]
fn union<Other>(
self,
other: Other,
) -> union_iterator::UnionIterator<
ClosedRangeEnd<Self::Item>,
Self,
<Other as IntoIterator>::IntoIter,
>
where
Self: Sized,
Other: IntoNormalizedRangeIter<Item: ClosedRange<EndT = ClosedRangeEnd<Self::Item>>>,
{
union_iterator::UnionIterator::new(self, other.into_iter())
}
#[must_use]
fn collect_range_vec(self) -> RangeVec<ClosedRangeEnd<Self::Item>>
where
Self: Sized,
{
#[cfg(feature = "internal_checks")]
let hint = self.size_hint();
let inner: SmallVec<[_; INLINE_SIZE]> = self.map(|range| range.get()).collect();
#[cfg(feature = "internal_checks")]
{
assert!(hint.0 <= inner.len());
assert!(inner.len() <= hint.1.unwrap_or(usize::MAX));
assert!(is_normalized(&inner));
}
unsafe { RangeVec::new_unchecked(inner) }
}
}
impl<T: NormalizedRangeIter + ?Sized> private::Sealed for alloc::boxed::Box<T> {}
impl<T: NormalizedRangeIter + ?Sized> NormalizedRangeIter for alloc::boxed::Box<T> {}
pub trait IntoNormalizedRangeIter: IntoIterator<IntoIter: NormalizedRangeIter> {}
impl<T: IntoIterator<IntoIter: NormalizedRangeIter>> IntoNormalizedRangeIter for T {}
impl<T: Endpoint> private::Sealed for (T, T) {}
impl<T: Endpoint> ClosedRange for (T, T) {
type EndT = T;
#[inline(always)]
fn get(self) -> (T, T) {
self
}
}
impl<T: Endpoint> private::Sealed for &(T, T) {}
impl<T: Endpoint> ClosedRange for &(T, T) {
type EndT = T;
#[inline(always)]
fn get(self) -> (T, T) {
*self
}
}
type ClosedRangeEnd<T> = <T as ClosedRange>::EndT;
type ClosedRangeVal<T> = Pair<ClosedRangeEnd<T>>;
#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
fn ranges_to_bits(ranges: &[(u8, u8)]) -> alloc::vec::Vec<bool> {
use alloc::vec;
let mut marks = vec![false; 256];
for (start, stop) in ranges.iter().copied() {
if start <= stop {
for i in start..=stop {
marks[i as usize] = true;
}
}
}
marks
}
#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
mod test {
use super::*;
use alloc::vec;
use alloc::vec::Vec;
#[test]
fn test_min_max() {
assert_eq!(<u8 as Endpoint>::min_value(), 0);
assert_eq!(<u8 as Endpoint>::max_value(), 255);
assert_eq!(<i8 as Endpoint>::min_value(), -128);
assert_eq!(<i8 as Endpoint>::max_value(), 127);
assert_eq!(<i32 as Endpoint>::min_value(), i32::MIN);
assert_eq!(<i32 as Endpoint>::max_value(), i32::MAX);
assert_eq!(<isize as Endpoint>::min_value(), isize::MIN);
assert_eq!(<isize as Endpoint>::max_value(), isize::MAX);
assert_eq!(<usize as Endpoint>::min_value(), usize::MIN);
assert_eq!(<usize as Endpoint>::max_value(), usize::MAX);
}
#[test]
fn test_prev_next_u64() {
assert_eq!(0u64.prev_before(), None);
assert_eq!(0u64.next_after(), Some(1));
assert_eq!(u64::MAX.prev_before(), Some(u64::MAX - 1));
assert_eq!(u64::MAX.next_after(), None);
assert_eq!(0u64.decrease_toward(0u64), None);
assert_eq!(0u64.increase_toward(10u64), Some(1));
assert_eq!(1u64.decrease_toward(0u64), Some(0u64));
assert_eq!(1u64.decrease_toward(1u64), None);
assert_eq!(1u64.decrease_toward(2u64), None);
assert_eq!(1u64.increase_toward(0u64), None);
assert_eq!(1u64.increase_toward(1u64), None);
assert_eq!(1u64.increase_toward(2u64), Some(2u64));
assert_eq!(u64::MAX.increase_toward(u64::MAX), None);
assert_eq!(u64::MAX.decrease_toward(0), Some(u64::MAX - 1));
}
#[test]
fn test_closed_range() {
let ranges = vec![(1u8, 2u8), (10u8, 4u8)];
assert_eq!(
&ranges.iter().map(ClosedRange::get).collect::<Vec<_>>(),
&ranges
);
assert_eq!(
ranges
.clone()
.into_iter()
.map(ClosedRange::get)
.collect::<Vec<_>>(),
ranges
);
}
#[test]
fn test_empty_inhabited_iter() {
assert!(RangeVec::<u8>::new().into_iter().into_empty_flag());
assert!(!RangeVec::<u8>::new().into_iter().into_inhabited_flag());
assert!(!RangeVec::from_vec(vec![(1u8, 1u8)])
.into_iter()
.into_empty_flag());
assert!(RangeVec::from_vec(vec![(1u8, 1u8)])
.into_iter()
.into_inhabited_flag());
}
#[test]
fn test_chain_boxed_iter() {
let mut acc: Option<Box<dyn NormalizedRangeIter<Item = (u8, u8)>>> = None;
for i in 1u8..=4u8 {
let vec = RangeVec::from_vec(vec![(2 * i, 10 * i)]);
acc = match acc.take() {
None => Some(Box::new(vec.into_iter())),
Some(acc) if i % 2 == 0 => Some(Box::new(acc.intersect(vec.into_iter()))),
Some(acc) => Some(Box::new(acc.intersect_vec(Box::leak(Box::new(vec))))),
};
}
let singleton: SmallVec<[(u8, u8); 1]> = smallvec::smallvec![(0, 6)];
acc = Some(Box::new(
acc.unwrap().union(RangeVec::from_smallvec(singleton)),
));
let expected = RangeVec::from_vec(vec![(7u8, 7u8), (11u8, 255u8)]);
assert!(acc.unwrap().complement().eqv(expected));
}
proptest::proptest! {
#[test]
fn test_increase(x: u8) {
assert_eq!(<u8 as Endpoint>::max_value(), u8::MAX);
if x != u8::MAX {
assert_eq!(x.next_after(), Some(x + 1));
} else {
assert_eq!(x.next_after(), None);
}
}
#[test]
fn test_decrease(x: u8) {
assert_eq!(<u8 as Endpoint>::min_value(), 0u8);
if x != 0u8 {
assert_eq!(x.prev_before(), Some(x - 1));
} else {
assert_eq!(x.prev_before(), None);
}
}
#[test]
fn test_toward(x: u8, y: u8) {
let (x, y) = (x.min(y), x.max(y));
assert_eq!(x.decrease_toward(y), None);
assert_eq!(y.increase_toward(x), None);
if x == y {
assert_eq!(x.increase_toward(y), None);
assert_eq!(x.decrease_toward(y), None);
assert_eq!(y.increase_toward(x), None);
assert_eq!(y.decrease_toward(x), None);
} else {
assert_eq!(x.increase_toward(y), Some(x + 1));
assert_eq!(y.decrease_toward(x), Some(y - 1));
}
}
#[test]
fn test_top_bot(x: u8, y: u8) {
assert_eq!(x.bot_end(y), x.min(y));
assert_eq!(y.bot_end(x), x.min(y));
assert_eq!(x.top_end(y), x.max(y));
assert_eq!(y.top_end(x), x.max(y));
}
#[test]
fn test_cmp(x: u8, y: u8) {
assert_eq!(x.cmp_end(y), x.cmp(&y));
assert_eq!(y.cmp_end(x), y.cmp(&x));
}
#[test]
fn test_cmp_range(x: (u8, u8), y: (u8, u8)) {
assert_eq!(u8::cmp_range(x, y), x.cmp(&y));
assert_eq!(u8::cmp_range(y, x), y.cmp(&x));
}
#[test]
fn test_increase_isize(x: isize) {
assert_eq!(<isize as Endpoint>::max_value(), isize::MAX);
if x != isize::MAX {
assert_eq!(x.next_after(), Some(x + 1));
} else {
assert_eq!(x.next_after(), None);
}
}
#[test]
fn test_decrease_isize(x: isize) {
assert_eq!(<isize as Endpoint>::min_value(), isize::MIN);
if x != isize::MIN {
assert_eq!(x.prev_before(), Some(x - 1));
} else {
assert_eq!(x.prev_before(), None);
}
}
#[test]
fn test_toward_isize(x: isize, y: isize) {
let (x, y) = (x.min(y), x.max(y));
assert_eq!(x.decrease_toward(y), None);
assert_eq!(y.increase_toward(x), None);
if x == y {
assert_eq!(x.increase_toward(y), None);
assert_eq!(x.decrease_toward(y), None);
assert_eq!(y.increase_toward(x), None);
assert_eq!(y.decrease_toward(x), None);
} else {
assert_eq!(x.increase_toward(y), Some(x + 1));
assert_eq!(y.decrease_toward(x), Some(y - 1));
}
}
#[test]
fn test_top_bot_isize(x: isize, y: isize) {
assert_eq!(x.bot_end(y), x.min(y));
assert_eq!(y.bot_end(x), x.min(y));
assert_eq!(x.top_end(y), x.max(y));
assert_eq!(y.top_end(x), x.max(y));
}
#[test]
fn test_cmp_isize(x: isize, y: isize) {
assert_eq!(x.cmp_end(y), x.cmp(&y));
assert_eq!(y.cmp_end(x), y.cmp(&x));
}
#[test]
fn test_cmp_range_isize(x: (isize, isize), y: (isize, isize)) {
assert_eq!(isize::cmp_range(x, y), x.cmp(&y));
assert_eq!(isize::cmp_range(y, x), y.cmp(&x));
}
#[test]
fn test_increase_usize(x: usize) {
assert_eq!(<usize as Endpoint>::max_value(), usize::MAX);
if x != usize::MAX {
assert_eq!(x.next_after(), Some(x + 1));
} else {
assert_eq!(x.next_after(), None);
}
}
#[test]
fn test_decrease_usize(x: usize) {
assert_eq!(<usize as Endpoint>::min_value(), 0usize);
if x != usize::MIN {
assert_eq!(x.prev_before(), Some(x - 1));
} else {
assert_eq!(x.prev_before(), None);
}
}
#[test]
fn test_toward_usize(x: usize, y: usize) {
let (x, y) = (x.min(y), x.max(y));
assert_eq!(x.decrease_toward(y), None);
assert_eq!(y.increase_toward(x), None);
if x == y {
assert_eq!(x.increase_toward(y), None);
assert_eq!(x.decrease_toward(y), None);
assert_eq!(y.increase_toward(x), None);
assert_eq!(y.decrease_toward(x), None);
} else {
assert_eq!(x.increase_toward(y), Some(x + 1));
assert_eq!(y.decrease_toward(x), Some(y - 1));
}
}
#[test]
fn test_top_bot_usize(x: usize, y: usize) {
assert_eq!(x.bot_end(y), x.min(y));
assert_eq!(y.bot_end(x), x.min(y));
assert_eq!(x.top_end(y), x.max(y));
assert_eq!(y.top_end(x), x.max(y));
}
#[test]
fn test_cmp_usize(x: usize, y: usize) {
assert_eq!(x.cmp_end(y), x.cmp(&y));
assert_eq!(y.cmp_end(x), y.cmp(&x));
}
#[test]
fn test_cmp_range_usize(x: (usize, usize), y: (usize, usize)) {
assert_eq!(usize::cmp_range(x, y), x.cmp(&y));
assert_eq!(usize::cmp_range(y, x), y.cmp(&x));
}
}
}