Skip to content

Commit 4868e7a

Browse files
authored
perf(toml): Allow opting in to faster hasher (#956)
I chose `foldhash` because it is the default of `[email protected]` (replacing ahash), see rust-lang/hashbrown#563. Currently, `ahash` is the only hasher I noticed inside of Cargo and that is coming in from `[email protected]`. In the future, we could consider allowing the use of a `FixedState` so we could offer `IndexMap` on `alloc`. ``` $ cargo bench --bench 0-cargo -Fpreserve_order -- 0_cargo::toml::document::2-features Compiling toml v0.5.11 Compiling toml v0.8.23 (/home/epage/src/personal/toml/crates/toml) Compiling toml_benchmarks v0.0.0 (/home/epage/src/personal/toml/crates/benchmarks) Finished `bench` profile [optimized] target(s) in 19.13s Running benches/0-cargo.rs (/home/epage/src/personal/toml/target/release/deps/0_cargo-09d7e00849b1b878) Timer precision: 11 ns 0_cargo fastest │ slowest │ median │ mean │ samples │ iters ╰─ toml │ │ │ │ │ ╰─ document │ │ │ │ │ ╰─ 2-features 468.8 µs │ 1.016 ms │ 513.5 µs │ 543.5 µs │ 100 │ 100 $ cargo bench --bench 0-cargo -Ffast_hash -- 0_cargo::toml::document::2-features Finished `bench` profile [optimized] target(s) in 0.02s Running benches/0-cargo.rs (/home/epage/src/personal/toml/target/release/deps/0_cargo-ea11bd9a52599c35) Timer precision: 18 ns 0_cargo fastest │ slowest │ median │ mean │ samples │ iters ╰─ toml │ │ │ │ │ ╰─ document │ │ │ │ │ ╰─ 2-features 431.4 µs │ 870.3 µs │ 446.2 µs │ 459.9 µs │ 100 │ 100 ```
2 parents c654479 + 367cdc4 commit 4868e7a

File tree

4 files changed

+25
-15
lines changed

4 files changed

+25
-15
lines changed

Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/benchmarks/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ default = []
1313
simd = ["toml_parse/simd"]
1414
unsafe = ["toml_parse/unsafe", "toml_edit/unsafe"]
1515
preserve_order = ["toml_old/preserve_order", "toml/preserve_order"]
16+
fast_hash = ["toml/fast_hash"]
1617

1718
[dependencies]
1819
serde = { version = "1.0.197", features = ["derive"] }

crates/toml/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ std = ["indexmap?/std"]
3333
parse = ["dep:toml_parse", "dep:winnow"]
3434
display = ["std", "dep:toml_edit", "toml_edit?/display"]
3535
unsafe = ["toml_parse?/unsafe"]
36+
fast_hash = ["preserve_order", "dep:foldhash"]
3637
debug = ["std", "toml_parse?/debug", "dep:anstream", "dep:anstyle"]
3738

3839
# Provide a method disable_recursion_limit to parse arbitrarily deep structures
@@ -57,6 +58,7 @@ anstyle = { version = "1.0.8", optional = true }
5758
toml_edit = { version = "0.22.27", path = "../toml_edit", default-features = false, features = ["serde"], optional = true }
5859
toml_datetime = { version = "0.6.11", path = "../toml_datetime", default-features = false, features = ["serde", "alloc"] }
5960
serde_spanned = { version = "0.6.9", path = "../serde_spanned", default-features = false, features = ["serde", "alloc"] }
61+
foldhash = { version = "0.1.5", default-features = false, optional = true }
6062

6163
[dev-dependencies]
6264
serde = { version = "1.0.199", features = ["derive"] }

crates/toml/src/map.rs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,12 @@ pub struct Map<K, V> {
4040

4141
#[cfg(not(feature = "preserve_order"))]
4242
type MapImpl<K, V> = BTreeMap<K, V>;
43+
#[cfg(all(feature = "preserve_order", not(feature = "fast_hash")))]
44+
type RandomState = std::collections::hash_map::RandomState;
45+
#[cfg(all(feature = "preserve_order", feature = "fast_hash"))]
46+
type RandomState = foldhash::fast::RandomState;
4347
#[cfg(feature = "preserve_order")]
44-
type MapImpl<K, V> = IndexMap<K, V>;
48+
type MapImpl<K, V> = IndexMap<K, V, RandomState>;
4549

4650
impl<K, V> Map<K, V>
4751
where
@@ -51,6 +55,9 @@ where
5155
#[inline]
5256
pub fn new() -> Self {
5357
Map {
58+
#[cfg(feature = "preserve_order")]
59+
map: MapImpl::with_hasher(RandomState::default()),
60+
#[cfg(not(feature = "preserve_order"))]
5461
map: MapImpl::new(),
5562
dotted: false,
5663
implicit: false,
@@ -64,20 +71,15 @@ where
6471
pub fn with_capacity(capacity: usize) -> Self {
6572
// does not support with_capacity
6673
let _ = capacity;
67-
Map {
68-
map: BTreeMap::new(),
69-
dotted: false,
70-
implicit: false,
71-
inline: false,
72-
}
74+
Self::new()
7375
}
7476

7577
#[cfg(feature = "preserve_order")]
7678
/// Makes a new empty Map with the given initial capacity.
7779
#[inline]
7880
pub fn with_capacity(capacity: usize) -> Self {
7981
Map {
80-
map: IndexMap::with_capacity(capacity),
82+
map: IndexMap::with_capacity_and_hasher(capacity, RandomState::default()),
8183
dotted: false,
8284
implicit: false,
8385
inline: false,
@@ -298,15 +300,13 @@ where
298300
}
299301
}
300302

301-
impl<K, V> Default for Map<K, V> {
303+
impl<K, V> Default for Map<K, V>
304+
where
305+
K: Ord + Hash,
306+
{
302307
#[inline]
303308
fn default() -> Self {
304-
Map {
305-
map: MapImpl::new(),
306-
dotted: false,
307-
implicit: false,
308-
inline: false,
309-
}
309+
Self::new()
310310
}
311311
}
312312

0 commit comments

Comments
 (0)