Skip to content

Commit

Permalink
feat: Implement more checked_* methods
Browse files Browse the repository at this point in the history
  • Loading branch information
sorairolake committed Nov 14, 2024
1 parent 1addd14 commit 17fd4e9
Show file tree
Hide file tree
Showing 4 changed files with 227 additions and 0 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ project adheres to https://semver.org/[Semantic Versioning].
({pull-request-url}/7[#7])
* Implement `From<BitInt>` and `From<BitUint>` for the underlying type
({pull-request-url}/8[#8])
* Implement `BitInt::checked_neg` and `BitUint::checked_neg`
({pull-request-url}/10[#10])
* Implement `BitInt::checked_abs` ({pull-request-url}/10[#10])
* Implement `BitInt::checked_pow` and `BitUint::checked_pow`
({pull-request-url}/10[#10])

== {project-url}/releases/tag/v0.1.0[0.1.0] - 2024-11-12

Expand Down
35 changes: 35 additions & 0 deletions benches/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,38 @@ fn checked_rem_bit_uint(b: &mut Bencher) {

b.iter(|| n.checked_rem(2));
}

#[bench]
fn checked_neg_bit_int(b: &mut Bencher) {
let n = BitI32::<31>::new(5).unwrap();

b.iter(|| n.checked_neg());
}

#[bench]
fn checked_neg_bit_uint(b: &mut Bencher) {
let n = BitU32::<31>::MIN;

b.iter(|| n.checked_neg());
}

#[bench]
fn checked_abs(b: &mut Bencher) {
let n = BitI32::<31>::new(-5).unwrap();

b.iter(|| n.checked_abs());
}

#[bench]
fn checked_pow_bit_int(b: &mut Bencher) {
let n = BitI32::<31>::new(8).unwrap();

b.iter(|| n.checked_pow(2));
}

#[bench]
fn checked_pow_bit_uint(b: &mut Bencher) {
let n = BitU32::<31>::new(2).unwrap();

b.iter(|| n.checked_pow(5));
}
111 changes: 111 additions & 0 deletions src/bit_int/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,78 @@ macro_rules! impl_ops {
_ => None,
}
}

/// Negates `self`.
///
/// Returns [`None`] if `self` is [`Self::MIN`].
///
/// # Examples
///
/// ```
/// # use bit_int::BitInt;
/// #
#[doc = concat!("let n = BitInt::<", stringify!($T), ", 4>::new(5).unwrap();")]
///
/// assert_eq!(n.checked_neg().map(BitInt::get), Some(-5));
#[doc = concat!("assert!(BitInt::<", stringify!($T), ", 4>::MIN.checked_neg().is_none());")]
/// ```
#[must_use]
#[inline]
pub const fn checked_neg(self) -> Option<Self> {
if let Some(result) = self.get().checked_neg() {
Self::new(result)
} else {
None
}
}

/// Computes the absolute value of `self`.
///
/// Returns [`None`] if `self` is [`Self::MIN`].
///
/// # Examples
///
/// ```
/// # use bit_int::BitInt;
/// #
#[doc = concat!("let n = BitInt::<", stringify!($T), ", 4>::new(-5).unwrap();")]
///
/// assert_eq!(n.checked_abs().map(BitInt::get), Some(5));
#[doc = concat!("assert!(BitInt::<", stringify!($T), ", 4>::MIN.checked_abs().is_none());")]
/// ```
#[must_use]
#[inline]
pub const fn checked_abs(self) -> Option<Self> {
if let Some(result) = self.get().checked_abs() {
Self::new(result)
} else {
None
}
}

/// Raises `self` to the power of `exp`, using exponentiation by squaring.
///
/// Returns [`None`] if overflow occurred.
///
/// # Examples
///
/// ```
/// # use bit_int::BitInt;
/// #
#[doc = concat!("let n = BitInt::<", stringify!($T), ", 8>::new(8).unwrap();")]
///
/// assert_eq!(n.checked_pow(2).map(BitInt::get), Some(64));
#[doc = concat!("assert!(BitInt::<", stringify!($T), ", 8>::MAX.checked_pow(2).is_none());")]
/// ```
#[must_use]
#[inline]
pub const fn checked_pow(self, exp: u32) -> Option<Self> {
if let Some(result) = self.get().checked_pow(exp) {
Self::new(result)
} else {
None
}
}
}
};
}
Expand Down Expand Up @@ -209,4 +281,43 @@ mod tests {
const fn checked_rem_is_const_fn() {
const _: Option<BitI8<4>> = BitI8::<4>::MAX.checked_rem(0);
}

#[test]
fn checked_neg() {
let n = BitI8::<4>::new(5).unwrap();

assert_eq!(n.checked_neg().map(BitI8::get), Some(-5));
assert!(BitI8::<4>::MIN.checked_neg().is_none());
}

#[test]
const fn checked_neg_is_const_fn() {
const _: Option<BitI8<4>> = BitI8::<4>::MIN.checked_neg();
}

#[test]
fn checked_abs() {
let n = BitI8::<4>::new(-5).unwrap();

assert_eq!(n.checked_abs().map(BitI8::get), Some(5));
assert!(BitI8::<4>::MIN.checked_abs().is_none());
}

#[test]
const fn checked_abs_is_const_fn() {
const _: Option<BitI8<4>> = BitI8::<4>::MIN.checked_abs();
}

#[test]
fn checked_pow() {
let n = BitI8::<8>::new(8).unwrap();

assert_eq!(n.checked_pow(2).map(BitI8::get), Some(64));
assert!(BitI8::<8>::MAX.checked_pow(2).is_none());
}

#[test]
const fn checked_pow_is_const_fn() {
const _: Option<BitI8<8>> = BitI8::<8>::MAX.checked_pow(2);
}
}
76 changes: 76 additions & 0 deletions src/bit_uint/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,58 @@ macro_rules! impl_ops {
None
}
}

/// Negates `self`.
///
/// Returns [`None`] unless `self` is `0`.
///
/// Note that negating any positive integer will overflow.
///
/// # Examples
///
/// ```
/// # use bit_int::BitUint;
/// #
///
/// assert_eq!(
#[doc = concat!(" BitUint::<", stringify!($T), ", 1>::MIN.checked_neg().map(BitUint::get),")]
/// Some(0)
/// );
#[doc = concat!("assert!(BitUint::<", stringify!($T), ", 1>::MAX.checked_neg().is_none());")]
/// ```
#[must_use]
#[inline]
pub const fn checked_neg(self) -> Option<Self> {
if let Some(result) = self.get().checked_neg() {
Self::new(result)
} else {
None
}
}

/// Raises `self` to the power of `exp`, using exponentiation by squaring.
///
/// Returns [`None`] if overflow occurred.
///
/// # Examples
///
/// ```
/// # use bit_int::BitUint;
/// #
#[doc = concat!("let n = BitUint::<", stringify!($T), ", 6>::new(2).unwrap();")]
///
/// assert_eq!(n.checked_pow(5).map(BitUint::get), Some(32));
#[doc = concat!("assert!(BitUint::<", stringify!($T), ", 6>::MAX.checked_pow(2).is_none());")]
/// ```
#[must_use]
#[inline]
pub const fn checked_pow(self, exp: u32) -> Option<Self> {
if let Some(result) = self.get().checked_pow(exp) {
Self::new(result)
} else {
None
}
}
}
};
}
Expand Down Expand Up @@ -206,4 +258,28 @@ mod tests {
const fn checked_rem_is_const_fn() {
const _: Option<BitU8<3>> = BitU8::<3>::MAX.checked_rem(0);
}

#[test]
fn checked_neg() {
assert_eq!(BitU8::<1>::MIN.checked_neg().map(BitU8::get), Some(0));
assert!(BitU8::<1>::MAX.checked_neg().is_none());
}

#[test]
const fn checked_neg_is_const_fn() {
const _: Option<BitU8<1>> = BitU8::<1>::MAX.checked_neg();
}

#[test]
fn checked_pow() {
let n = BitU8::<6>::new(2).unwrap();

assert_eq!(n.checked_pow(5).map(BitU8::get), Some(32));
assert!(BitU8::<6>::MAX.checked_pow(2).is_none());
}

#[test]
const fn checked_pow_is_const_fn() {
const _: Option<BitU8<6>> = BitU8::<6>::MAX.checked_pow(2);
}
}

0 comments on commit 17fd4e9

Please sign in to comment.