Skip to content

Commit c6cc7f8

Browse files
authored
arrow-buffer: implement num-traits numeric operations (#8977)
# Which issue does this PR close? - Closes #8976 # Rationale for this change `i256` doesn't implement some numeric traits. It'd be good to have it supported alongside other standard types. # What changes are included in this PR? - Trait implementations (checked ops, `Num`, `One`, `Zero`) using already written methods - Unit tests Not all traits are implemented (checked shl/shr, pow is not here yet). The main point of this PR is to provide a starting implementation. # Are these changes tested? Tested via new unit test # Are there any user-facing changes? Only new trait implementation.
1 parent 5db072f commit c6cc7f8

1 file changed

Lines changed: 213 additions & 1 deletion

File tree

arrow-buffer/src/bigint/mod.rs

Lines changed: 213 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@
1818
use crate::arith::derive_arith;
1919
use crate::bigint::div::div_rem;
2020
use num_bigint::BigInt;
21-
use num_traits::{FromPrimitive, ToPrimitive, cast::AsPrimitive};
21+
use num_traits::{
22+
Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedSub, FromPrimitive,
23+
Num, One, Signed, ToPrimitive, WrappingAdd, WrappingMul, WrappingNeg, WrappingSub, Zero,
24+
cast::AsPrimitive,
25+
};
2226
use std::cmp::Ordering;
2327
use std::num::ParseIntError;
2428
use std::ops::{BitAnd, BitOr, BitXor, Neg, Shl, Shr};
@@ -869,6 +873,137 @@ impl ToPrimitive for i256 {
869873
}
870874
}
871875

