use core::ops::Add;
use crate::RangeSet;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct WrappedInterval {
low: u64,
high: u64,
empty: bool,
full: bool,
}
impl WrappedInterval {
pub const fn empty() -> Self {
Self {
low: 0,
high: 0,
empty: true,
full: false,
}
}
pub const fn full() -> Self {
Self {
low: 0,
high: u64::MAX,
empty: false,
full: true,
}
}
pub const fn new(low: u64, high: u64) -> Self {
Self {
low,
high,
empty: false,
full: false,
}
}
pub const fn from_value(value: u64) -> Self {
Self::new(value, value)
}
pub const fn bounds(&self) -> Option<(u64, u64)> {
if self.empty {
None
} else {
Some((self.low, self.high))
}
}
pub fn is_wrapping(&self) -> bool {
!self.empty && !self.full && self.low > self.high
}
pub fn contains_value(&self, value: u64) -> bool {
if self.empty {
false
} else if self.full {
true
} else if self.low <= self.high {
self.low <= value && value <= self.high
} else {
value >= self.low || value <= self.high
}
}
pub fn cardinality(&self) -> u128 {
if self.empty {
0
} else if self.full {
1_u128 << 64
} else {
u128::from(self.high.wrapping_sub(self.low)) + 1
}
}
pub fn as_range_set(&self) -> RangeSet<2> {
if self.empty {
RangeSet::empty()
} else if self.full {
RangeSet::full()
} else if self.low <= self.high {
RangeSet::from_range(self.low, self.high)
} else {
RangeSet::from_range(self.low, u64::MAX).union(RangeSet::from_range(0, self.high))
}
}
}
impl Default for WrappedInterval {
fn default() -> Self {
Self::full()
}
}
impl Add for WrappedInterval {
type Output = Self;
fn add(self, other: Self) -> Self {
if self.empty || other.empty {
return Self::empty();
}
if self.full || other.full || self.cardinality() + other.cardinality() > (1_u128 << 64) {
return Self::full();
}
Self::new(
self.low.wrapping_add(other.low),
self.high.wrapping_add(other.high),
)
}
}