use crate::convert::*;
use std::hash::{Hasher};
use std::intrinsics::assume;
const MULTIPLE: u64 = 6364136223846793005;
const INCREMENT: u64 = 1442695040888963407;
const ROT: u32 = 23;
#[derive(Debug, Clone)]
pub struct AHasher {
buffer: u64
}
impl AHasher {
#[inline]
pub(crate) fn new_with_key(key: u64, loc: u64) -> AHasher {
AHasher { buffer: key ^ (loc.rotate_left(ROT)) }
}
#[inline(always)]
fn update(&mut self, new_data: u64) {
let existing = self.buffer.wrapping_mul(MULTIPLE).rotate_left(ROT).wrapping_mul(MULTIPLE);
self.buffer = existing ^ new_data;
}
#[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, 87);
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);
if data.len() > 8 {
let mut key: u64 = self.buffer;
while data.len() > 16 {
let (val, rest) = data.read_u64();
key = self.ordered_update(val, key);
data = rest;
}
unsafe{assume(data.len() > 8)} let (val, _) = data.read_u64();
self.ordered_update(val, key);
let val = data.read_last_u64();
self.update(val);
} 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 {
if data.len() >= 1 {
self.update(data[0] as u64);
}
}
}
}
#[inline]
fn finish(&self) -> u64 {
self.buffer.wrapping_mul(MULTIPLE).rotate_left(9).wrapping_mul(MULTIPLE)
}
}
#[cfg(test)]
mod tests {
use crate::convert::Convert;
use crate::fallback_hash::*;
#[test]
fn test_hash() {
let mut hasher = AHasher::new_with_key(0,0);
let value: u64 = 1 << 32;
hasher.update(value);
let result = hasher.buffer;
let mut hasher = AHasher::new_with_key(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);
}
}