fxhash/
lib.rs

1// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11#![deny(missing_docs)]
12
13// Turns on no_std features if std is not available.
14#![cfg_attr(not(feature = "std"), no_std)]
15
16//! # Fx Hash
17//!
18//! This hashing algorithm was extracted from the Rustc compiler.  This is the same hashing
19//! algorithm used for some internal operations in FireFox.  The strength of this algorithm
20//! is in hashing 8 bytes at a time on 64-bit platforms, where the FNV algorithm works on one
21//! byte at a time.
22//!
23//! ## Disclaimer
24//!
25//! It is **not a cryptographically secure** hash, so it is strongly recommended that you do
26//! not use this hash for cryptographic purproses.  Furthermore, this hashing algorithm was
27//! not designed to prevent any attacks for determining collisions which could be used to
28//! potentially cause quadratic behavior in `HashMap`s.  So it is not recommended to expose
29//! this hash in places where collissions or DDOS attacks may be a concern.
30
31// Include the `hashmap_core` crate if std is not available.
32#[allow(unused_extern_crates)]
33#[cfg(all(feature = "hashmap_core", not(feature = "std")))]
34extern crate hashmap_core;
35
36use std::default::Default;
37use std::hash::{Hasher, Hash, BuildHasherDefault};
38use std::ops::BitXor;
39
40extern crate byteorder;
41#[macro_use]
42extern crate cfg_if;
43use byteorder::{ByteOrder, NativeEndian};
44
45/// A builder for default Fx hashers.
46pub type FxBuildHasher = BuildHasherDefault<FxHasher>;
47
48cfg_if! {
49    if #[cfg(any(feature = "hashmap-core", feature = "std"))] {
50        use std::collections::{HashMap, HashSet};
51
52        /// A `HashMap` using a default Fx hasher.
53        pub type FxHashMap<K, V> = HashMap<K, V, FxBuildHasher>;
54
55        /// A `HashSet` using a default Fx hasher.
56        pub type FxHashSet<V> = HashSet<V, FxBuildHasher>;
57    }
58}
59
60const ROTATE: u32 = 5;
61const SEED64: u64 = 0x517cc1b727220a95;
62const SEED32: u32 = (SEED64 & 0xFFFF_FFFF) as u32;
63
64#[cfg(target_pointer_width = "32")]
65const SEED: usize = SEED32 as usize;
66#[cfg(target_pointer_width = "64")]
67const SEED: usize = SEED64 as usize;
68
69trait HashWord {
70    fn hash_word(&mut self, Self);
71}
72
73macro_rules! impl_hash_word {
74    ($($ty:ty = $key:ident),* $(,)*) => (
75        $(
76            impl HashWord for $ty {
77                #[inline]
78                fn hash_word(&mut self, word: Self) {
79                    *self = self.rotate_left(ROTATE).bitxor(word).wrapping_mul($key);
80                }
81            }
82        )*
83    )
84}
85
86impl_hash_word!(usize = SEED, u32 = SEED32, u64 = SEED64);
87
88#[inline]
89fn write32(mut hash: u32, mut bytes: &[u8]) -> u32 {
90    while bytes.len() >= 4 {
91        let n = NativeEndian::read_u32(bytes);
92        hash.hash_word(n);
93        bytes = bytes.split_at(4).1;
94    }
95
96    for byte in bytes {
97        hash.hash_word(*byte as u32);
98    }
99    hash
100}
101
102#[inline]
103fn write64(mut hash: u64, mut bytes: &[u8]) -> u64 {
104    while bytes.len() >= 8 {
105        let n = NativeEndian::read_u64(bytes);
106        hash.hash_word(n);
107        bytes = bytes.split_at(8).1;
108    }
109
110    if bytes.len() >= 4 {
111        let n = NativeEndian::read_u32(bytes);
112        hash.hash_word(n as u64);
113        bytes = bytes.split_at(4).1;
114    }
115
116    for byte in bytes {
117        hash.hash_word(*byte as u64);
118    }
119    hash
120}
121
122#[inline]
123#[cfg(target_pointer_width = "32")]
124fn write(hash: usize, bytes: &[u8]) -> usize {
125    write32(hash as u32, bytes) as usize
126}
127
128#[inline]
129#[cfg(target_pointer_width = "64")]
130fn write(hash: usize, bytes: &[u8]) -> usize {
131    write64(hash as u64, bytes) as usize
132}
133
134/// This hashing algorithm was extracted from the Rustc compiler.
135/// This is the same hashing algorithm used for some internal operations in FireFox.
136/// The strength of this algorithm is in hashing 8 bytes at a time on 64-bit platforms,
137/// where the FNV algorithm works on one byte at a time.
138///
139/// This hashing algorithm should not be used for cryptographic, or in scenarios where
140/// DOS attacks are a concern.
141#[derive(Debug, Clone)]
142pub struct FxHasher {
143    hash: usize,
144}
145
146impl Default for FxHasher {
147    #[inline]
148    fn default() -> FxHasher {
149        FxHasher { hash: 0 }
150    }
151}
152
153impl Hasher for FxHasher {
154    #[inline]
155    fn write(&mut self, bytes: &[u8]) {
156        self.hash = write(self.hash, bytes);
157    }
158
159    #[inline]
160    fn write_u8(&mut self, i: u8) {
161        self.hash.hash_word(i as usize);
162    }
163
164    #[inline]
165    fn write_u16(&mut self, i: u16) {
166        self.hash.hash_word(i as usize);
167    }
168
169    #[inline]
170    fn write_u32(&mut self, i: u32) {
171        self.hash.hash_word(i as usize);
172    }
173
174    #[inline]
175    #[cfg(target_pointer_width = "32")]
176    fn write_u64(&mut self, i: u64) {
177        self.hash.hash_word(i as usize);
178        self.hash.hash_word((i >> 32) as usize);
179    }
180
181    #[inline]
182    #[cfg(target_pointer_width = "64")]
183    fn write_u64(&mut self, i: u64) {
184        self.hash.hash_word(i as usize);
185    }
186
187    #[inline]
188    fn write_usize(&mut self, i: usize) {
189        self.hash.hash_word(i);
190    }
191
192    #[inline]
193    fn finish(&self) -> u64 {
194        self.hash as u64
195    }
196}
197
198/// This hashing algorithm was extracted from the Rustc compiler.
199/// This is the same hashing algorithm used for some internal operations in FireFox.
200/// The strength of this algorithm is in hashing 8 bytes at a time on any platform,
201/// where the FNV algorithm works on one byte at a time.
202///
203/// This hashing algorithm should not be used for cryptographic, or in scenarios where
204/// DOS attacks are a concern.
205#[derive(Debug, Clone)]
206pub struct FxHasher64 {
207    hash: u64,
208}
209
210impl Default for FxHasher64 {
211    #[inline]
212    fn default() -> FxHasher64 {
213        FxHasher64 { hash: 0 }
214    }
215}
216
217impl Hasher for FxHasher64 {
218    #[inline]
219    fn write(&mut self, bytes: &[u8]) {
220        self.hash = write64(self.hash, bytes);
221    }
222
223    #[inline]
224    fn write_u8(&mut self, i: u8) {
225        self.hash.hash_word(i as u64);
226    }
227
228    #[inline]
229    fn write_u16(&mut self, i: u16) {
230        self.hash.hash_word(i as u64);
231    }
232
233    #[inline]
234    fn write_u32(&mut self, i: u32) {
235        self.hash.hash_word(i as u64);
236    }
237
238    fn write_u64(&mut self, i: u64) {
239        self.hash.hash_word(i);
240    }
241
242    #[inline]
243    fn write_usize(&mut self, i: usize) {
244        self.hash.hash_word(i as u64);
245    }
246
247    #[inline]
248    fn finish(&self) -> u64 {
249        self.hash
250    }
251}
252
253/// This hashing algorithm was extracted from the Rustc compiler.
254/// This is the same hashing algorithm used for some internal operations in FireFox.
255/// The strength of this algorithm is in hashing 4 bytes at a time on any platform,
256/// where the FNV algorithm works on one byte at a time.
257///
258/// This hashing algorithm should not be used for cryptographic, or in scenarios where
259/// DOS attacks are a concern.
260#[derive(Debug, Clone)]
261pub struct FxHasher32 {
262    hash: u32,
263}
264
265impl Default for FxHasher32 {
266    #[inline]
267    fn default() -> FxHasher32 {
268        FxHasher32 { hash: 0 }
269    }
270}
271
272impl Hasher for FxHasher32 {
273    #[inline]
274    fn write(&mut self, bytes: &[u8]) {
275        self.hash = write32(self.hash, bytes);
276    }
277
278    #[inline]
279    fn write_u8(&mut self, i: u8) {
280        self.hash.hash_word(i as u32);
281    }
282
283    #[inline]
284    fn write_u16(&mut self, i: u16) {
285        self.hash.hash_word(i as u32);
286    }
287
288    #[inline]
289    fn write_u32(&mut self, i: u32) {
290        self.hash.hash_word(i);
291    }
292
293    #[inline]
294    fn write_u64(&mut self, i: u64) {
295        self.hash.hash_word(i as u32);
296        self.hash.hash_word((i >> 32) as u32);
297    }
298
299    #[inline]
300    #[cfg(target_pointer_width = "32")]
301    fn write_usize(&mut self, i: usize) {
302        self.write_u32(i as u32);
303    }
304
305    #[inline]
306    #[cfg(target_pointer_width = "64")]
307    fn write_usize(&mut self, i: usize) {
308        self.write_u64(i as u64);
309    }
310
311    #[inline]
312    fn finish(&self) -> u64 {
313        self.hash as u64
314    }
315}
316
317/// A convenience function for when you need a quick 64-bit hash.
318#[inline]
319pub fn hash64<T: Hash + ?Sized>(v: &T) -> u64 {
320    let mut state = FxHasher64::default();
321    v.hash(&mut state);
322    state.finish()
323}
324
325/// A convenience function for when you need a quick 32-bit hash.
326#[inline]
327pub fn hash32<T: Hash + ?Sized>(v: &T) -> u32 {
328    let mut state = FxHasher32::default();
329    v.hash(&mut state);
330    state.finish() as u32
331}
332
333/// A convenience function for when you need a quick usize hash.
334#[inline]
335pub fn hash<T: Hash + ?Sized>(v: &T) -> usize {
336    let mut state = FxHasher::default();
337    v.hash(&mut state);
338    state.finish() as usize
339}
340
341/// This replaces `std` in builds with `core`.
342#[cfg(not(feature = "std"))]
343mod std {
344    pub use core::*;
345
346    #[cfg(feature = "hashmap-core")]
347    pub mod collections {
348        pub use hashmap_core::{HashMap, HashSet};
349        pub use hashmap_core::map as hash_map;
350    }
351}