-
Notifications
You must be signed in to change notification settings - Fork 22
Description
Motivation
Hash{Map,Set}::with_capacity limit us to the default hashing algorithm (SipHash).
Solutions
I have 2 ideas on how to implement this suggestion.
Extend capabilities of hashmap! and hashset!
I tried to trivially modify hashmap! like this:
macro_rules! hashmap {
(@single $($x:tt)*) => (());
(@count $($rest:expr),*) => (<[()]>::len(&[$(hashmap!(@single $rest)),*]));
($($key:expr => $value:expr,)+) => { hashmap!($($key => $value),+) };
($($key:expr => $value:expr),*) => {
{
let _cap = hashmap!(@count $($key),*);
- let mut _map = ::std::collections::HashMap::with_capacity(_cap);
+ let mut _map = ::std::collections::HashMap::with_capacity_and_hasher(_cap, Default::default());
$(
let _ = _map.insert($key, $value);
)*
_map
}
};
}For hashset! changes are analogous.
Unfortunately, this change messes with type inference:
error[E0282]: unable to infer enough type information about `S`
--> src/main.rs:5:15
|
5 | let map = hashmap! {
| _______________^ starting here...
6 | | "a" => 1,
7 | | "b" => 3,
8 | | "c" => 2,
9 | | };
| |_____^ ...ending here: cannot infer type for `S`
|
= note: type annotations or generic parameter binding required
= note: this error originates in a macro outside of the current crate
Aside from the fact that this is a breaking change (I bet most of the code that uses these macros relies on type inference to remove boilerplate), this change also requires users to always write down the exact type which is unergonomic.
If anyone has a better idea how to approach this problem without creating new macros, please comment!
Add new macros
hashmap_with_hasher!--- create aHashMapwith a providedBuildHasherhashmap_with_default_hasher!--- create aHashMapwith a defaultBuildHasherhashset_with_hasher!--- create aHashSetwith a providedBuildHasherhashset_with_default_hasher!--- create aHashSetwith a defaultBuildHasher
hash{map,set}_with_default_hasher! work as hash{map,set}! but use S::default() where S: BuildHasher + Default instead of RandomState::default().
Syntax of hash{map,set}_with_hasher! are subject for bikeshedding:
// 1
hashmap_with_hasher!(FnvHasher::with_key(0), {
"a" => 1,
"b" => 2,
});
hashset_with_hasher!(FnvHasher::with_key(0), {"a", "b"});
// 2
hashmap_with_hasher! {
hasher = FnvHasher::with_key(0),
data = {
"a" => 1,
"b" => 2,
},
};
hashset_with_hasher! {
hasher = FnvHasher::with_key(0),
data = {"a", "b"},
};
// Additional syntaxes are welcome!