Skip to main content

malachite_nz/natural/comparison/
partial_cmp_primitive_int.rs

1// Copyright © 2026 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::natural::InnerNatural::{Large, Small};
10use crate::natural::{Natural, bit_to_limb_count_ceiling, limb_to_bit_count};
11use crate::platform::Limb;
12use core::cmp::Ordering::{self, *};
13use malachite_base::num::basic::integers::{PrimitiveInt, USIZE_IS_U32};
14use malachite_base::num::conversion::traits::WrappingFrom;
15use malachite_base::num::logic::traits::SignificantBits;
16
17macro_rules! impl_partial_ord_limb {
18    ($u: ident) => {
19        impl PartialOrd<$u> for Natural {
20            /// Compares a [`Natural`] to a [`Limb`](crate#limbs).
21            ///
22            /// # Worst-case complexity
23            /// Constant time and additional memory.
24            ///
25            /// # Examples
26            /// See [here](super::partial_cmp_primitive_int#partial_cmp).
27            fn partial_cmp(&self, other: &$u) -> Option<Ordering> {
28                match self {
29                    Natural(Small(small)) => small.partial_cmp(other),
30                    Natural(Large(_)) => Some(Greater),
31                }
32            }
33        }
34
35        impl PartialOrd<Natural> for $u {
36            /// Compares a [`Limb`](crate#limbs) to a [`Natural`].
37            ///
38            /// # Worst-case complexity
39            /// Constant time and additional memory.
40            ///
41            /// # Examples
42            /// See [here](super::partial_cmp_primitive_int#partial_cmp).
43            #[inline]
44            fn partial_cmp(&self, other: &Natural) -> Option<Ordering> {
45                other.partial_cmp(self).map(Ordering::reverse)
46            }
47        }
48    };
49}
50
51macro_rules! impl_partial_ord_smaller_than_limb {
52    ($u: ident) => {
53        impl PartialOrd<$u> for Natural {
54            /// Compares a [`Natural`] to a value of an unsigned primitive integer type that's
55            /// smaller than a [`Limb`](crate#limbs).
56            ///
57            /// # Worst-case complexity
58            /// Constant time and additional memory.
59            ///
60            /// # Examples
61            /// See [here](super::partial_cmp_primitive_int#partial_cmp).
62            #[inline]
63            fn partial_cmp(&self, other: &$u) -> Option<Ordering> {
64                self.partial_cmp(&Limb::from(*other))
65            }
66        }
67
68        impl PartialOrd<Natural> for $u {
69            /// Compares a value of an unsigned primitive integer type that's smaller than a
70            /// [`Limb`](crate#limbs) to a [`Natural`].
71            ///
72            /// # Worst-case complexity
73            /// Constant time and additional memory.
74            ///
75            /// # Examples
76            /// See [here](super::partial_cmp_primitive_int#partial_cmp).
77            #[inline]
78            fn partial_cmp(&self, other: &Natural) -> Option<Ordering> {
79                other.partial_cmp(self).map(Ordering::reverse)
80            }
81        }
82    };
83}
84
85macro_rules! impl_partial_ord_larger_than_limb_or_usize {
86    ($u: ident) => {
87        impl PartialOrd<Natural> for $u {
88            /// Compares a value of an unsigned primitive integer type that's larger than a
89            /// [`Limb`](crate#limbs) to a [`Natural`]. This implementation is general enough to
90            /// also work for [`usize`], regardless of whether it is equal in width to
91            /// [`Limb`](crate#limbs).
92            ///
93            /// # Worst-case complexity
94            /// Constant time and additional memory.
95            ///
96            /// # Examples
97            /// See [here](super::partial_cmp_primitive_int#partial_cmp).
98            #[inline]
99            fn partial_cmp(&self, other: &Natural) -> Option<Ordering> {
100                other.partial_cmp(self).map(Ordering::reverse)
101            }
102        }
103    };
104}
105
106macro_rules! impl_partial_ord_larger_than_limb {
107    ($u: ident) => {
108        impl_partial_ord_larger_than_limb_or_usize!($u);
109
110        impl PartialOrd<$u> for Natural {
111            /// Compares a [`Natural`] to a value of an unsigned primitive integer type that's
112            /// larger than a [`Limb`](crate#limbs).
113            ///
114            /// # Worst-case complexity
115            /// Constant time and additional memory.
116            ///
117            /// # Examples
118            /// See [here](super::partial_cmp_primitive_int#partial_cmp).
119            #[inline]
120            fn partial_cmp(&self, other: &$u) -> Option<Ordering> {
121                let limb_count = bit_to_limb_count_ceiling(other.significant_bits());
122                let limb_count_cmp = usize::wrapping_from(self.limb_count()).cmp(&limb_count);
123                if limb_count_cmp != Equal || limb_count == 0 {
124                    return Some(limb_count_cmp);
125                }
126                let width = Limb::WIDTH;
127                let mut i = limb_to_bit_count(limb_count);
128                let mut mask = $u::from(Limb::MAX) << (i - width);
129                for limb in self.limbs().rev() {
130                    i -= width;
131                    let limb_cmp = limb.cmp(&Limb::wrapping_from((other & mask) >> i));
132                    if limb_cmp != Equal {
133                        return Some(limb_cmp);
134                    }
135                    mask >>= width;
136                }
137                Some(Equal)
138            }
139        }
140    };
141}
142
143macro_rules! impl_signed {
144    ($t: ident) => {
145        impl PartialOrd<$t> for Natural {
146            /// Compares a [`Natural`] to a signed primitive integer.
147            ///
148            /// # Worst-case complexity
149            /// Constant time and additional memory.
150            ///
151            /// # Examples
152            /// See [here](super::partial_cmp_primitive_int#partial_cmp).
153            fn partial_cmp(&self, other: &$t) -> Option<Ordering> {
154                if *other < 0 {
155                    Some(Greater)
156                } else {
157                    self.partial_cmp(&other.unsigned_abs())
158                }
159            }
160        }
161
162        impl PartialOrd<Natural> for $t {
163            /// Compares a signed primitive integer to a [`Natural`].
164            ///
165            /// # Worst-case complexity
166            /// Constant time and additional memory.
167            ///
168            /// # Examples
169            /// See [here](super::partial_cmp_primitive_int#partial_cmp).
170            #[inline]
171            fn partial_cmp(&self, other: &Natural) -> Option<Ordering> {
172                other.partial_cmp(self).map(Ordering::reverse)
173            }
174        }
175    };
176}
177
178impl_partial_ord_smaller_than_limb!(u8);
179impl_partial_ord_smaller_than_limb!(u16);
180#[cfg(feature = "32_bit_limbs")]
181impl_partial_ord_limb!(u32);
182#[cfg(not(feature = "32_bit_limbs"))]
183impl_partial_ord_smaller_than_limb!(u32);
184#[cfg(feature = "32_bit_limbs")]
185impl_partial_ord_larger_than_limb!(u64);
186#[cfg(not(feature = "32_bit_limbs"))]
187impl_partial_ord_limb!(u64);
188impl_partial_ord_larger_than_limb!(u128);
189impl_partial_ord_larger_than_limb_or_usize!(usize);
190
191apply_to_signeds!(impl_signed);
192
193impl PartialOrd<usize> for Natural {
194    /// Compares a [`Natural`] to a [`usize`].
195    ///
196    /// # Worst-case complexity
197    /// Constant time and additional memory.
198    ///
199    /// # Examples
200    /// See [here](super::partial_cmp_primitive_int#partial_cmp).
201    #[inline]
202    fn partial_cmp(&self, other: &usize) -> Option<Ordering> {
203        if USIZE_IS_U32 {
204            self.partial_cmp(&u32::wrapping_from(*other))
205        } else {
206            assert_eq!(usize::WIDTH, u64::WIDTH);
207            self.partial_cmp(&u64::wrapping_from(*other))
208        }
209    }
210}