use crate::natural::InnerNatural::{Large, Small};
use crate::natural::Natural;
use crate::natural::logic::count_ones::limbs_count_ones;
use crate::platform::Limb;
use core::cmp::Ordering::*;
use malachite_base::num::logic::traits::HammingDistance;
pub_test! {limbs_hamming_distance_limb(xs: &[Limb], y: Limb) -> u64 {
xs[0].hamming_distance(y) + limbs_count_ones(&xs[1..])
}}
pub_crate_test! {limbs_hamming_distance_same_length(xs: &[Limb], ys: &[Limb]) -> u64 {
assert_eq!(xs.len(), ys.len());
xs.iter()
.zip(ys.iter())
.map(|(x, &y)| x.hamming_distance(y))
.sum()
}}
pub_test! {limbs_hamming_distance(xs: &[Limb], ys: &[Limb]) -> u64 {
let xs_len = xs.len();
let ys_len = ys.len();
match xs_len.cmp(&ys_len) {
Equal => limbs_hamming_distance_same_length(xs, ys),
Less => {
limbs_hamming_distance_same_length(xs, &ys[..xs_len]) + limbs_count_ones(&ys[xs_len..])
}
Greater => {
limbs_hamming_distance_same_length(&xs[..ys_len], ys) + limbs_count_ones(&xs[ys_len..])
}
}
}}
impl Natural {
fn hamming_distance_limb(&self, other: Limb) -> u64 {
match self {
Self(Small(small)) => small.hamming_distance(other),
Self(Large(limbs)) => limbs_hamming_distance_limb(limbs, other),
}
}
}
impl HammingDistance<&Natural> for &Natural {
fn hamming_distance(self, other: &Natural) -> u64 {
match (self, other) {
(&Natural(Small(x)), _) => other.hamming_distance_limb(x),
(_, &Natural(Small(y))) => self.hamming_distance_limb(y),
(Natural(Large(xs)), Natural(Large(ys))) => limbs_hamming_distance(xs, ys),
}
}
}