use crate::convert::{Convert};
use std::hash::{Hasher};
use arrayref::*;
use std::ops::BitXor;
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_keys(key0: u64, key1: u64) -> AHasher {
AHasher { buffer: key0 ^ key1.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)
}
}
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 (block, rest) = data.split_at(8);
let val: u64 = as_array!(block, 8).convert();
key = self.ordered_update(val, key);
data = rest;
}
let val: u64 = (*array_ref!(data, 0, 8)).convert();
self.ordered_update(val, key);
let val: u64 = (*array_ref!(data, data.len()-8, 8)).convert();
self.update(val);
} else {
if data.len() >= 2 {
if data.len() >= 4 {
let block: [u32; 2] = [(*array_ref!(data, 0, 4)).convert(),
(*array_ref!(data, data.len()-4, 4)).convert()];
self.update(block.convert());
} else {
let block: [u16; 2] = [(*array_ref!(data, 0, 2)).convert(),
(*array_ref!(data, data.len()-2, 2)).convert()];
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(ROT).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_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);
}
}