1use core::{
4 hash::{Hash, Hasher},
5 ops::BitXor as _,
6};
7
8use crate::primitive::{FixedIsize, FixedUsize};
9
10#[derive(Default)]
12pub struct FxHasher64 {
13 hash: u64,
14}
15
16#[inline]
17fn hash_word(hash: u64, word: u64) -> u64 {
18 const ROTATE: u32 = 5;
19 const SEED: u64 = 0x51_7c_c1_b7_27_22_0a_95;
20
21 hash.rotate_left(ROTATE).bitxor(word).wrapping_mul(SEED)
22}
23
24#[inline]
25fn hash_bytes(mut hash: u64, bytes: &[u8]) -> u64 {
26 let ptr = bytes.as_ptr();
27 let len = bytes.len();
28
29 for i in 0..len / 8 {
30 let bytes = unsafe { ptr.cast::<[u8; 8]>().add(i).read_unaligned() };
31 hash = hash_word(hash, u64::from_le_bytes(bytes));
32 }
33
34 if bytes.len() & 4 != 0 {
35 let bytes = unsafe {
36 ptr.add(bytes.len() & !7).cast::<[u8; 4]>().read_unaligned()
37 };
38 hash = hash_word(hash, u32::from_le_bytes(bytes).into());
39 }
40
41 if bytes.len() & 2 != 0 {
42 let bytes = unsafe {
43 ptr.add(bytes.len() & !3).cast::<[u8; 2]>().read_unaligned()
44 };
45 hash = hash_word(hash, u16::from_le_bytes(bytes).into());
46 }
47
48 if bytes.len() & 1 != 0 {
49 let byte = unsafe { ptr.add(len - 1).read() };
50 hash = hash_word(hash, byte.into());
51 }
52
53 hash
54}
55
56impl Hasher for FxHasher64 {
57 #[inline]
58 fn write(&mut self, bytes: &[u8]) {
59 self.hash = hash_bytes(self.hash, bytes);
60 }
61
62 #[inline]
63 fn finish(&self) -> u64 {
64 self.hash
65 }
66
67 #[inline]
68 fn write_u8(&mut self, i: u8) {
69 self.hash = hash_word(self.hash, i as u64);
70 }
71
72 #[inline]
73 fn write_u16(&mut self, i: u16) {
74 self.hash = hash_word(self.hash, i as u64);
75 }
76
77 #[inline]
78 fn write_u32(&mut self, i: u32) {
79 self.hash = hash_word(self.hash, i as u64);
80 }
81
82 #[inline]
83 fn write_u64(&mut self, i: u64) {
84 self.hash = hash_word(self.hash, i);
85 }
86
87 #[inline]
88 fn write_u128(&mut self, i: u128) {
89 let bytes = i.to_ne_bytes();
90 let ptr = bytes.as_ptr().cast::<[u8; 8]>();
91 #[cfg(target_endian = "little")]
92 let (first, second) = (unsafe { ptr.read_unaligned() }, unsafe {
93 ptr.add(1).read_unaligned()
94 });
95 #[cfg(target_endian = "big")]
96 let (first, second) =
97 (unsafe { ptr.add(1).read_unaligned() }, unsafe {
98 ptr.read_unaligned()
99 });
100 self.hash = hash_word(
101 hash_word(self.hash, u64::from_ne_bytes(first)),
102 u64::from_ne_bytes(second),
103 );
104 }
105
106 #[inline]
107 fn write_usize(&mut self, i: usize) {
108 self.hash = hash_word(self.hash, i as FixedUsize as u64);
109 }
110
111 #[inline]
112 fn write_isize(&mut self, i: isize) {
113 self.write_i64(i as FixedIsize as i64)
114 }
115}
116
117pub fn hash_value<Q, H: Hasher + Default>(value: &Q) -> u64
119where
120 Q: Hash + ?Sized,
121{
122 let mut state = H::default();
123 value.hash(&mut state);
124 state.finish()
125}