use std::cmp::{Ordering, min};
use std::marker::Sized;
use std::mem;
use std::num::Wrapping;
pub trait Xorable: Ord + Sized {
fn common_prefix(&self, other: &Self) -> usize;
fn cmp_distance(&self, lhs: &Self, rhs: &Self) -> Ordering;
fn bit(&self, i: usize) -> bool;
fn differs_in_bit(&self, other: &Self, i: usize) -> bool;
fn with_flipped_bit(self, i: usize) -> Self;
fn with_bit(self, i: usize, bit: bool) -> Self;
fn binary(&self) -> String;
fn debug_binary(&self) -> String;
fn set_remaining(self, n: usize, val: bool) -> Self;
fn bit_len() -> usize {
mem::size_of::<Self>() * 8
}
fn from_hash<T: AsRef<[u8]>>(hash: T) -> Self;
}
pub fn debug_format(input: String) -> String {
if input.len() <= 20 {
return input;
}
input.chars()
.take(8)
.chain("...".chars())
.chain(input.chars().skip(input.len() - 8))
.collect()
}
macro_rules! impl_xorable_for_array {
($t: ident, $l: expr) => {
impl Xorable for [$t; $l] {
fn common_prefix(&self, other: &[$t; $l]) -> usize {
for byte_index in 0..$l {
if self[byte_index] != other[byte_index] {
return (byte_index * mem::size_of::<$t>() * 8) +
(self[byte_index] ^ other[byte_index]).leading_zeros() as usize;
}
}
$l * mem::size_of::<$t>() * 8
}
fn cmp_distance(&self, lhs: &[$t; $l], rhs: &[$t; $l]) -> Ordering {
for i in 0..$l {
if lhs[i] != rhs[i] {
return Ord::cmp(&(lhs[i] ^ self[i]), &(rhs[i] ^ self[i]));
}
}
Ordering::Equal
}
fn bit(&self, i: usize) -> bool {
let bits = mem::size_of::<$t>() * 8;
let index = i / bits;
let pow_i = 1 << (bits - 1 - (i % bits));
self[index] & pow_i != 0
}
fn differs_in_bit(&self, name: &[$t; $l], i: usize) -> bool {
let bits = mem::size_of::<$t>() * 8;
let index = i / bits;
let pow_i = 1 << (bits - 1 - (i % bits));
(self[index] ^ name[index]) & pow_i != 0
}
fn with_flipped_bit(mut self, i: usize) -> Self {
let bits = mem::size_of::<$t>() * 8;
if i >= Self::bit_len() {
return self;
}
self[i / bits] ^= 1 << (bits - 1 - i % bits);
self
}
fn with_bit(mut self, i: usize, bit: bool) -> Self {
let bits = mem::size_of::<$t>() * 8;
if i >= Self::bit_len() {
return self;
}
let pow_i = 1 << (bits - 1 - i % bits); if bit {
self[i / bits] |= pow_i;
} else {
self[i / bits] &= !pow_i;
}
self
}
fn binary(&self) -> String {
let bit_len = Self::bit_len();
let mut s = String::with_capacity(bit_len);
for value in self.iter() {
s.push_str(&value.binary());
}
s
}
fn debug_binary(&self) -> String {
debug_format(self.binary())
}
fn set_remaining(mut self, n: usize, val: bool) -> Self {
let bits = mem::size_of::<$t>() * 8;
for (i, x) in self.iter_mut().enumerate() {
if n <= i * bits {
*x = if val { !0 } else { 0 };
} else if n < (i + 1) * bits {
let mask = !0 >> (n - i * bits);
if val {
*x |= mask
} else {
*x &= !mask
}
}
}
self
}
fn from_hash<T: AsRef<[u8]>>(hash: T) -> Self {
let hash = hash.as_ref();
let size = mem::size_of::<$t>();
let needed_bytes = min(hash.len(), size * $l);
let mut result: [$t; $l] = [0; $l];
let full_elems = needed_bytes / size;
for (i, elem) in result.iter_mut().enumerate().take(full_elems) {
for j in 0..size {
let mut x = Wrapping(*elem);
x <<= 4;
x <<= 4;
*elem = x.0;
*elem |= hash[i*size + j];
}
}
for j in 0..(needed_bytes % size) {
let mut x = Wrapping(result[full_elems]);
x <<= 4;
x <<= 4;
result[full_elems] = x.0;
result[full_elems] |= hash[full_elems*size + j];
}
result
}
}
}
}
impl_xorable_for_array!(u8, 32);
impl_xorable_for_array!(u8, 16);
impl_xorable_for_array!(u8, 8);
impl_xorable_for_array!(u8, 4);
macro_rules! impl_xorable {
($t:ident) => {
impl Xorable for $t {
fn common_prefix(&self, other: &Self) -> usize {
(self ^ other).leading_zeros() as usize
}
fn cmp_distance(&self, lhs: &Self, rhs: &Self) -> Ordering {
Ord::cmp(&(lhs ^ self), &(rhs ^ self))
}
fn bit(&self, i: usize) -> bool {
let pow_i = 1 << (mem::size_of::<Self>() * 8 - 1 - i); self & pow_i != 0
}
fn differs_in_bit(&self, name: &Self, i: usize) -> bool {
let pow_i = 1 << (mem::size_of::<Self>() * 8 - 1 - i); (self ^ name) & pow_i != 0
}
fn with_flipped_bit(mut self, i: usize) -> Self {
if i >= mem::size_of::<Self>() * 8 {
return self;
}
let pow_i = 1 << (mem::size_of::<Self>() * 8 - 1 - i); self ^= pow_i;
self
}
fn with_bit(mut self, i: usize, bit: bool) -> Self {
if i >= mem::size_of::<Self>() * 8 {
return self;
}
let pow_i = 1 << (mem::size_of::<Self>() * 8 - 1 - i); if bit {
self |= pow_i;
} else {
self &= !pow_i;
}
self
}
fn binary(&self) -> String {
format!("{1:00$b}", mem::size_of::<Self>() * 8, self)
}
fn debug_binary(&self) -> String {
debug_format(self.binary())
}
fn set_remaining(self, n: usize, val: bool) -> Self {
let bits = mem::size_of::<Self>() * 8;
if n >= bits {
self
} else {
let mask = !0 >> n;
if val {
self | mask
} else {
self & !mask
}
}
}
fn from_hash<T: AsRef<[u8]>>(hash: T) -> Self {
let hash = hash.as_ref();
let size = mem::size_of::<$t>();
let needed_bytes = min(hash.len(), size);
let mut result: $t = 0;
for elem in hash.into_iter().take(needed_bytes) {
let mut x = Wrapping(result);
x <<= 4;
x <<= 4;
result = x.0;
result |= From::from(*elem);
}
result
}
}
}
}
impl_xorable!(usize);
impl_xorable!(u64);
impl_xorable!(u32);
impl_xorable!(u16);
impl_xorable!(u8);
#[cfg(test)]
mod tests {
use super::*;
use std::cmp::Ordering;
#[test]
fn common_prefix() {
assert_eq!(0, 0u8.common_prefix(&128u8));
assert_eq!(3, 10u8.common_prefix(&16u8));
assert_eq!(0, 0u16.common_prefix(&(1 << 15)));
assert_eq!(11, 10u16.common_prefix(&16u16));
assert_eq!(64, 100u64.common_prefix(&100));
}
#[test]
fn common_prefix_array() {
assert_eq!(0, [0, 0, 0, 0].common_prefix(&[128u8, 0, 0, 0]));
assert_eq!(11, [0, 10u8, 0, 0].common_prefix(&[0, 16u8, 0, 0]));
assert_eq!(31, [1u8, 2, 3, 4].common_prefix(&[1, 2, 3, 5]));
assert_eq!(32, [1u8, 2, 3, 4].common_prefix(&[1, 2, 3, 4]));
}
#[test]
fn cmp_distance() {
assert_eq!(Ordering::Equal, 42u8.cmp_distance(&13, &13));
assert_eq!(Ordering::Less, 42u8.cmp_distance(&44, &45));
assert_eq!(Ordering::Greater, 42u8.cmp_distance(&45, &44));
}
#[test]
fn cmp_distance_array() {
assert_eq!(Ordering::Equal,
[1u8, 2, 3, 4].cmp_distance(&[2u8, 3, 4, 5], &[2u8, 3, 4, 5]));
assert_eq!(Ordering::Less,
[1u8, 2, 3, 4].cmp_distance(&[2u8, 2, 4, 5], &[2u8, 3, 6, 5]));
assert_eq!(Ordering::Greater,
[1u8, 2, 3, 4].cmp_distance(&[2u8, 3, 6, 5], &[2u8, 2, 4, 5]));
assert_eq!(Ordering::Less,
[1u8, 2, 3, 4].cmp_distance(&[1, 2, 3, 8], &[1, 2, 8, 4]));
assert_eq!(Ordering::Greater,
[1u8, 2, 3, 4].cmp_distance(&[1, 2, 8, 4], &[1, 2, 3, 8]));
assert_eq!(Ordering::Less,
[1u8, 2, 3, 4].cmp_distance(&[1, 2, 7, 4], &[1, 2, 6, 4]));
assert_eq!(Ordering::Greater,
[1u8, 2, 3, 4].cmp_distance(&[1, 2, 6, 4], &[1, 2, 7, 4]));
}
#[test]
fn bit() {
assert_eq!(false, 0b00101000u8.bit(0));
assert_eq!(true, 0b00101000u8.bit(2));
assert_eq!(false, 0b00101000u8.bit(3));
}
#[test]
fn bit_array() {
assert_eq!(true, [2u8, 128, 1, 0].bit(6));
assert_eq!(true, [2u8, 128, 1, 0].bit(8));
assert_eq!(true, [2u8, 128, 1, 0].bit(23));
assert_eq!(false, [2u8, 128, 1, 0].bit(5));
assert_eq!(false, [2u8, 128, 1, 0].bit(7));
assert_eq!(false, [2u8, 128, 1, 0].bit(9));
assert_eq!(false, [2u8, 128, 1, 0].bit(22));
assert_eq!(false, [2u8, 128, 1, 0].bit(24));
}
#[test]
fn differs_in_bit() {
assert!(0b00101010u8.differs_in_bit(&0b00100010u8, 4));
assert!(0b00101010u8.differs_in_bit(&0b00000010u8, 4));
assert!(!0b00101010u8.differs_in_bit(&0b00001010u8, 4));
}
#[test]
fn differs_in_bit_array() {
assert!([0u8, 0, 0, 0].differs_in_bit(&[0, 1, 0, 10], 15));
assert!([0u8, 7, 0, 0].differs_in_bit(&[0, 0, 0, 0], 14));
assert!(![0u8, 7, 0, 0].differs_in_bit(&[0, 0, 0, 0], 26));
}
#[test]
fn set_remaining() {
assert_eq!(0b10011011u8.set_remaining(5, false), 0b10011000);
assert_eq!(0b11111111u8.set_remaining(2, false), 0b11000000);
assert_eq!(0b00000000u8.set_remaining(4, true), 0b00001111);
}
#[test]
fn set_remaining_array() {
assert_eq!([13u8, 112, 9, 1].set_remaining(0, false), [0u8, 0, 0, 0]);
assert_eq!([13u8, 112, 9, 1].set_remaining(100, false),
[13u8, 112, 9, 1]);
assert_eq!([13u8, 112, 9, 1].set_remaining(10, false), [13u8, 64, 0, 0]);
assert_eq!([13u8, 112, 9, 1].set_remaining(10, true),
[13u8, 127, 255, 255]);
}
#[test]
fn bit_len() {
type Array32 = [u8; 32];
type Array16 = [u8; 16];
type Array8 = [u8; 8];
type Array4 = [u8; 4];
assert_eq!(u64::bit_len(), 64);
assert_eq!(u32::bit_len(), 32);
assert_eq!(u16::bit_len(), 16);
assert_eq!(u8::bit_len(), 8);
assert_eq!(Array32::bit_len(), 256);
assert_eq!(Array16::bit_len(), 128);
assert_eq!(Array8::bit_len(), 64);
assert_eq!(Array4::bit_len(), 32);
}
#[test]
fn from_hash() {
assert_eq!(u8::from_hash([5u8]), 5);
assert_eq!(u8::from_hash([5u8, 6]), 5);
assert_eq!(u16::from_hash([8u8, 6]), 2054);
assert_eq!(u16::from_hash([8u8, 6, 7]), 2054);
assert_eq!(u16::from_hash([8u8]), 8);
}
}