crate::ix!();
#[macro_export]
macro_rules! define_baseuint_bitxor {
($uint_type:ident, $bits:expr, $limbs:expr) => {
impl core::ops::BitXor<&$uint_type> for $uint_type {
type Output = $uint_type;
fn bitxor(self, other: &$uint_type) -> Self::Output {
let mut ret = self.clone();
ret ^= other;
ret
}
}
impl core::ops::BitXorAssign<&$uint_type> for $uint_type {
#[inline]
fn bitxor_assign(&mut self, b: &$uint_type) {
for i in 0..$limbs {
self.pn[i] ^= b.pn[i];
}
}
}
impl core::ops::BitXorAssign<u64> for $uint_type {
#[inline]
fn bitxor_assign(&mut self, b: u64) {
self.pn[0] ^= (b & 0xffff_ffff) as u32;
if $limbs > 1 {
self.pn[1] ^= ((b >> 32) & 0xffff_ffff) as u32;
}
}
}
}
}
#[cfg(test)]
mod base_uint_bitxor_exhaustive_tests {
use super::*;
#[traced_test]
fn test_bitxor_32_bits_edge_cases() {
info!("Testing bitwise XOR (`^=`) for 32-bit BaseUInt edge cases.");
type U32 = BaseUInt32;
let mut x = U32::default();
let y = U32::default();
x ^= &y;
debug!("(0 ^ 0) => 0x{:08X}", x.pn[0]);
assert_eq!(x.pn[0], 0);
let mut a = U32::default();
a.pn[0] = 0xABCD_1234;
a ^= 0u64; assert_eq!(a.pn[0], 0xABCD_1234);
let mut b = U32::default();
b.pn[0] = 0xFFFF_FFFF;
b ^= 0x1234_5678_9ABC_DEF0u64;
let expect = 0xFFFF_FFFF ^ 0x9ABC_DEF0;
assert_eq!(b.pn[0], expect);
let mut d = U32::default();
d.pn[0] = 0x1234_0000;
let mut e = U32::default();
e.pn[0] = 0x0000_9999;
d ^= &e;
assert_eq!(d.pn[0], 0x1234_9999);
info!("32-bit XOR edge-case tests passed.");
}
#[traced_test]
fn test_bitxor_64_bits_edge_cases() {
info!("Testing bitwise XOR for 64-bit BaseUInt edge cases.");
type U64B = BaseUInt64;
let mut x = U64B::default();
x ^= &U64B::default();
assert_eq!(x.pn, [0, 0]);
let mut a = U64B::default();
a.pn[0] = 0xAAAA_0000;
a.pn[1] = 0x0000_BBBB;
a ^= 0x1122_3344_5566_7788u64;
let res0 = 0xAAAA_0000 ^ 0x5566_7788;
let res1 = 0x0000_BBBB ^ 0x1122_3344;
assert_eq!(a.pn[0], res0);
assert_eq!(a.pn[1], res1);
let mut b = U64B::default();
b.pn[0] = 0xFFFF_0000;
let mut c = U64B::default();
c.pn[0] = 0x1234_5678;
b ^= &c;
let expected0 = 0xFFFF_0000 ^ 0x1234_5678;
debug!("(0xFFFF0000 ^ 0x12345678) => 0x{:08X}", expected0);
assert_eq!(b.pn[0], expected0);
assert_eq!(b.pn[1], 0);
info!("64-bit XOR edge-case tests passed.");
}
#[traced_test]
fn test_bitxor_256_bits_edge_cases() {
info!("Testing bitwise XOR for 256-bit BaseUInt edge cases.");
type U256 = BaseUInt256;
let mut x = U256::default();
x ^= &U256::default();
assert!(x.pn.iter().all(|&limb| limb == 0));
let mut a = U256::default();
a.pn[0] = 0xAAAA_AAAA;
a.pn[1] = 0x0000_FFFF;
a.pn[7] = 0x1111_2222; let mut b = U256::default();
b.pn[0] = 0x5555_5555;
b.pn[1] = 0xFFFF_0000;
b.pn[3] = 0x1234_5678;
b.pn[7] = 0x8888_9999;
a ^= &b;
assert_eq!(a.pn[0], 0xFFFF_FFFF); assert_eq!(a.pn[1], 0xFFFF_FFFF); assert_eq!(a.pn[3], 0x1234_5678); assert_eq!(a.pn[7], 0x9999_BBBB);
info!("256-bit XOR edge-case tests passed.");
}
#[traced_test]
fn test_bitxor_random_64_and_256() {
info!("Testing bitwise XOR with random data in 64-bit & 256-bit BaseUInt.");
let mut rng = SimpleLCG::new(0x1234_5678_9ABC_DEF0);
for _ in 0..50 {
let a_val = rng.next_u64();
let b_val = rng.next_u64();
let expected64 = a_val ^ b_val;
let mut a_bu = BaseUInt64::default();
a_bu.pn[0] = (a_val & 0xFFFF_FFFF) as u32;
a_bu.pn[1] = ((a_val >> 32) & 0xFFFF_FFFF) as u32;
a_bu ^= b_val;
let got64 = ((a_bu.pn[1] as u64) << 32) | (a_bu.pn[0] as u64);
assert_eq!(got64, expected64, "64-bit random XOR mismatch");
}
for _ in 0..50 {
let a0 = rng.next_u64();
let a1 = rng.next_u64();
let a2 = rng.next_u64();
let a3 = rng.next_u64();
let b0 = rng.next_u64();
let b1 = rng.next_u64();
let b2 = rng.next_u64();
let b3 = rng.next_u64();
let r0 = a0 ^ b0;
let r1 = a1 ^ b1;
let r2 = a2 ^ b2;
let r3 = a3 ^ b3;
let mut a_bu = BaseUInt256::default();
a_bu.pn[0] = (a0 & 0xFFFF_FFFF) as u32;
a_bu.pn[1] = ((a0 >> 32) & 0xFFFF_FFFF) as u32;
a_bu.pn[2] = (a1 & 0xFFFF_FFFF) as u32;
a_bu.pn[3] = ((a1 >> 32) & 0xFFFF_FFFF) as u32;
a_bu.pn[4] = (a2 & 0xFFFF_FFFF) as u32;
a_bu.pn[5] = ((a2 >> 32) & 0xFFFF_FFFF) as u32;
a_bu.pn[6] = (a3 & 0xFFFF_FFFF) as u32;
a_bu.pn[7] = ((a3 >> 32) & 0xFFFF_FFFF) as u32;
let mut b_bu = BaseUInt256::default();
b_bu.pn[0] = (b0 & 0xFFFF_FFFF) as u32;
b_bu.pn[1] = ((b0 >> 32) & 0xFFFF_FFFF) as u32;
b_bu.pn[2] = (b1 & 0xFFFF_FFFF) as u32;
b_bu.pn[3] = ((b1 >> 32) & 0xFFFF_FFFF) as u32;
b_bu.pn[4] = (b2 & 0xFFFF_FFFF) as u32;
b_bu.pn[5] = ((b2 >> 32) & 0xFFFF_FFFF) as u32;
b_bu.pn[6] = (b3 & 0xFFFF_FFFF) as u32;
b_bu.pn[7] = ((b3 >> 32) & 0xFFFF_FFFF) as u32;
a_bu ^= &b_bu;
let rr0 = ((a_bu.pn[1] as u64) << 32) | (a_bu.pn[0] as u64);
let rr1 = ((a_bu.pn[3] as u64) << 32) | (a_bu.pn[2] as u64);
let rr2 = ((a_bu.pn[5] as u64) << 32) | (a_bu.pn[4] as u64);
let rr3 = ((a_bu.pn[7] as u64) << 32) | (a_bu.pn[6] as u64);
assert_eq!(rr0, r0, "256-bit random XOR mismatch, lower 64 bits");
assert_eq!(rr1, r1, "256-bit random XOR mismatch, next 64 bits");
assert_eq!(rr2, r2, "256-bit random XOR mismatch, next 64 bits");
assert_eq!(rr3, r3, "256-bit random XOR mismatch, top 64 bits");
}
info!("Random XOR tests for 64-bit & 256-bit completed successfully.");
}
#[traced_test]
fn test_bitxor_operator_new() {
info!("Testing `self ^ &other => new BaseUInt` with some small examples.");
let mut x = BaseUInt64::default();
x.pn[0] = 0xFFFF_0000;
let mut y = BaseUInt64::default();
y.pn[0] = 0x1234_5678;
let z = x ^ &y;
let expect = 0xFFFF_0000 ^ 0x1234_5678;
assert_eq!(z.pn[0], expect);
assert_eq!(z.pn[1], 0);
{
let mut x32 = BaseUInt32::default();
x32.pn[0] = 0xAAAA_AAAA;
let mut y32 = BaseUInt32::default();
y32.pn[0] = 0x5555_0000;
let z32 = x32 ^ &y32;
let expected32 = 0xAAAA_AAAA ^ 0x5555_0000;
assert_eq!(z32.pn[0], expected32);
}
info!("`BitXor` operator returning new BaseUInt tested OK.");
}
}