Skip to content

Commit

Permalink
Merge pull request #21 from isaacholt100/const_trait_fillers
Browse files Browse the repository at this point in the history
Add support for const-trait methods defined on the types themselves
  • Loading branch information
isaacholt100 committed May 27, 2023
2 parents cb9df63 + c4ce707 commit 4194e9a
Show file tree
Hide file tree
Showing 18 changed files with 489 additions and 296 deletions.
3 changes: 3 additions & 0 deletions changes/v0.7.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Removal of `const` impls of standard library traits, addition of equivalent methods defined on the integer types themselves.
`abs_diff`, `BUint::{overflowing_neg, wrapping_neg}` now `const`.
(TODO): implementation of `Arbitrary`.
40 changes: 7 additions & 33 deletions src/bint/cmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,12 @@ macro_rules! cmp {
impl<const N: usize> const PartialEq for $BInt<N> {
#[inline]
fn eq(&self, other: &Self) -> bool {
$BUint::eq(&self.bits, &other.bits)
Self::eq(self, other)
}
}
}

//impl_const! {
impl<const N: usize> Eq for $BInt<N> {}
//}
impl<const N: usize> Eq for $BInt<N> {}

impl_const! {
impl<const N: usize> const PartialOrd for $BInt<N> {
Expand All @@ -29,46 +27,22 @@ macro_rules! cmp {
impl<const N: usize> const Ord for $BInt<N> {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
let s1 = self.signed_digit();
let s2 = other.signed_digit();

// Don't use match here as `cmp` is not yet const for primitive integers
#[allow(clippy::comparison_chain)]
if s1 == s2 {
$BUint::cmp(&self.bits, &other.bits)
} else if s1 > s2 {
Ordering::Greater
} else {
Ordering::Less
}
Self::cmp(self, other)
}

#[inline]
fn max(self, other: Self) -> Self {
match self.cmp(&other) {
Ordering::Less | Ordering::Equal => other,
_ => self,
}
Self::max(self, other)
}

#[inline]
fn min(self, other: Self) -> Self {
match self.cmp(&other) {
Ordering::Less | Ordering::Equal => self,
_ => other,
}
}
Self::min(self, other)
}

#[inline]
fn clamp(self, min: Self, max: Self) -> Self {
assert!(min <= max);
if let Ordering::Less = self.cmp(&min) {
min
} else if let Ordering::Greater = self.cmp(&max) {
max
} else {
self
}
Self::clamp(self, min, max)
}
}
}
Expand Down
96 changes: 96 additions & 0 deletions src/bint/const_trait_fillers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
use core::cmp::Ordering;
use crate::ExpType;

macro_rules! const_trait_fillers {
($BUint: ident, $BInt: ident, $Digit: ident) => {
impl<const N: usize> $BInt<N> {
#[inline]
pub const fn bitand(self, rhs: Self) -> Self {
Self::from_bits(self.bits.bitand(rhs.bits))
}

#[inline]
pub const fn bitor(self, rhs: Self) -> Self {
Self::from_bits(self.bits.bitor(rhs.bits))
}

#[inline]
pub const fn bitxor(self, rhs: Self) -> Self {
Self::from_bits(self.bits.bitxor(rhs.bits))
}

#[inline]
pub const fn not(self) -> Self {
Self::from_bits(self.bits.not())
}

#[inline]
pub const fn eq(&self, other: &Self) -> bool {
$BUint::eq(&self.bits, &other.bits)
}

#[inline]
pub const fn ne(&self, other: &Self) -> bool {
!Self::eq(self, other)
}

#[inline]
pub const fn cmp(&self, other: &Self) -> Ordering {
let s1 = self.signed_digit();
let s2 = other.signed_digit();

// Don't use match here as `cmp` is not yet const for primitive integers
#[allow(clippy::comparison_chain)]
if s1 == s2 {
$BUint::cmp(&self.bits, &other.bits)
} else if s1 > s2 {
Ordering::Greater
} else {
Ordering::Less
}
}

crate::int::cmp::impls!();
#[inline]
pub const fn neg(self) -> Self {
#[cfg(debug_assertions)]
return crate::errors::option_expect!(self.checked_neg(), crate::errors::err_msg!("attempt to negate with overflow"));

#[cfg(not(debug_assertions))]
self.wrapping_neg()
}

crate::int::ops::trait_fillers!();

crate::nightly::const_fn! {
#[inline]
pub const fn div(self, rhs: Self) -> Self {
if self.eq(&Self::MIN) && rhs.eq(&Self::NEG_ONE) {
panic!(crate::errors::err_msg!("attempt to divide with overflow"))
} else {
if rhs.is_zero() {
crate::errors::div_zero!()
}
self.div_rem_unchecked(rhs).0
}
}
}

crate::nightly::const_fn! {
#[inline]
pub const fn rem(self, rhs: Self) -> Self {
if self.eq(&Self::MIN) && rhs.eq(&Self::NEG_ONE) {
panic!(crate::errors::err_msg!("attempt to calculate remainder with overflow"))
} else {
if rhs.is_zero() {
crate::errors::rem_zero!()
}
self.div_rem_unchecked(rhs).1
}
}
}
}
};
}

