use core::fmt;
use core::hash::Hash;
use core::num::NonZero;
use core::ops::Range;
use num_traits::{AsPrimitive, PrimInt, Unsigned};
mod private {
pub trait Sealed {}
impl Sealed for u16 {}
impl Sealed for u32 {}
impl Sealed for u64 {}
impl Sealed for usize {}
}
pub trait SmallRangeStorage:
private::Sealed + PrimInt + Unsigned + Hash + AsPrimitive<usize> + 'static
where
usize: AsPrimitive<Self>,
{
type NonZeroStorage: Copy + Eq + Hash;
const HALF_BITS: u32;
const LOW_MASK: Self;
unsafe fn new_nonzero_unchecked(val: Self) -> Self::NonZeroStorage;
fn get_nonzero(nz: Self::NonZeroStorage) -> Self;
}
impl SmallRangeStorage for u16 {
type NonZeroStorage = NonZero<u16>;
const HALF_BITS: u32 = 8;
const LOW_MASK: Self = 0xFF;
#[inline]
unsafe fn new_nonzero_unchecked(val: Self) -> Self::NonZeroStorage {
NonZero::new_unchecked(val)
}
#[inline]
fn get_nonzero(nz: Self::NonZeroStorage) -> Self {
nz.get()
}
}
impl SmallRangeStorage for u32 {
type NonZeroStorage = NonZero<u32>;
const HALF_BITS: u32 = 16;
const LOW_MASK: Self = 0xFFFF;
#[inline]
unsafe fn new_nonzero_unchecked(val: Self) -> Self::NonZeroStorage {
NonZero::new_unchecked(val)
}
#[inline]
fn get_nonzero(nz: Self::NonZeroStorage) -> Self {
nz.get()
}
}
impl SmallRangeStorage for u64 {
type NonZeroStorage = NonZero<u64>;
const HALF_BITS: u32 = 32;
const LOW_MASK: Self = 0xFFFF_FFFF;
#[inline]
unsafe fn new_nonzero_unchecked(val: Self) -> Self::NonZeroStorage {
NonZero::new_unchecked(val)
}
#[inline]
fn get_nonzero(nz: Self::NonZeroStorage) -> Self {
nz.get()
}
}
impl SmallRangeStorage for usize {
type NonZeroStorage = NonZero<usize>;
const HALF_BITS: u32 = (core::mem::size_of::<usize>() * 8 / 2) as u32;
const LOW_MASK: Self = (1usize << Self::HALF_BITS) - 1;
#[inline]
unsafe fn new_nonzero_unchecked(val: Self) -> Self::NonZeroStorage {
NonZero::new_unchecked(val)
}
#[inline]
fn get_nonzero(nz: Self::NonZeroStorage) -> Self {
nz.get()
}
}
#[repr(transparent)]
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct SmallRange<T: SmallRangeStorage = u64>
where
usize: AsPrimitive<T>,
{
bits: T::NonZeroStorage,
}
impl<T: SmallRangeStorage> SmallRange<T>
where
usize: AsPrimitive<T>,
{
#[inline]
fn encode(start: T, end: T) -> T::NonZeroStorage {
debug_assert!(start <= end, "start must not exceed end");
let length = end - start;
let hi = start + T::one();
let lo = length + T::one();
debug_assert!(hi <= T::LOW_MASK, "start+1 exceeds half-width capacity");
debug_assert!(lo <= T::LOW_MASK, "length+1 exceeds half-width capacity");
let packed = (hi << T::HALF_BITS as usize) | lo;
unsafe { T::new_nonzero_unchecked(packed) }
}
#[inline]
fn decode_start_length(bits: T::NonZeroStorage) -> (T, T) {
let packed = T::get_nonzero(bits);
let hi = packed >> T::HALF_BITS as usize;
let lo = packed & T::LOW_MASK;
let start = hi - T::one();
let length = lo - T::one();
(start, length)
}
#[inline]
pub fn new(start: T, end: T) -> Self {
Self {
bits: Self::encode(start, end),
}
}
#[inline]
pub fn start(&self) -> T {
let (start, _) = Self::decode_start_length(self.bits);
start
}
#[inline]
pub fn end(&self) -> T {
let (start, length) = Self::decode_start_length(self.bits);
start + length
}
#[inline]
pub fn len(&self) -> usize {
let packed = T::get_nonzero(self.bits);
let lo = packed & T::LOW_MASK;
(lo - T::one()).as_()
}
#[inline]
pub fn is_empty(&self) -> bool {
let packed = T::get_nonzero(self.bits);
let lo = packed & T::LOW_MASK;
lo == T::one() }
#[inline]
pub fn to_range(&self) -> Range<T> {
let (start, length) = Self::decode_start_length(self.bits);
start..(start + length)
}
#[inline]
pub fn try_new(start: T, end: T) -> Option<Self> {
if start > end {
return None;
}
let length = end - start;
let hi = start + T::one();
let lo = length + T::one();
if hi > T::LOW_MASK || lo > T::LOW_MASK {
return None;
}
let packed = (hi << T::HALF_BITS as usize) | lo;
Some(Self {
bits: unsafe { T::new_nonzero_unchecked(packed) },
})
}
#[inline]
pub fn contains(&self, value: T) -> bool {
value >= self.start() && value < self.end()
}
#[inline]
pub fn overlaps(&self, other: &Self) -> bool {
!self.is_empty()
&& !other.is_empty()
&& self.start() < other.end()
&& other.start() < self.end()
}
}
impl<T: SmallRangeStorage> Default for SmallRange<T>
where
usize: AsPrimitive<T>,
{
fn default() -> Self {
Self::new(T::zero(), T::zero())
}
}
impl<T: SmallRangeStorage + fmt::Debug> fmt::Debug for SmallRange<T>
where
usize: AsPrimitive<T>,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SmallRange")
.field("start", &self.start())
.field("end", &self.end())
.finish()
}
}
impl<T: SmallRangeStorage> IntoIterator for SmallRange<T>
where
usize: AsPrimitive<T>,
Range<T>: Iterator<Item = T>,
{
type Item = T;
type IntoIter = Range<T>;
fn into_iter(self) -> Self::IntoIter {
self.to_range()
}
}
impl<T: SmallRangeStorage> IntoIterator for &SmallRange<T>
where
usize: AsPrimitive<T>,
Range<T>: Iterator<Item = T>,
{
type Item = T;
type IntoIter = Range<T>;
fn into_iter(self) -> Self::IntoIter {
self.to_range()
}
}