876+
// num_traits checked implementations
877+
878+
impl CheckedNeg for i256 {
879+
fn checked_neg(&self) -> Option<Self> {
880+
(*self).checked_neg()
881+
}
882+
}
883+
884+
impl CheckedAdd for i256 {
885+
fn checked_add(&self, v: &i256) -> Option<Self> {
886+
(*self).checked_add(*v)
887+
}
888+
}
889+
890+
impl CheckedSub for i256 {
891+
fn checked_sub(&self, v: &i256) -> Option<Self> {
892+
(*self).checked_sub(*v)
893+
}
894+
}
895+
896+
impl CheckedDiv for i256 {
897+
fn checked_div(&self, v: &i256) -> Option<Self> {
898+
(*self).checked_div(*v)
899+
}
900+
}
901+
902+
impl CheckedMul for i256 {
903+
fn checked_mul(&self, v: &i256) -> Option<Self> {
904+
(*self).checked_mul(*v)
905+
}
906+
}
907+
908+
impl CheckedRem for i256 {
909+
fn checked_rem(&self, v: &i256) -> Option<Self> {
910+
(*self).checked_rem(*v)
911+
}
912+
}
913+
914+
impl WrappingAdd for i256 {
915+
fn wrapping_add(&self, v: &Self) -> Self {
916+
(*self).wrapping_add(*v)
917+
}
918+
}
919+
920+
impl WrappingSub for i256 {
921+
fn wrapping_sub(&self, v: &Self) -> Self {
922+
(*self).wrapping_sub(*v)
923+
}
924+
}
925+
926+
impl WrappingMul for i256 {
927+
fn wrapping_mul(&self, v: &Self) -> Self {
928+
(*self).wrapping_mul(*v)
929+
}
930+
}
931+
932+
impl WrappingNeg for i256 {
933+
fn wrapping_neg(&self) -> Self {
934+
(*self).wrapping_neg()
935+
}
936+
}
937+
938+
impl Zero for i256 {
939+
fn zero() -> Self {
940+
i256::ZERO
941+
}
942+
943+
fn is_zero(&self) -> bool {
944+
*self == i256::ZERO
945+
}
946+
}
947+
948+
impl One for i256 {
949+
fn one() -> Self {
950+
i256::ONE
951+
}
952+
953+
fn is_one(&self) -> bool {
954+
*self == i256::ONE
955+
}
956+
}
957+
958+
impl Num for i256 {
959+
type FromStrRadixErr = ParseI256Error;
960+
961+
fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
962+
if radix == 10 {
963+
str.parse()
964+
} else {
965+
// Parsing from non-10 baseseeÎ is not supported
966+
Err(ParseI256Error {})
967+
}
968+
}
969+
}
970+
971+
impl Signed for i256 {
972+
fn abs(&self) -> Self {
973+
self.wrapping_abs()
974+
}
975+
976+
fn abs_sub(&self, other: &Self) -> Self {
977+
if self > other {
978+
self.wrapping_sub(other)
979+
} else {
980+
i256::ZERO
981+
}
982+
}
983+
984+
fn signum(&self) -> Self {
985+
(*self).signum()
986+
}
987+
988+
fn is_positive(&self) -> bool {
989+
(*self).is_positive()
990+
}
991+
992+
fn is_negative(&self) -> bool {
993+
(*self).is_negative()
994+
}
995+
}
996+
997+
impl Bounded for i256 {
998+
fn min_value() -> Self {
999+
i256::MIN
1000+
}
1001+
1002+
fn max_value() -> Self {
1003+
i256::MAX
1004+
}
1005+
}
1006+
8721007
#[cfg(all(test, not(miri)))] // llvm.x86.subborrow.64 not supported by MIRI
8731008
mod tests {
8741009
use super::*;
@@ -1337,6 +1472,83 @@ mod tests {
13371472
assert!(out.is_finite() && out.is_sign_negative());
13381473
}
13391474

1475+
#[test]
1476+
fn test_num_traits() {
1477+
let value = i256::from_i128(-5);
1478+
assert_eq!(
1479+
<i256 as CheckedNeg>::checked_neg(&value),
1480+
Some(i256::from(5))
1481+
);
1482+
1483+
assert_eq!(
1484+
<i256 as CheckedAdd>::checked_add(&value, &value),
1485+
Some(i256::from(-10))
1486+
);
1487+
1488+
assert_eq!(
1489+
<i256 as CheckedSub>::checked_sub(&value, &value),
1490+
Some(i256::from(0))
1491+
);
1492+
1493+
assert_eq!(
1494+
<i256 as CheckedMul>::checked_mul(&value, &value),
1495+
Some(i256::from(25))
1496+
);
1497+
1498+
assert_eq!(
1499+
<i256 as CheckedDiv>::checked_div(&value, &value),
1500+
Some(i256::from(1))
1501+
);
1502+
1503+
assert_eq!(
1504+
<i256 as CheckedRem>::checked_rem(&value, &value),
1505+
Some(i256::from(0))
1506+
);
1507+
1508+
assert_eq!(
1509+
<i256 as WrappingAdd>::wrapping_add(&value, &value),
1510+
i256::from(-10)
1511+
);
1512+
1513+
assert_eq!(
1514+
<i256 as WrappingSub>::wrapping_sub(&value, &value),
1515+
i256::from(0)
1516+
);
1517+
1518+
assert_eq!(
1519+
<i256 as WrappingMul>::wrapping_mul(&value, &value),
1520+
i256::from(25)
1521+
);
1522+
1523+
assert_eq!(<i256 as WrappingNeg>::wrapping_neg(&value), i256::from(5));
1524+
1525+
// A single check for wrapping behavior, rely on trait implementation for others
1526+
let result = <i256 as WrappingAdd>::wrapping_add(&i256::MAX, &i256::ONE);
1527+
assert_eq!(result, i256::MIN);
1528+
1529+
assert_eq!(<i256 as Signed>::abs(&value), i256::from(5));
1530+
1531+
assert_eq!(<i256 as One>::one(), i256::from(1));
1532+
assert_eq!(<i256 as Zero>::zero(), i256::from(0));
1533+
1534+
assert_eq!(<i256 as Bounded>::min_value(), i256::MIN);
1535+
assert_eq!(<i256 as Bounded>::max_value(), i256::MAX);
1536+
}
1537+
1538+
#[test]
1539+
fn test_numtraits_from_str_radix() {
1540+
assert_eq!(
1541+
i256::from_str_radix("123456789", 10).expect("parsed"),
1542+
i256::from(123456789)
1543+
);
1544+
assert_eq!(
1545+
i256::from_str_radix("0", 10).expect("parsed"),
1546+
i256::from(0)
1547+
);
1548+
assert!(i256::from_str_radix("abc", 10).is_err());
1549+
assert!(i256::from_str_radix("0", 16).is_err());
1550+
}
1551+
13401552
#[test]
13411553
fn test_leading_zeros() {
13421554
// Without high part

0 commit comments

Comments
 (0)