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
}
impl AHasher {
#[inline]
pub fn new_with_key(key: u64) -> AHasher {
AHasher { buffer: key }
}
#[inline]
pub(crate) fn new_with_keys(key1: u64, key2: u64) -> AHasher {
AHasher { buffer: key1 ^ (key2.rotate_left(ROT)) }
}
#[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_key(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 {
value = data[0]; } else {
value = 0;
}
self.update(value as u64);
}
}
}
#[inline]
fn finish(&self) -> u64 {
self.buffer
}
}
#[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);
}
}