Skip to main content

oxidd_core/util/num/
mod.rs

1//! Number types useful for counting satisfying assignments
2
3use std::fmt;
4use std::ops::{Add, Shl, Shr, Sub};
5
6use crate::util::IsFloatingPoint;
7
8mod bigint;
9pub use bigint::Natural;
10
11/// Error type returned when a number is not representable in the target type
12#[derive(Clone, Copy, PartialEq, Eq, Debug)]
13pub struct NotRepresentable;
14
15impl std::error::Error for NotRepresentable {}
16
17impl fmt::Display for NotRepresentable {
18    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19        "number is not representable in the target type".fmt(f)
20    }
21}
22
23/// Natural numbers with saturating arithmetic
24///
25/// In contrast to [`std::num::Saturating`], `T::MAX` represents an
26/// out-of-bounds value, and a subsequent subtraction or right shift does not
27/// change this value.
28#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
29pub struct Saturating<T>(pub T);
30
31/// cbindgen:ignore
32impl<T> IsFloatingPoint for Saturating<T> {
33    const FLOATING_POINT: bool = false;
34    const MIN_EXP: i32 = 0;
35}
36
37impl<T: From<u32>> From<u32> for Saturating<T> {
38    #[inline]
39    fn from(value: u32) -> Self {
40        Self(T::from(value))
41    }
42}
43
44macro_rules! impl_assign_via_copy {
45    ($t:ty) => {
46        impl<'a> ::std::ops::AddAssign<&'a Self> for $t {
47            #[inline]
48            fn add_assign(&mut self, rhs: &'a Self) {
49                *self = *self + *rhs;
50            }
51        }
52        impl<'a> ::std::ops::SubAssign<&'a Self> for $t {
53            #[inline]
54            fn sub_assign(&mut self, rhs: &'a Self) {
55                *self = *self - *rhs;
56            }
57        }
58        impl<'a> ::std::ops::ShlAssign<u32> for $t {
59            #[inline]
60            fn shl_assign(&mut self, rhs: u32) {
61                *self = *self << rhs;
62            }
63        }
64        impl<'a> ::std::ops::ShrAssign<u32> for $t {
65            #[inline]
66            fn shr_assign(&mut self, rhs: u32) {
67                *self = *self >> rhs;
68            }
69        }
70    };
71}
72
73macro_rules! impl_saturating {
74    ($t:ty) => {
75        impl ::std::ops::Add for Saturating<$t> {
76            type Output = Self;
77            #[inline]
78            fn add(self, rhs: Self) -> Self {
79                Self(self.0.saturating_add(rhs.0))
80            }
81        }
82
83        impl ::std::ops::Sub for Saturating<$t> {
84            type Output = Self;
85            #[inline]
86            fn sub(self, rhs: Self) -> Self {
87                Self(if self.0 == <$t>::MAX {
88                    <$t>::MAX
89                } else {
90                    self.0 - rhs.0
91                })
92            }
93        }
94
95        impl ::std::ops::Shl<u32> for Saturating<$t> {
96            type Output = Self;
97            #[inline]
98            fn shl(self, rhs: u32) -> Self {
99                Self(self.0.checked_shl(rhs).unwrap_or(<$t>::MAX))
100            }
101        }
102
103        impl ::std::ops::Shr<u32> for Saturating<$t> {
104            type Output = Self;
105            #[inline]
106            fn shr(self, rhs: u32) -> Self {
107                Self(if self.0 == <$t>::MAX {
108                    <$t>::MAX
109                } else {
110                    self.0 >> rhs
111                })
112            }
113        }
114
115        impl_assign_via_copy!(Saturating<$t>);
116    };
117}
118
119impl_saturating!(u64);
120impl_saturating!(u128);
121
122/// Floating point number like [`f64`], but with [`Shl<u32>`] and
123/// [`Shr<u32>`].
124#[derive(Clone, Copy, PartialEq, PartialOrd)]
125#[repr(transparent)]
126pub struct F64(pub f64);
127
128impl From<u32> for F64 {
129    #[inline]
130    fn from(value: u32) -> Self {
131        Self(value as f64)
132    }
133}
134
135/// cbindgen:ignore
136impl IsFloatingPoint for F64 {
137    const FLOATING_POINT: bool = true;
138    const MIN_EXP: i32 = f64::MIN_EXP;
139}
140
141impl Add for F64 {
142    type Output = F64;
143    #[inline]
144    fn add(self, rhs: F64) -> F64 {
145        F64(self.0 + rhs.0)
146    }
147}
148impl Sub for F64 {
149    type Output = F64;
150    #[inline]
151    fn sub(self, rhs: F64) -> F64 {
152        F64(self.0 - rhs.0)
153    }
154}
155
156impl Shl<u32> for F64 {
157    type Output = F64;
158    #[inline]
159    #[allow(clippy::suspicious_arithmetic_impl)]
160    fn shl(self, rhs: u32) -> F64 {
161        F64(self.0 * (rhs as f64).exp2())
162    }
163}
164impl Shr<u32> for F64 {
165    type Output = F64;
166    #[inline]
167    #[allow(clippy::suspicious_arithmetic_impl)]
168    fn shr(self, rhs: u32) -> F64 {
169        F64(self.0 * (-(rhs as f64)).exp2())
170    }
171}
172
173impl_assign_via_copy!(F64);