11e15f31bSopenharmony_ci// Copyright 2015 The Rust Project Developers. See the COPYRIGHT 21e15f31bSopenharmony_ci// file at the top-level directory of this distribution and at 31e15f31bSopenharmony_ci// http://rust-lang.org/COPYRIGHT. 41e15f31bSopenharmony_ci// 51e15f31bSopenharmony_ci// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or 61e15f31bSopenharmony_ci// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license 71e15f31bSopenharmony_ci// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your 81e15f31bSopenharmony_ci// option. This file may not be copied, modified, or distributed 91e15f31bSopenharmony_ci// except according to those terms. 101e15f31bSopenharmony_ci 111e15f31bSopenharmony_ci//! Fast, non-cryptographic hash used by rustc and Firefox. 121e15f31bSopenharmony_ci//! 131e15f31bSopenharmony_ci//! # Example 141e15f31bSopenharmony_ci//! 151e15f31bSopenharmony_ci//! ```rust 161e15f31bSopenharmony_ci//! # #[cfg(feature = "std")] 171e15f31bSopenharmony_ci//! # fn main() { 181e15f31bSopenharmony_ci//! use rustc_hash::FxHashMap; 191e15f31bSopenharmony_ci//! let mut map: FxHashMap<u32, u32> = FxHashMap::default(); 201e15f31bSopenharmony_ci//! map.insert(22, 44); 211e15f31bSopenharmony_ci//! # } 221e15f31bSopenharmony_ci//! # #[cfg(not(feature = "std"))] 231e15f31bSopenharmony_ci//! # fn main() { } 241e15f31bSopenharmony_ci//! ``` 251e15f31bSopenharmony_ci 261e15f31bSopenharmony_ci#![no_std] 271e15f31bSopenharmony_ci 281e15f31bSopenharmony_ci#[cfg(feature = "std")] 291e15f31bSopenharmony_ciextern crate std; 301e15f31bSopenharmony_ci 311e15f31bSopenharmony_ciuse core::convert::TryInto; 321e15f31bSopenharmony_ciuse core::default::Default; 331e15f31bSopenharmony_ci#[cfg(feature = "std")] 341e15f31bSopenharmony_ciuse core::hash::BuildHasherDefault; 351e15f31bSopenharmony_ciuse core::hash::Hasher; 361e15f31bSopenharmony_ciuse core::mem::size_of; 371e15f31bSopenharmony_ciuse core::ops::BitXor; 381e15f31bSopenharmony_ci#[cfg(feature = "std")] 391e15f31bSopenharmony_ciuse std::collections::{HashMap, HashSet}; 401e15f31bSopenharmony_ci 411e15f31bSopenharmony_ci/// Type alias for a hashmap using the `fx` hash algorithm. 421e15f31bSopenharmony_ci#[cfg(feature = "std")] 431e15f31bSopenharmony_cipub type FxHashMap<K, V> = HashMap<K, V, BuildHasherDefault<FxHasher>>; 441e15f31bSopenharmony_ci 451e15f31bSopenharmony_ci/// Type alias for a hashmap using the `fx` hash algorithm. 461e15f31bSopenharmony_ci#[cfg(feature = "std")] 471e15f31bSopenharmony_cipub type FxHashSet<V> = HashSet<V, BuildHasherDefault<FxHasher>>; 481e15f31bSopenharmony_ci 491e15f31bSopenharmony_ci/// A speedy hash algorithm for use within rustc. The hashmap in liballoc 501e15f31bSopenharmony_ci/// by default uses SipHash which isn't quite as speedy as we want. In the 511e15f31bSopenharmony_ci/// compiler we're not really worried about DOS attempts, so we use a fast 521e15f31bSopenharmony_ci/// non-cryptographic hash. 531e15f31bSopenharmony_ci/// 541e15f31bSopenharmony_ci/// This is the same as the algorithm used by Firefox -- which is a homespun 551e15f31bSopenharmony_ci/// one not based on any widely-known algorithm -- though modified to produce 561e15f31bSopenharmony_ci/// 64-bit hash values instead of 32-bit hash values. It consistently 571e15f31bSopenharmony_ci/// out-performs an FNV-based hash within rustc itself -- the collision rate is 581e15f31bSopenharmony_ci/// similar or slightly worse than FNV, but the speed of the hash function 591e15f31bSopenharmony_ci/// itself is much higher because it works on up to 8 bytes at a time. 601e15f31bSopenharmony_cipub struct FxHasher { 611e15f31bSopenharmony_ci hash: usize, 621e15f31bSopenharmony_ci} 631e15f31bSopenharmony_ci 641e15f31bSopenharmony_ci#[cfg(target_pointer_width = "32")] 651e15f31bSopenharmony_ciconst K: usize = 0x9e3779b9; 661e15f31bSopenharmony_ci#[cfg(target_pointer_width = "64")] 671e15f31bSopenharmony_ciconst K: usize = 0x517cc1b727220a95; 681e15f31bSopenharmony_ci 691e15f31bSopenharmony_ciimpl Default for FxHasher { 701e15f31bSopenharmony_ci #[inline] 711e15f31bSopenharmony_ci fn default() -> FxHasher { 721e15f31bSopenharmony_ci FxHasher { hash: 0 } 731e15f31bSopenharmony_ci } 741e15f31bSopenharmony_ci} 751e15f31bSopenharmony_ci 761e15f31bSopenharmony_ciimpl FxHasher { 771e15f31bSopenharmony_ci #[inline] 781e15f31bSopenharmony_ci fn add_to_hash(&mut self, i: usize) { 791e15f31bSopenharmony_ci self.hash = self.hash.rotate_left(5).bitxor(i).wrapping_mul(K); 801e15f31bSopenharmony_ci } 811e15f31bSopenharmony_ci} 821e15f31bSopenharmony_ci 831e15f31bSopenharmony_ciimpl Hasher for FxHasher { 841e15f31bSopenharmony_ci #[inline] 851e15f31bSopenharmony_ci fn write(&mut self, mut bytes: &[u8]) { 861e15f31bSopenharmony_ci #[cfg(target_pointer_width = "32")] 871e15f31bSopenharmony_ci let read_usize = |bytes: &[u8]| u32::from_ne_bytes(bytes[..4].try_into().unwrap()); 881e15f31bSopenharmony_ci #[cfg(target_pointer_width = "64")] 891e15f31bSopenharmony_ci let read_usize = |bytes: &[u8]| u64::from_ne_bytes(bytes[..8].try_into().unwrap()); 901e15f31bSopenharmony_ci 911e15f31bSopenharmony_ci let mut hash = FxHasher { hash: self.hash }; 921e15f31bSopenharmony_ci assert!(size_of::<usize>() <= 8); 931e15f31bSopenharmony_ci while bytes.len() >= size_of::<usize>() { 941e15f31bSopenharmony_ci hash.add_to_hash(read_usize(bytes) as usize); 951e15f31bSopenharmony_ci bytes = &bytes[size_of::<usize>()..]; 961e15f31bSopenharmony_ci } 971e15f31bSopenharmony_ci if (size_of::<usize>() > 4) && (bytes.len() >= 4) { 981e15f31bSopenharmony_ci hash.add_to_hash(u32::from_ne_bytes(bytes[..4].try_into().unwrap()) as usize); 991e15f31bSopenharmony_ci bytes = &bytes[4..]; 1001e15f31bSopenharmony_ci } 1011e15f31bSopenharmony_ci if (size_of::<usize>() > 2) && bytes.len() >= 2 { 1021e15f31bSopenharmony_ci hash.add_to_hash(u16::from_ne_bytes(bytes[..2].try_into().unwrap()) as usize); 1031e15f31bSopenharmony_ci bytes = &bytes[2..]; 1041e15f31bSopenharmony_ci } 1051e15f31bSopenharmony_ci if (size_of::<usize>() > 1) && bytes.len() >= 1 { 1061e15f31bSopenharmony_ci hash.add_to_hash(bytes[0] as usize); 1071e15f31bSopenharmony_ci } 1081e15f31bSopenharmony_ci self.hash = hash.hash; 1091e15f31bSopenharmony_ci } 1101e15f31bSopenharmony_ci 1111e15f31bSopenharmony_ci #[inline] 1121e15f31bSopenharmony_ci fn write_u8(&mut self, i: u8) { 1131e15f31bSopenharmony_ci self.add_to_hash(i as usize); 1141e15f31bSopenharmony_ci } 1151e15f31bSopenharmony_ci 1161e15f31bSopenharmony_ci #[inline] 1171e15f31bSopenharmony_ci fn write_u16(&mut self, i: u16) { 1181e15f31bSopenharmony_ci self.add_to_hash(i as usize); 1191e15f31bSopenharmony_ci } 1201e15f31bSopenharmony_ci 1211e15f31bSopenharmony_ci #[inline] 1221e15f31bSopenharmony_ci fn write_u32(&mut self, i: u32) { 1231e15f31bSopenharmony_ci self.add_to_hash(i as usize); 1241e15f31bSopenharmony_ci } 1251e15f31bSopenharmony_ci 1261e15f31bSopenharmony_ci #[cfg(target_pointer_width = "32")] 1271e15f31bSopenharmony_ci #[inline] 1281e15f31bSopenharmony_ci fn write_u64(&mut self, i: u64) { 1291e15f31bSopenharmony_ci self.add_to_hash(i as usize); 1301e15f31bSopenharmony_ci self.add_to_hash((i >> 32) as usize); 1311e15f31bSopenharmony_ci } 1321e15f31bSopenharmony_ci 1331e15f31bSopenharmony_ci #[cfg(target_pointer_width = "64")] 1341e15f31bSopenharmony_ci #[inline] 1351e15f31bSopenharmony_ci fn write_u64(&mut self, i: u64) { 1361e15f31bSopenharmony_ci self.add_to_hash(i as usize); 1371e15f31bSopenharmony_ci } 1381e15f31bSopenharmony_ci 1391e15f31bSopenharmony_ci #[inline] 1401e15f31bSopenharmony_ci fn write_usize(&mut self, i: usize) { 1411e15f31bSopenharmony_ci self.add_to_hash(i); 1421e15f31bSopenharmony_ci } 1431e15f31bSopenharmony_ci 1441e15f31bSopenharmony_ci #[inline] 1451e15f31bSopenharmony_ci fn finish(&self) -> u64 { 1461e15f31bSopenharmony_ci self.hash as u64 1471e15f31bSopenharmony_ci } 1481e15f31bSopenharmony_ci} 149