use alloc::{vec, vec::Vec};
use core::iter::FromIterator;
use crate::{generic_range::GenericRange, Arrangement, Domain};
#[cfg(feature = "arbitrary")]
mod arbitrary;
mod contains;
mod difference;
mod format;
mod insert;
mod intersect;
mod invert;
mod iterators;
#[cfg(any(feature = "proptest", test))]
mod proptest;
mod remove;
mod symmetric_difference;
mod union;
#[allow(clippy::missing_inline_in_public_items)]
#[derive(Clone, Debug, Default, Hash, PartialEq, Eq)]
pub struct Ranges<T: Domain> {
pub(crate) ranges: Vec<GenericRange<T>>,
}
impl<T: Domain> Ranges<T> {
#[must_use]
pub fn new() -> Self {
Self::with_capacity(0)
}
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
Self {
ranges: Vec::with_capacity(capacity),
}
}
#[must_use]
pub fn full() -> Self {
Self {
ranges: vec![GenericRange::full()],
}
}
#[allow(clippy::indexing_slicing)]
#[must_use]
pub fn is_full(&self) -> bool
where
T: PartialEq,
{
self.ranges.len() == 1 && self.ranges[0] == GenericRange::full()
}
#[must_use]
pub fn len(&self) -> usize {
self.ranges.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.ranges.is_empty()
}
#[must_use]
pub fn find_intersecting_ranges(&self, other: &GenericRange<T>) -> Option<(usize, usize)> {
let mut seen_overlap = false;
let mut indices = None;
for (index, range) in self.ranges.iter().enumerate() {
#[allow(clippy::wildcard_enum_match_arm)]
let overlap = match other.arrangement(range) {
Arrangement::Disjoint { .. } => false,
Arrangement::Empty { .. } => return None,
_ => true,
};
match (seen_overlap, overlap) {
(false, false) => {}
(false, true) => {
seen_overlap = true;
indices = Some((index, index));
}
(true, true) => {
indices = indices.map(|(start, _)| (start, index));
}
(true, false) => {
break;
}
}
}
indices
}
#[must_use]
pub fn as_slice(&self) -> &[GenericRange<T>] {
self.ranges.as_slice()
}
}
impl<T: Domain, U> From<U> for Ranges<T>
where
U: Into<GenericRange<T>>,
{
#[must_use]
fn from(range_value: U) -> Self {
let range = range_value.into();
let mut ranges = Self::new();
#[allow(clippy::let_underscore_untyped)]
let _ = ranges.insert(range);
ranges
}
}
impl<T: Domain, U> From<Vec<U>> for Ranges<T>
where
U: Into<GenericRange<T>>,
{
#[must_use]
fn from(items: Vec<U>) -> Self {
let mut ranges = Self::with_capacity(items.capacity());
#[allow(clippy::let_underscore_untyped)]
for range in items {
let _ = ranges.insert(range.into());
}
ranges
}
}
impl<T: Domain> FromIterator<GenericRange<T>> for Ranges<T> {
#[allow(clippy::shadow_reuse)]
fn from_iter<I: IntoIterator<Item = GenericRange<T>>>(iter: I) -> Self {
let iter = iter.into_iter();
let (lower_bound, _) = iter.size_hint();
let mut ranges = Self::with_capacity(lower_bound);
#[allow(clippy::let_underscore_untyped)]
for range in iter {
let _ = ranges.insert(range);
}
ranges.ranges.shrink_to_fit();
ranges
}
}
impl<T: Domain> AsRef<Vec<GenericRange<T>>> for Ranges<T> {
fn as_ref(&self) -> &Vec<GenericRange<T>> {
&self.ranges
}
}
#[cfg(test)]
mod tests {
use alloc::vec;
use core::ops::Bound;
use crate::{GenericRange, Ranges};
#[test]
fn from_core_ranges() {
assert_eq!(
Ranges::from(1..5),
Ranges {
ranges: vec![GenericRange {
start: Bound::Included(1),
end: Bound::Excluded(5)
}]
}
);
assert_eq!(
Ranges::from(6..=10),
Ranges {
ranges: vec![GenericRange {
start: Bound::Included(6),
end: Bound::Included(10)
}]
}
);
assert_eq!(
Ranges::from(12..),
Ranges {
ranges: vec![GenericRange {
start: Bound::Included(12),
end: Bound::Included(2_147_483_647)
}]
}
);
assert_eq!(
Ranges::from(..15),
Ranges {
ranges: vec![GenericRange {
start: Bound::Included(-2_147_483_648),
end: Bound::Excluded(15)
}]
}
);
assert_eq!(
Ranges::from(..=20),
Ranges {
ranges: vec![GenericRange {
start: Bound::Included(-2_147_483_648),
end: Bound::Included(20)
}]
}
);
let ranges: Ranges<usize> = Ranges::from(..);
assert_eq!(
ranges,
Ranges {
ranges: vec![GenericRange {
start: Bound::Included(0),
end: Bound::Included(18_446_744_073_709_551_615)
}]
}
);
assert_eq!(
Ranges::from((Bound::Excluded(30), Bound::Excluded(42))),
Ranges {
ranges: vec![GenericRange {
start: Bound::Excluded(30),
end: Bound::Excluded(42)
}]
}
);
assert_eq!(
Ranges::from((Bound::Excluded(45), Bound::Included(50))),
Ranges {
ranges: vec![GenericRange {
start: Bound::Excluded(45),
end: Bound::Included(50)
}]
}
);
assert_eq!(
Ranges::from((Bound::Excluded(55), Bound::Unbounded)),
Ranges {
ranges: vec![GenericRange {
start: Bound::Excluded(55),
end: Bound::Included(2_147_483_647)
}]
}
);
}
}