use crate::natural::InnerNatural::{Large, Small};
use crate::natural::Natural;
use crate::platform::Limb;
use core::cmp::Ordering::{self, *};
use core::mem::swap;
use malachite_base::num::basic::integers::PrimitiveInt;
use malachite_base::num::logic::traits::LeadingZeros;
use malachite_base::slices::{slice_leading_zeros, slice_test_zero};
pub_crate_test! {limbs_cmp_same_length(xs: &[Limb], ys: &[Limb]) -> Ordering {
assert_eq!(xs.len(), ys.len());
xs.iter().rev().cmp(ys.iter().rev())
}}
pub_crate_test! {limbs_cmp(xs: &[Limb], ys: &[Limb]) -> Ordering {
assert_ne!(xs.last(), Some(&0));
assert_ne!(ys.last(), Some(&0));
xs.len()
.cmp(&ys.len())
.then_with(|| limbs_cmp_same_length(xs, ys))
}}
pub_test! {limbs_cmp_normalized(xs: &[Limb], ys: &[Limb]) -> Ordering {
let mut xs = &xs[slice_leading_zeros(xs)..];
let mut ys = &ys[slice_leading_zeros(ys)..];
let mut xs_leading = LeadingZeros::leading_zeros(*xs.last().unwrap());
assert_ne!(xs_leading, Limb::WIDTH);
let mut ys_leading = LeadingZeros::leading_zeros(*ys.last().unwrap());
assert_ne!(ys_leading, Limb::WIDTH);
let mut xs_len = xs.len();
let mut ys_len = ys.len();
let mut swapped = false;
match xs_leading.cmp(&ys_leading) {
Equal => {
return match xs_len.cmp(&ys_len) {
Equal => limbs_cmp_same_length(xs, ys),
Less => {
let leading_cmp = limbs_cmp_same_length(xs, &ys[ys_len - xs_len..]);
if leading_cmp == Greater {
Greater
} else {
Less
}
}
Greater => {
let leading_cmp = limbs_cmp_same_length(&xs[xs_len - ys_len..], ys);
if leading_cmp == Less {
Less
} else {
Greater
}
}
};
}
Less => {
swap(&mut xs, &mut ys);
swap(&mut xs_leading, &mut ys_leading);
swap(&mut xs_len, &mut ys_len);
swapped = true;
}
_ => {}
}
let xs_shift = xs_leading - ys_leading;
let comp_xs_shift = Limb::WIDTH - xs_shift;
let mut xs_i = xs_len - 1;
let mut ys_i = ys_len - 1;
loop {
let y = ys[ys_i];
let xs_hi = xs[xs_i];
let xs_lo = if xs_i == 0 { 0 } else { xs[xs_i - 1] };
let x = (xs_hi << xs_shift) | (xs_lo >> comp_xs_shift);
let cmp = x.cmp(&y);
if cmp != Equal {
return if swapped { cmp.reverse() } else { cmp };
}
if xs_i == 0 {
return if ys_i == 0 {
Equal
} else if swapped {
Greater
} else {
Less
};
} else if ys_i == 0 {
return if xs_lo << xs_shift == 0 && slice_test_zero(&xs[..xs_i - 1]) {
Equal
} else if swapped {
Less
} else {
Greater
};
}
xs_i -= 1;
ys_i -= 1;
}
}}
impl PartialOrd for Natural {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Natural {
fn cmp(&self, other: &Self) -> Ordering {
if core::ptr::eq(self, other) {
return Equal;
}
match (self, other) {
(&Self(Small(ref x)), &Self(Small(ref y))) => x.cmp(y),
(&Self(Small(_)), &Self(Large(_))) => Less,
(&Self(Large(_)), &Self(Small(_))) => Greater,
(&Self(Large(ref xs)), &Self(Large(ref ys))) => limbs_cmp(xs, ys),
}
}
}
impl Natural {
pub fn cmp_normalized(&self, other: &Self) -> Ordering {
assert_ne!(*self, 0);
assert_ne!(*other, 0);
if core::ptr::eq(self, other) {
return Equal;
}
match (self, other) {
(&Self(Small(x)), &Self(Small(y))) => {
let leading_x = x.leading_zeros();
let leading_y = y.leading_zeros();
match leading_x.cmp(&leading_y) {
Equal => x.cmp(&y),
Less => x.cmp(&(y << (leading_y - leading_x))),
Greater => (x << (leading_x - leading_y)).cmp(&y),
}
}
(&Self(Small(x)), &Self(Large(ref ys))) => limbs_cmp_normalized(&[x], ys),
(&Self(Large(ref xs)), &Self(Small(y))) => limbs_cmp_normalized(xs, &[y]),
(&Self(Large(ref xs)), &Self(Large(ref ys))) => limbs_cmp_normalized(xs, ys),
}
}
#[cfg(feature = "float_helpers")]
pub fn cmp_normalized_no_shift(&self, other: &Self) -> Ordering {
assert_ne!(*self, 0);
assert_ne!(*other, 0);
if core::ptr::eq(self, other) {
return Equal;
}
match (self, other) {
(&Self(Small(x)), &Self(Small(y))) => x.cmp(&y),
(Self(Small(x)), &Self(Large(ref ys))) => {
let (ys_last, ys_init) = ys.split_last().unwrap();
let c = x.cmp(ys_last);
if c != Equal {
c
} else if slice_test_zero(ys_init) {
Equal
} else {
Less
}
}
(&Self(Large(ref xs)), Self(Small(y))) => {
let (xs_last, xs_init) = xs.split_last().unwrap();
let c = xs_last.cmp(y);
if c != Equal {
c
} else if slice_test_zero(xs_init) {
Equal
} else {
Greater
}
}
(&Self(Large(ref xs)), &Self(Large(ref ys))) => {
let xs_len = xs.len();
let ys_len = ys.len();
match xs_len.cmp(&ys_len) {
Equal => xs.iter().rev().cmp(ys.iter().rev()),
Less => {
let (ys_lo, ys_hi) = ys.split_at(ys_len - xs_len);
let c = xs.iter().rev().cmp(ys_hi.iter().rev());
if c != Equal {
c
} else if slice_test_zero(ys_lo) {
Equal
} else {
Less
}
}
Greater => {
let (xs_lo, xs_hi) = xs.split_at(xs_len - ys_len);
let c = xs_hi.iter().rev().cmp(ys.iter().rev());
if c != Equal {
c
} else if slice_test_zero(xs_lo) {
Equal
} else {
Greater
}
}
}
}
}
}
}