From b89a7657a9e1820b0e95b322b00b60dece15cb04 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Sat, 7 Feb 2026 05:47:32 +0100 Subject: [PATCH] perf: specialize Ord::cmp for small sizes --- CHANGELOG.md | 6 ++++++ src/bits.rs | 4 ++-- src/cmp.rs | 12 ++++++++++++ src/from.rs | 2 +- src/macros.rs | 30 ++++++++++++++++++++---------- 5 files changed, 41 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cd83e55..097070bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- Specialize `Ord::cmp`, `const_eq`, `const_is_zero` for small sizes ([#561]) + +[#561]: https://github.com/recmo/uint/pull/561 + ## [1.17.2] - 2025-12-28 ### Fixed diff --git a/src/bits.rs b/src/bits.rs index fef5179d..a2ea24fb 100644 --- a/src/bits.rs +++ b/src/bits.rs @@ -157,10 +157,10 @@ impl Uint { pub const fn leading_zeros(&self) -> usize { let fixed = Self::MASK.leading_zeros() as usize; - as_primitives!(self, { + as_primitives!(self; { u64(x) => return x.leading_zeros() as usize - fixed, u128(x) => return x.leading_zeros() as usize - fixed, - u256(lo, hi) => return (select_unpredictable_u32(hi != 0, + u256((lo, hi)) => return (select_unpredictable_u32(hi != 0, hi.leading_zeros(), lo.leading_zeros() + 128 )) as usize - fixed, diff --git a/src/cmp.rs b/src/cmp.rs index 47ede059..a263e99a 100644 --- a/src/cmp.rs +++ b/src/cmp.rs @@ -11,6 +11,10 @@ impl PartialOrd for Uint { impl Ord for Uint { #[inline] fn cmp(&self, rhs: &Self) -> Ordering { + as_primitives!(self, rhs; { + u64(x, y) => return x.cmp(&y), + u128(x, y) => return x.cmp(&y), + }); crate::algorithms::cmp(self.as_limbs(), rhs.as_limbs()) } } @@ -82,6 +86,10 @@ impl Uint { #[inline] #[must_use] pub const fn const_is_zero(&self) -> bool { + as_primitives!(self; { + u64(x) => return x == 0, + u128(x) => return x == 0, + }); self.const_eq(&Self::ZERO) } @@ -92,6 +100,10 @@ impl Uint { #[inline] #[must_use] pub const fn const_eq(&self, other: &Self) -> bool { + as_primitives!(self, other; { + u64(x, y) => return x == y, + u128(x, y) => return x == y, + }); // TODO: Replace with `self == other` and deprecate once `PartialEq` is const. let a = self.as_limbs(); let b = other.as_limbs(); diff --git a/src/from.rs b/src/from.rs index 2ab2a17e..e92e8eb9 100644 --- a/src/from.rs +++ b/src/from.rs @@ -807,7 +807,7 @@ impl Uint { /// Convert to IEEE 754 double precision float bit representation. #[inline] fn as_f64_bits(&self) -> u64 { - as_primitives!(self, { + as_primitives!(self; { u64(x) => return f64::to_bits(x as f64), }); diff --git a/src/macros.rs b/src/macros.rs index a8ff8fb1..04ef869d 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -116,29 +116,39 @@ macro_rules! let_double_bits { /// Specialize an operation for u64, u128, u256 ([u128; 2])... macro_rules! as_primitives { - ($uint:expr, { $($arm:ident $t:tt => $e:expr),* $(,)? }) => { + ($($uints:expr),* $(,)?; $($rest:tt)*) => { + as_primitives!(@inner ($($uints),*); $($rest)*); + }; + + (@inner $uints:tt; { $($arm:ident $t:tt => $e:expr),* $(,)? }) => { $( - as_primitives!(@arm $uint; $arm $t => $e); + as_primitives!(@arm $uints; $arm $t => $e); )* }; - (@arm $uint:expr; u64($n:ident) => $e:expr) => { + (@arm ($($uint:expr),*); u64($($n:pat),*) => $e:expr) => { if LIMBS == 1 { - let $n = $uint.limbs[0]; + $( + let $n = $uint.limbs[0]; + )* $e } }; - (@arm $uint:expr; u128($n:ident) => $e:expr) => { + (@arm ($($uint:expr),*); u128($($n:pat),*) => $e:expr) => { if LIMBS == 2 { - let $n = $uint.as_double_words()[0].get(); + $( + let $n = $uint.as_double_words()[0].get(); + )* $e } }; - (@arm $uint:expr; u256($lo:ident, $hi:ident) => $e:expr) => { + (@arm ($($uint:expr),*); u256($(($lo:pat, $hi:pat)),*) => $e:expr) => { if LIMBS == 4 { - let &[lo, hi] = $uint.as_double_words() else { unreachable!() }; - let $lo = lo.get(); - let $hi = hi.get(); + $( + let &[lo, hi] = $uint.as_double_words() else { unreachable!() }; + let $lo = lo.get(); + let $hi = hi.get(); + )* $e } };