use core::{
cmp::Ordering,
fmt,
num::Wrapping,
ops::{Add, AddAssign, Sub, SubAssign},
};
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(doc, derive(PartialOrd, Ord))]
pub struct Cyclic<T>(pub Wrapping<T>);
macro_rules! impl_cyclic {
(@impl $UID:ident -> $SID:ident) => {
impl Cyclic<$UID> {
#[allow(dead_code)]
pub const fn relative_min(self) -> Self {
Cyclic(Wrapping(self.relative_max().0.0.wrapping_add(1)))
}
#[allow(dead_code)]
pub const fn relative_max(self) -> Self {
Cyclic::new(self.0.0 ^ !(!(0 as $UID) >> 1))
}
}
impl PartialOrd for Cyclic<$UID> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Cyclic<$UID> {
fn cmp(&self, other: &Self) -> Ordering {
match (self.0.0.wrapping_sub(other.0.0) as $SID).signum() {
0 => Ordering::Equal,
1 => Ordering::Greater,
_ => Ordering::Less,
}
}
}
};
($($UID:ident -> $SID:ident),* $(,)?) => {
$(impl_cyclic!(@impl $UID -> $SID);)*
};
}
#[cfg(not(doc))]
impl_cyclic!(u8 -> i8, u16 -> i16, u32 -> i32, u64 -> i64, usize -> isize);
impl<T: fmt::Display> fmt::Display for Cyclic<T> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl<T> Cyclic<T> {
#[allow(dead_code)]
pub const fn new(value: T) -> Self {
Cyclic(Wrapping(value))
}
}
impl<T> Add for Cyclic<T>
where
Wrapping<T>: Add<Output = Wrapping<T>>,
{
type Output = Self;
#[inline]
fn add(self, other: Self) -> Self {
Cyclic(self.0 + other.0)
}
}
impl<T> Add<T> for Cyclic<T>
where
Wrapping<T>: Add<Output = Wrapping<T>>,
{
type Output = Self;
#[inline]
fn add(self, other: T) -> Self {
Cyclic(self.0 + Wrapping(other))
}
}
impl<T> AddAssign for Cyclic<T>
where
Wrapping<T>: AddAssign,
{
#[inline]
fn add_assign(&mut self, other: Self) {
self.0 += other.0;
}
}
impl<T> AddAssign<T> for Cyclic<T>
where
Wrapping<T>: AddAssign<T>,
{
#[inline]
fn add_assign(&mut self, other: T) {
self.0 += other;
}
}
impl<T> Sub for Cyclic<T>
where
Wrapping<T>: Sub<Output = Wrapping<T>>,
{
type Output = Self;
#[inline]
fn sub(self, other: Self) -> Self {
Cyclic(self.0 - other.0)
}
}
impl<T> Sub<T> for Cyclic<T>
where
Wrapping<T>: Sub<Output = Wrapping<T>>,
{
type Output = Self;
#[inline]
fn sub(self, other: T) -> Self {
Cyclic(self.0 - Wrapping(other))
}
}
impl<T> SubAssign for Cyclic<T>
where
Wrapping<T>: SubAssign,
{
#[inline]
fn sub_assign(&mut self, other: Self) {
self.0 -= other.0;
}
}
impl<T> SubAssign<T> for Cyclic<T>
where
Wrapping<T>: SubAssign<T>,
{
#[inline]
fn sub_assign(&mut self, other: T) {
self.0 -= other;
}
}
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Default)]
pub struct Partition<T>(pub T);
struct Iter<T> {
next: Partition<T>,
size: T,
}
macro_rules! impl_prec {
(@impl $UID:ident $($GEN:ident)?) => {
impl<$($GEN)*> Partition<$UID> {
const EXP_BITS: u32 = $UID::BITS.ilog2();
const NUM_BITS: u32 = $UID::BITS - Self::EXP_BITS;
const EXP_MASK: $UID = !(!0 << Self::EXP_BITS);
pub const fn new() -> Self {
Self(0)
}
pub const fn lowest() -> Self {
Self((!0 << Self::EXP_BITS) | (Self::NUM_BITS as $UID))
}
pub const fn split(self, n: $UID) -> Option<impl ExactSizeIterator<Item = Self>> {
let bits = n.next_power_of_two().trailing_zeros();
if bits <= self.capacity() {
Some(Iter {
next: Self(self.0 + bits as $UID),
size: n
})
} else {
None
}
}
const fn advance(self) -> Self {
self.advance_by(1)
}
const fn advance_by(self, count: u32) -> Self {
Self(
self.0.wrapping_add(
(count as $UID).wrapping_shl(self.0.wrapping_neg() as u32)
)
)
}
pub const fn capacity(self) -> u32 {
Self::NUM_BITS - self.nesting() as u32
}
const fn offset(self) -> $UID {
self.0 >> Self::EXP_BITS
}
const fn nesting(self) -> $UID {
self.0 & Self::EXP_MASK
}
const fn delta(self) -> $UID {
(!0) as $UID >> Self::EXP_BITS >> self.nesting()
}
pub const fn range(self) -> core::ops::Range<$UID> {
let lo = self.offset();
let hi = lo | self.delta();
lo..hi+1
}
pub fn float_range(self) -> core::ops::Range<f64> {
let max = (1 as $UID) << Self::NUM_BITS;
let range = self.range();
(range.start as f64) / (max as f64)
.. (range.end as f64) / (max as f64)
}
}
impl<$($GEN)*> From<$UID> for Partition<$UID> {
fn from(value: $UID) -> Self {
Self((value << Self::EXP_BITS) | (Self::NUM_BITS as $UID))
}
}
impl<$($GEN)*> fmt::Display for Partition<$UID> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Partition")
.field(&self.float_range())
.finish()
}
}
impl<$($GEN)*> fmt::Debug for Partition<$UID> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Partition")
.field("irange", &self.range())
.field("frange", &self.float_range())
.field("capacity", &self.capacity())
.finish()
}
}
impl<$($GEN)*> fmt::Binary for Partition<$UID> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f, "Partition({:0num$b}_{:0exp$b})",
self.offset(), self.nesting(),
exp = Self::EXP_BITS as usize,
num = Self::NUM_BITS as usize
)
}
}
impl<$($GEN)*> Iterator for Iter<$UID> {
type Item = Partition<$UID>;
fn next(&mut self) -> Option<Self::Item> {
if self.size > 0 {
let next = self.next;
self.size -= 1;
self.next = next.advance();
Some(next)
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len(), Some(self.len()))
}
fn count(self) -> usize {
self.len()
}
}
impl<$($GEN)*> ExactSizeIterator for Iter<$UID> {
fn len(&self) -> usize {
self.size as usize
}
}
};
(@doc $UID:ident) => {
impl_prec!(@impl $UID $UID);
};
($($UID:ident),* $(,)?) => {
$(impl_prec!(@impl $UID);)*
};
}
#[cfg(not(doc))]
impl_prec!(u8, u16, u32, u64, u128, usize);
#[cfg(doc)]
impl_prec!(@doc T);
#[repr(transparent)]
pub(crate) struct ForceOrd<T>(pub T);
impl<T: PartialEq> PartialEq for ForceOrd<T> {
fn eq(&self, other: &Self) -> bool {
self.0.eq(&other.0)
}
}
impl<T: PartialOrd> Eq for ForceOrd<T> {}
impl<T: PartialOrd> PartialOrd for ForceOrd<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<T: PartialOrd> Ord for ForceOrd<T> {
fn cmp(&self, other: &Self) -> Ordering {
self.0.partial_cmp(&other.0).unwrap_or(Ordering::Equal)
}
}
#[cfg(test)]
mod tests {
use super::*;
use proptest::{prop_assert, proptest};
proptest! {
#[test]
#[cfg_attr(miri, ignore)]
fn cyclic_non_transitive(value: u32) {
let x = Cyclic::new(value);
let y = x.relative_max();
let z = y + 100;
prop_assert!(x < y && y < z && z < x);
}
#[test]
#[cfg_attr(miri, ignore)]
fn cyclic_relative_min(value: u32) {
let x = Cyclic::new(value);
let y = x.relative_min();
prop_assert!(x > y);
}
#[test]
#[cfg_attr(miri, ignore)]
fn cyclic_relative_max(value: u32) {
let x = Cyclic::new(value);
let y = x.relative_max();
prop_assert!(x < y);
}
#[test]
#[cfg_attr(miri, ignore)]
fn cyclic_relative_max_plus_one(value: u32) {
let x = Cyclic::new(value);
let y = x.relative_max() + 1;
prop_assert!(x > y);
}
#[test]
#[cfg_attr(miri, ignore)]
fn cyclic_relative_min_minus_one(value: u32) {
let x = Cyclic::new(value);
let y = x.relative_min() - 1;
prop_assert!(x < y);
}
}
#[test]
fn partition_capacity() {
assert_eq!(Partition::<u8>::new().capacity(), 8 - 3);
assert_eq!(Partition::<u16>::new().capacity(), 16 - 4);
assert_eq!(Partition::<u32>::new().capacity(), 32 - 5);
assert_eq!(Partition::<u64>::new().capacity(), 64 - 6);
assert_eq!(Partition::<u128>::new().capacity(), 128 - 7);
}
#[test]
fn partition_deep_nesting() {
let p1 = Partition::<u8>::new();
for p2 in p1.split(4).expect("remaining capacity is 5") {
for p3 in p2.split(4).expect("remaining capacity is 3") {
for p4 in p3.split(2).expect("remaining capacity is 1") {
assert_eq!(p4.capacity(), 0);
}
}
}
}
#[test]
fn partition_shallow_nesting() {
let p1 = Partition::<u8>::new();
for p2 in p1.split(32).expect("remaining capacity is 5") {
assert_eq!(p2.capacity(), 0);
}
}
}