crate::macro_impl!(const_trait_fillers);
35 changes: 18 additions & 17 deletions src/bint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,15 +151,15 @@ macro_rules! mod_impl {
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn div_euclid(self, rhs: Self) -> Self {
assert!(self != Self::MIN || rhs != Self::NEG_ONE, errors::err_msg!("attempt to divide with overflow"));
assert!(self.ne(&Self::MIN) || rhs.ne(&Self::NEG_ONE), errors::err_msg!("attempt to divide with overflow"));
self.wrapping_div_euclid(rhs)
}

#[doc = doc::rem_euclid!(I)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn rem_euclid(self, rhs: Self) -> Self {
assert!(self != Self::MIN || rhs != Self::NEG_ONE, errors::err_msg!("attempt to calculate remainder with overflow"));
assert!(self.ne(&Self::MIN) || rhs.ne(&Self::NEG_ONE), errors::err_msg!("attempt to calculate remainder with overflow"));
self.wrapping_rem_euclid(rhs)
}
}
Expand Down Expand Up @@ -226,18 +226,18 @@ macro_rules! mod_impl {
ilog!(ilog2);
ilog!(ilog10);

crate::nightly::const_fns! {
#[doc = doc::abs_diff!(I)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn abs_diff(self, other: Self) -> $BUint<N> {
if self < other {
other.wrapping_sub(self).to_bits()
} else {
self.wrapping_sub(other).to_bits()
}
#[doc = doc::abs_diff!(I)]
#[must_use = doc::must_use_op!()]
#[inline]
pub const fn abs_diff(self, other: Self) -> $BUint<N> {
if self.lt(other) {
other.wrapping_sub(self).to_bits()
} else {
self.wrapping_sub(other).to_bits()
}

}

crate::nightly::const_fns! {
#[doc = doc::next_multiple_of!(I)]
#[must_use = doc::must_use_op!()]
#[inline]
Expand All @@ -247,9 +247,9 @@ macro_rules! mod_impl {
return self;
}
if rem.is_negative() == rhs.is_negative() {
self + (rhs - rem)
self.add(rhs.sub(rem))
} else {
self - rem
self.sub(rem)
}
}

Expand All @@ -264,7 +264,7 @@ macro_rules! mod_impl {
if rem.is_zero() || self.is_negative() == rhs.is_negative() {
div
} else {
div - Self::ONE
div.sub(Self::ONE)
}
}

Expand All @@ -279,7 +279,7 @@ macro_rules! mod_impl {
if rem.is_zero() || self.is_negative() != rhs.is_negative() {
div
} else {
div + Self::ONE
div.add(Self::ONE)
}
}
}
Expand Down Expand Up @@ -474,6 +474,7 @@ crate::macro_impl!(mod_impl);
mod cast;
mod checked;
mod cmp;
mod const_trait_fillers;
mod consts;
mod convert;
mod endian;
Expand Down
40 changes: 11 additions & 29 deletions src/bint/ops.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use crate::errors;
use crate::ExpType;
use core::ops::{
Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
Expand All @@ -13,11 +12,7 @@ macro_rules! ops {

#[inline]
fn neg(self) -> Self {
#[cfg(debug_assertions)]
return errors::option_expect!(self.checked_neg(), errors::err_msg!("attempt to negate with overflow"));

#[cfg(not(debug_assertions))]
self.wrapping_neg()
Self::neg(self)
}
}
}
Expand All @@ -28,7 +23,7 @@ macro_rules! ops {

#[inline]
fn neg(self) -> $BInt<N> {
(*self).neg()
$BInt::neg(*self)
}
}
}
Expand All @@ -39,7 +34,7 @@ macro_rules! ops {

#[inline]
fn bitand(self, rhs: Self) -> Self {
Self::from_bits(self.bits & rhs.bits)
Self::bitand(self, rhs)
}
}
}
Expand All @@ -50,7 +45,7 @@ macro_rules! ops {

#[inline]
fn bitor(self, rhs: Self) -> Self {
Self::from_bits(self.bits | rhs.bits)
Self::bitor(self, rhs)
}
}
}
Expand All @@ -61,7 +56,7 @@ macro_rules! ops {

#[inline]
fn bitxor(self, rhs: Self) -> Self {
Self::from_bits(self.bits ^ rhs.bits)
Self::bitxor(self, rhs)
}
}
}
Expand All @@ -70,15 +65,9 @@ macro_rules! ops {
impl<const N: usize> const Div for $BInt<N> {
type Output = Self;

#[inline]
fn div(self, rhs: Self) -> Self {
if self.eq(&Self::MIN) && rhs.eq(&Self::NEG_ONE) {
panic!(crate::errors::err_msg!("attempt to divide with overflow"))
} else {
if rhs.is_zero() {
errors::div_zero!()
}
self.div_rem_unchecked(rhs).0
}
Self::div(self, rhs)
}
}
}
Expand All @@ -87,26 +76,19 @@ macro_rules! ops {
impl<const N: usize> const Not for $BInt<N> {
type Output = Self;

#[inline]
fn not(self) -> Self {
Self::from_bits(!self.bits)
}
Self::not(self)
}
}
}

crate::nightly::impl_const! {
impl<const N: usize> const Rem for $BInt<N> {
type Output = Self;

#[inline]
fn rem(self, rhs: Self) -> Self {
if self.eq(&Self::MIN) && rhs.eq(&Self::NEG_ONE) {
panic!(crate::errors::err_msg!("attempt to calculate remainder with overflow"))
} else {
if rhs.is_zero() {
errors::rem_zero!()
}
self.div_rem_unchecked(rhs).1
}
Self::rem(self, rhs)
}
}
}
Expand Down
Loading

0 comments on commit 4194e9a

Please sign in to comment.