Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
214 changes: 213 additions & 1 deletion arrow-buffer/src/bigint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@
use crate::arith::derive_arith;
use crate::bigint::div::div_rem;
use num_bigint::BigInt;
use num_traits::{FromPrimitive, ToPrimitive, cast::AsPrimitive};
use num_traits::{
Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedSub, FromPrimitive,
Num, One, Signed, ToPrimitive, WrappingAdd, WrappingMul, WrappingNeg, WrappingSub, Zero,
cast::AsPrimitive,
};
use std::cmp::Ordering;
use std::num::ParseIntError;
use std::ops::{BitAnd, BitOr, BitXor, Neg, Shl, Shr};
Expand Down Expand Up @@ -869,6 +873,137 @@ impl ToPrimitive for i256 {
}
}

// num_traits checked implementations

impl CheckedNeg for i256 {
fn checked_neg(&self) -> Option<Self> {
(*self).checked_neg()
}
}

impl CheckedAdd for i256 {
fn checked_add(&self, v: &i256) -> Option<Self> {
(*self).checked_add(*v)
}
}

impl CheckedSub for i256 {
fn checked_sub(&self, v: &i256) -> Option<Self> {
(*self).checked_sub(*v)
}
}

impl CheckedDiv for i256 {
fn checked_div(&self, v: &i256) -> Option<Self> {
(*self).checked_div(*v)
}
}

impl CheckedMul for i256 {
fn checked_mul(&self, v: &i256) -> Option<Self> {
(*self).checked_mul(*v)
}
}

impl CheckedRem for i256 {
fn checked_rem(&self, v: &i256) -> Option<Self> {
(*self).checked_rem(*v)
}
}

impl WrappingAdd for i256 {
fn wrapping_add(&self, v: &Self) -> Self {
(*self).wrapping_add(*v)
}
}

impl WrappingSub for i256 {
fn wrapping_sub(&self, v: &Self) -> Self {
(*self).wrapping_sub(*v)
}
}

impl WrappingMul for i256 {
fn wrapping_mul(&self, v: &Self) -> Self {
(*self).wrapping_mul(*v)
}
}

impl WrappingNeg for i256 {
fn wrapping_neg(&self) -> Self {
(*self).wrapping_neg()
}
}

impl Zero for i256 {
fn zero() -> Self {
i256::ZERO
}

fn is_zero(&self) -> bool {
*self == i256::ZERO
}
}

impl One for i256 {
fn one() -> Self {
i256::ONE
}

fn is_one(&self) -> bool {
*self == i256::ONE
}
}

impl Num for i256 {
type FromStrRadixErr = ParseI256Error;

fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
if radix == 10 {
str.parse()
} else {
// Parsing from non-10 baseseeÎ is not supported
Err(ParseI256Error {})
}
}
}

impl Signed for i256 {
fn abs(&self) -> Self {
self.wrapping_abs()
}

fn abs_sub(&self, other: &Self) -> Self {
if self > other {
self.wrapping_sub(other)
} else {
i256::ZERO
}
}

fn signum(&self) -> Self {
(*self).signum()
}

fn is_positive(&self) -> bool {
(*self).is_positive()
}

fn is_negative(&self) -> bool {
(*self).is_negative()
}
}

impl Bounded for i256 {
fn min_value() -> Self {
i256::MIN
}

fn max_value() -> Self {
i256::MAX
}
}

#[cfg(all(test, not(miri)))] // llvm.x86.subborrow.64 not supported by MIRI
mod tests {
use super::*;
Expand Down Expand Up @@ -1337,6 +1472,83 @@ mod tests {
assert!(out.is_finite() && out.is_sign_negative());
}

#[test]
fn test_num_traits() {
let value = i256::from_i128(-5);
assert_eq!(
<i256 as CheckedNeg>::checked_neg(&value),
Some(i256::from(5))
);

assert_eq!(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for these tests -- can we also test the others (checked_sub, for example)?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, sure, let me add them for completeness

<i256 as CheckedAdd>::checked_add(&value, &value),
Some(i256::from(-10))
);

assert_eq!(
<i256 as CheckedSub>::checked_sub(&value, &value),
Some(i256::from(0))
);

assert_eq!(
<i256 as CheckedMul>::checked_mul(&value, &value),
Some(i256::from(25))
);

assert_eq!(
<i256 as CheckedDiv>::checked_div(&value, &value),
Some(i256::from(1))
);

assert_eq!(
<i256 as CheckedRem>::checked_rem(&value, &value),
Some(i256::from(0))
);

assert_eq!(
<i256 as WrappingAdd>::wrapping_add(&value, &value),
i256::from(-10)
);

assert_eq!(
<i256 as WrappingSub>::wrapping_sub(&value, &value),
i256::from(0)
);

assert_eq!(
<i256 as WrappingMul>::wrapping_mul(&value, &value),
i256::from(25)
);

assert_eq!(<i256 as WrappingNeg>::wrapping_neg(&value), i256::from(5));

// A single check for wrapping behavior, rely on trait implementation for others
let result = <i256 as WrappingAdd>::wrapping_add(&i256::MAX, &i256::ONE);
assert_eq!(result, i256::MIN);

assert_eq!(<i256 as Signed>::abs(&value), i256::from(5));

assert_eq!(<i256 as One>::one(), i256::from(1));
assert_eq!(<i256 as Zero>::zero(), i256::from(0));

assert_eq!(<i256 as Bounded>::min_value(), i256::MIN);
assert_eq!(<i256 as Bounded>::max_value(), i256::MAX);
}

#[test]
fn test_numtraits_from_str_radix() {
assert_eq!(
i256::from_str_radix("123456789", 10).expect("parsed"),
i256::from(123456789)
);
assert_eq!(
i256::from_str_radix("0", 10).expect("parsed"),
i256::from(0)
);
assert!(i256::from_str_radix("abc", 10).is_err());
assert!(i256::from_str_radix("0", 16).is_err());
}

#[test]
fn test_leading_zeros() {
// Without high part
Expand Down
Loading