use crate::convert::*;
use core::hash::Hasher;
const MULTIPLE: u64 = crate::MULTIPLE;
const INCREMENT: u64 = 1442695040888963407;
const ROT: u32 = 23;
#[derive(Debug, Clone)]
pub struct AHasher {
buffer: u64,
pad: u64,
}
impl AHasher {
#[inline]
pub fn new_with_keys(key1: u64, key2: u64) -> AHasher {
AHasher { buffer: key1, pad: key2 }
}
#[cfg(test)]
pub(crate) fn test_with_keys(key1: u64, key2: u64) -> AHasher {
use crate::scramble_keys;
let (k1, k2) = scramble_keys(key1, key2);
AHasher {
buffer: k1,
pad: k2
}
}
#[inline(always)]
fn update(&mut self, new_data: u64) {
let result: [u64; 2] = ((new_data ^ self.buffer) as u128)
.wrapping_mul(MULTIPLE as u128)
.convert();
self.buffer = result[0].wrapping_add(result[1]);
}
#[inline(always)]
fn ordered_update(&mut self, new_data: u64, key: u64) -> u64 {
self.buffer ^= (new_data ^ key)
.wrapping_mul(MULTIPLE)
.rotate_left(ROT)
.wrapping_mul(MULTIPLE);
key.wrapping_add(INCREMENT)
}
}
#[inline(never)]
#[no_mangle]
fn hash_test(input: &[u8]) -> u64 {
let mut a = AHasher::new_with_keys(12345, 67);
a.write(input);
a.finish()
}
impl Hasher for AHasher {
#[inline]
fn write_u8(&mut self, i: u8) {
self.update(i as u64);
}
#[inline]
fn write_u16(&mut self, i: u16) {
self.update(i as u64);
}
#[inline]
fn write_u32(&mut self, i: u32) {
self.update(i as u64);
}
#[inline]
fn write_u64(&mut self, i: u64) {
self.update(i as u64);
}
#[inline]
fn write_u128(&mut self, i: u128) {
let data: [u64; 2] = i.convert();
self.update(data[0]);
self.update(data[1]);
}
#[inline]
fn write_usize(&mut self, i: usize) {
self.write_u64(i as u64);
}
#[inline]
fn write(&mut self, input: &[u8]) {
let mut data = input;
let length = data.len() as u64;
self.buffer = self.buffer.wrapping_add(length.wrapping_mul(MULTIPLE));
if data.len() > 8 {
if data.len() > 16 {
let tail = data.read_last_u64();
let mut key: u64 = self.buffer;
while data.len() > 8 {
let (val, rest) = data.read_u64();
key = self.ordered_update(val, key);
data = rest;
}
self.update(tail);
} else {
self.update(data.read_u64().0);
self.update(data.read_last_u64());
}
} else {
if data.len() >= 2 {
if data.len() >= 4 {
let block: [u32; 2] = [data.read_u32().0, data.read_last_u32()];
self.update(block.convert());
} else {
let block: [u16; 2] = [data.read_u16().0, data.read_last_u16()];
let val: u32 = block.convert();
self.update(val as u64);
}
} else {
let value = if data.len() > 0 {
data[0] } else {
0
};
self.update(value as u64);
}
}
}
#[inline]
fn finish(&self) -> u64 {
(self.buffer ^ self.pad)
}
}
#[cfg(test)]
mod tests {
use crate::convert::Convert;
use crate::fallback_hash::*;
#[test]
fn test_hash() {
let mut hasher = AHasher::new_with_keys(0, 0);
let value: u64 = 1 << 32;
hasher.update(value);
let result = hasher.buffer;
let mut hasher = AHasher::new_with_keys(0, 0);
let value2: u64 = 1;
hasher.update(value2);
let result2 = hasher.buffer;
let result: [u8; 8] = result.convert();
let result2: [u8; 8] = result2.convert();
assert_ne!(hex::encode(result), hex::encode(result2));
}
#[test]
fn test_conversion() {
let input: &[u8] = "dddddddd".as_bytes();
let bytes: u64 = as_array!(input, 8).convert();
assert_eq!(bytes, 0x6464646464646464);
}
}