From 5435dc054b3d9db8b42ef32845bfda95802cddf7 Mon Sep 17 00:00:00 2001 From: Liam Gray Date: Mon, 4 Aug 2025 13:47:43 +0100 Subject: [PATCH 1/2] Change the default hasher to rapidhash --- CHANGELOG.md | 2 ++ Cargo.toml | 6 +++--- README.md | 6 +++--- benches/bench.rs | 54 ++++++++++++++++++++++++------------------------ src/lib.rs | 2 +- src/map.rs | 4 ++-- 6 files changed, 38 insertions(+), 36 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98050ce71..60317a4c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +- Changed the default hasher to rapidhash. (#563) + ## [0.15.4](https://github.com/rust-lang/hashbrown/compare/v0.15.3...v0.15.4) - 2025-06-05 ### Changed diff --git a/Cargo.toml b/Cargo.toml index 5c165cf29..df2fd76ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ rust-version = "1.65.0" [dependencies] # For the default hasher -foldhash = { version = "0.1.2", default-features = false, optional = true } +rapidhash = { version = "3.0.0", default-features = false, optional = true } # For external trait impls rayon = { version = "1.2", optional = true } @@ -62,10 +62,10 @@ rustc-dep-of-std = [ # Enables the deprecated RawEntry API. raw-entry = [] -# Provides a default hasher. Currently this is foldhash but this is subject to +# Provides a default hasher. Currently this is rapidhash but this is subject to # change in the future. Note that the default hasher does *not* provide HashDoS # resistance, unlike the one in the standard library. -default-hasher = ["dep:foldhash"] +default-hasher = ["dep:rapidhash"] # Enables usage of `#[inline]` on far more functions than by default in this # crate. This may lead to a performance increase but often comes at a compile diff --git a/README.md b/README.md index 83a538115..125a8b9c6 100644 --- a/README.md +++ b/README.md @@ -26,8 +26,8 @@ in environments without `std`, such as embedded systems and kernels. ## Features - Drop-in replacement for the standard library `HashMap` and `HashSet` types. -- Uses [foldhash](https://github.com/orlp/foldhash) as the default hasher, which is much faster than SipHash. - However, foldhash does *not provide the same level of HashDoS resistance* as SipHash, so if that is important to you, you might want to consider using a different hasher. +- Uses [rapidhash](https://github.com/hoxxep/rapidhash) as the default hasher, which is much faster than SipHash. + However, rapidhash does *not provide the same level of HashDoS resistance* as SipHash, so if that is important to you, you might want to consider using a different hasher. - Around 2x faster than the previous standard library `HashMap`. - Lower memory usage: only 1 byte of overhead per entry instead of 8. - Compatible with `#[no_std]` (but requires a global allocator with the `alloc` crate). @@ -61,7 +61,7 @@ This crate has the following Cargo features: - `raw-entry`: Enables access to the deprecated `RawEntry` API. - `inline-more`: Adds inline hints to most functions, improving run-time performance at the cost of compilation time. (enabled by default) -- `default-hasher`: Compiles with foldhash as default hasher. (enabled by default) +- `default-hasher`: Compiles with rapidhash as default hasher. (enabled by default) - `allocator-api2`: Enables support for allocators that support `allocator-api2`. (enabled by default) ## License diff --git a/benches/bench.rs b/benches/bench.rs index 111c5d54f..9c8d9086e 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -1,5 +1,5 @@ // This benchmark suite contains some benchmarks along a set of dimensions: -// Hasher: std default (SipHash) and crate default (foldhash). +// Hasher: std default (SipHash) and crate default (rapidhash). // Int key distribution: low bit heavy, top bit heavy, and random. // Task: basic functionality: insert, insert_erase, lookup, lookup_fail, iter #![feature(test)] @@ -18,7 +18,7 @@ use std::{ const SIZE: usize = 1000; // The default hashmap when using this crate directly. -type FoldHashMap = HashMap; +type RapidHashMap = HashMap; // This uses the hashmap from this crate with the default hasher of the stdlib. type StdHashMap = HashMap; @@ -56,14 +56,14 @@ impl Drop for DropType { } macro_rules! bench_suite { - ($bench_macro:ident, $bench_foldhash_serial:ident, $bench_std_serial:ident, - $bench_foldhash_highbits:ident, $bench_std_highbits:ident, - $bench_foldhash_random:ident, $bench_std_random:ident) => { - $bench_macro!($bench_foldhash_serial, FoldHashMap, 0..); + ($bench_macro:ident, $bench_rapidhash_serial:ident, $bench_std_serial:ident, + $bench_rapidhash_highbits:ident, $bench_std_highbits:ident, + $bench_rapidhash_random:ident, $bench_std_random:ident) => { + $bench_macro!($bench_rapidhash_serial, RapidHashMap, 0..); $bench_macro!($bench_std_serial, StdHashMap, 0..); $bench_macro!( - $bench_foldhash_highbits, - FoldHashMap, + $bench_rapidhash_highbits, + RapidHashMap, (0..).map(usize::swap_bytes) ); $bench_macro!( @@ -71,7 +71,7 @@ macro_rules! bench_suite { StdHashMap, (0..).map(usize::swap_bytes) ); - $bench_macro!($bench_foldhash_random, FoldHashMap, RandomKeys::new()); + $bench_macro!($bench_rapidhash_random, RapidHashMap, RandomKeys::new()); $bench_macro!($bench_std_random, StdHashMap, RandomKeys::new()); }; } @@ -95,11 +95,11 @@ macro_rules! bench_insert { bench_suite!( bench_insert, - insert_foldhash_serial, + insert_rapidhash_serial, insert_std_serial, - insert_foldhash_highbits, + insert_rapidhash_highbits, insert_std_highbits, - insert_foldhash_random, + insert_rapidhash_random, insert_std_random ); @@ -120,11 +120,11 @@ macro_rules! bench_grow_insert { bench_suite!( bench_grow_insert, - grow_insert_foldhash_serial, + grow_insert_rapidhash_serial, grow_insert_std_serial, - grow_insert_foldhash_highbits, + grow_insert_rapidhash_highbits, grow_insert_std_highbits, - grow_insert_foldhash_random, + grow_insert_rapidhash_random, grow_insert_std_random ); @@ -156,11 +156,11 @@ macro_rules! bench_insert_erase { bench_suite!( bench_insert_erase, - insert_erase_foldhash_serial, + insert_erase_rapidhash_serial, insert_erase_std_serial, - insert_erase_foldhash_highbits, + insert_erase_rapidhash_highbits, insert_erase_std_highbits, - insert_erase_foldhash_random, + insert_erase_rapidhash_random, insert_erase_std_random ); @@ -185,11 +185,11 @@ macro_rules! bench_lookup { bench_suite!( bench_lookup, - lookup_foldhash_serial, + lookup_rapidhash_serial, lookup_std_serial, - lookup_foldhash_highbits, + lookup_rapidhash_highbits, lookup_std_highbits, - lookup_foldhash_random, + lookup_rapidhash_random, lookup_std_random ); @@ -214,11 +214,11 @@ macro_rules! bench_lookup_fail { bench_suite!( bench_lookup_fail, - lookup_fail_foldhash_serial, + lookup_fail_rapidhash_serial, lookup_fail_std_serial, - lookup_fail_foldhash_highbits, + lookup_fail_rapidhash_highbits, lookup_fail_std_highbits, - lookup_fail_foldhash_random, + lookup_fail_rapidhash_random, lookup_fail_std_random ); @@ -242,11 +242,11 @@ macro_rules! bench_iter { bench_suite!( bench_iter, - iter_foldhash_serial, + iter_rapidhash_serial, iter_std_serial, - iter_foldhash_highbits, + iter_rapidhash_highbits, iter_std_highbits, - iter_foldhash_random, + iter_rapidhash_random, iter_std_random ); diff --git a/src/lib.rs b/src/lib.rs index e79da830f..a257032a5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -49,7 +49,7 @@ /// Default hasher for [`HashMap`] and [`HashSet`]. #[cfg(feature = "default-hasher")] -pub type DefaultHashBuilder = foldhash::fast::RandomState; +pub type DefaultHashBuilder = rapidhash::fast::RandomState; /// Dummy default hasher for [`HashMap`] and [`HashSet`]. #[cfg(not(feature = "default-hasher"))] diff --git a/src/map.rs b/src/map.rs index 91013945b..154fc6848 100644 --- a/src/map.rs +++ b/src/map.rs @@ -15,7 +15,7 @@ pub use crate::raw_entry::*; /// A hash map implemented with quadratic probing and SIMD lookup. /// -/// The default hashing algorithm is currently [`foldhash`], though this is +/// The default hashing algorithm is currently [`rapidhash`], though this is /// subject to change at any point in the future. This hash function is very /// fast for all types of keys, but this algorithm will typically *not* protect /// against attacks such as HashDoS. @@ -142,7 +142,7 @@ pub use crate::raw_entry::*; /// [`with_hasher`]: #method.with_hasher /// [`with_capacity_and_hasher`]: #method.with_capacity_and_hasher /// [`fnv`]: https://crates.io/crates/fnv -/// [`foldhash`]: https://crates.io/crates/foldhash +/// [`rapidhash`]: https://crates.io/crates/rapidhash /// /// ``` /// use hashbrown::HashMap; From f7ce2786e9cad48ecccb2a900e3fe563f7cc6acf Mon Sep 17 00:00:00 2001 From: Liam Gray Date: Tue, 26 Aug 2025 12:01:36 +0100 Subject: [PATCH 2/2] Bump rapidhash to v4.0.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index df2fd76ee..e664382b0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ rust-version = "1.65.0" [dependencies] # For the default hasher -rapidhash = { version = "3.0.0", default-features = false, optional = true } +rapidhash = { version = "4.0.0", default-features = false, optional = true } # For external trait impls rayon = { version = "1.2", optional = true }