diff --git a/CHANGELOG.md b/CHANGELOG.md index fd38a9659..e06de523d 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.5](https://github.com/rust-lang/hashbrown/compare/v0.15.4...v0.15.5) - 2025-08-07 ### Added diff --git a/Cargo.toml b/Cargo.toml index 4d870fa41..77735658e 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 = "4.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 ce3aee5ce..6df4780da 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)] @@ -19,7 +19,7 @@ const SIZE: usize = 1000; const OP_COUNT: usize = 500; // 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; @@ -57,14 +57,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!( @@ -72,7 +72,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()); }; } @@ -82,14 +82,14 @@ macro_rules! bench_suite_2 { $name0:ident, $size0:literal, $name1:ident, $size1:literal, $name2:ident, $size2:literal, $name3:ident, $size3:literal, $name4:ident, $size4:literal, $name5:ident, $size5:literal, $name6:ident, $size6:literal, $name7:ident, $size7:literal) => { - $bench_macro!($name0, $size0, FoldHashMap, RandomKeys::new()); - $bench_macro!($name1, $size1, FoldHashMap, RandomKeys::new()); - $bench_macro!($name2, $size2, FoldHashMap, RandomKeys::new()); - $bench_macro!($name3, $size3, FoldHashMap, RandomKeys::new()); - $bench_macro!($name4, $size4, FoldHashMap, RandomKeys::new()); - $bench_macro!($name5, $size5, FoldHashMap, RandomKeys::new()); - $bench_macro!($name6, $size6, FoldHashMap, RandomKeys::new()); - $bench_macro!($name7, $size7, FoldHashMap, RandomKeys::new()); + $bench_macro!($name0, $size0, RapidHashMap, RandomKeys::new()); + $bench_macro!($name1, $size1, RapidHashMap, RandomKeys::new()); + $bench_macro!($name2, $size2, RapidHashMap, RandomKeys::new()); + $bench_macro!($name3, $size3, RapidHashMap, RandomKeys::new()); + $bench_macro!($name4, $size4, RapidHashMap, RandomKeys::new()); + $bench_macro!($name5, $size5, RapidHashMap, RandomKeys::new()); + $bench_macro!($name6, $size6, RapidHashMap, RandomKeys::new()); + $bench_macro!($name7, $size7, RapidHashMap, RandomKeys::new()); }; } @@ -112,11 +112,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 ); @@ -137,11 +137,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 ); @@ -173,11 +173,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 ); @@ -202,11 +202,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 ); @@ -231,11 +231,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 ); @@ -336,11 +336,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 392a7463c..20a8ae2dc 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;