Skip to content

Commit 4a73a7b

Browse files
committed
Allow custom key type
1 parent e7edd6e commit 4a73a7b

File tree

17 files changed

+702
-243
lines changed

17 files changed

+702
-243
lines changed

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ name = "intmap"
33
version = "2.0.0"
44
edition = "2021"
55
rust-version = "1.58"
6-
description = "Specialized HashMap for u64 keys"
6+
description = "Specialized HashMap for integer keys"
77
authors = ["Jesper Axelsson <[email protected]>"]
88
readme = "README.md"
99
license = "MIT"
1010
repository = "https://github.com/JesperAxelsson/rust-intmap"
11-
keywords = ["hashmap", "u64", "intmap"]
11+
keywords = ["hashmap", "int", "intmap"]
1212

1313
[dependencies]
1414
serde = { version = "1.0", optional = true, default-features = false }

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[![crates.io](https://img.shields.io/crates/v/intmap.svg)](https://crates.io/crates/intmap)
22

33
# rust-intmap
4-
Specialized hashmap for `u64` keys
4+
Specialized hashmap for integer keys.
55

66
Might be missing some functionality but you can remove, add, get and clear for now.
77

@@ -53,12 +53,12 @@ for i in 0..20_000 {
5353
```
5454

5555
# How can it be so much faster?
56-
I use a specialized hash function for `u64` which multiplies the key with the largest prime for `u64`. By keeping the internal cache a power 2 you can avoid the expensive modulus operator as mentioned in [this Stack Overflow post](http://stackoverflow.com/questions/6670715/mod-of-power-2-on-bitwise-operators). The hash function looks like this:
56+
I use a specialized hash function for integers which multiplies the key with the their largest prime. By keeping the internal cache a power 2 you can avoid the expensive modulus operator as mentioned in [this Stack Overflow post](http://stackoverflow.com/questions/6670715/mod-of-power-2-on-bitwise-operators). The hash function looks like this:
5757

5858
```rust
5959
#[inline]
6060
fn hash_u64(seed: u64) -> u64 {
61-
let a = 11400714819323198549u64;
61+
let a = 18446744073709551611u64;
6262
let val = a.wrapping_mul(seed);
6363
val
6464
}

integration_tests/Cargo.lock

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

integration_tests/benchmark/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,7 @@ rand = "0.8.5"
1616
[[bench]]
1717
name = "basic_bench"
1818
harness = false
19+
20+
[[bench]]
21+
name = "key_comparison"
22+
harness = false

integration_tests/benchmark/benches/basic_bench.rs

Lines changed: 40 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ fn main() {
1717
#[bench]
1818
fn u64_insert_built_in(bencher: Bencher) {
1919
let data = get_random_range(VEC_COUNT);
20-
let mut map = HashMap::with_capacity(data.len());
20+
let mut map: HashMap<u64, u64> = HashMap::with_capacity(data.len());
2121

2222
bencher.bench_local(|| {
2323
map.clear();
2424

2525
for s in data.iter() {
26-
black_box(map.insert(s, s));
26+
black_box(map.insert(*s, *s));
2727
}
2828
});
2929
}
@@ -33,10 +33,10 @@ fn u64_insert_without_capacity_built_in(bencher: Bencher) {
3333
let data = get_random_range(VEC_COUNT);
3434

3535
bencher.bench_local(|| {
36-
let mut map = HashMap::new();
36+
let mut map: HashMap<u64, u64> = HashMap::new();
3737

3838
for s in data.iter() {
39-
black_box(map.insert(s, s));
39+
black_box(map.insert(*s, *s));
4040
}
4141

4242
black_box(&map);
@@ -46,10 +46,10 @@ fn u64_insert_without_capacity_built_in(bencher: Bencher) {
4646
#[bench]
4747
fn u64_get_built_in(bencher: Bencher) {
4848
let data = get_random_range(VEC_COUNT);
49-
let mut map: HashMap<&u64, &u64> = HashMap::with_capacity(data.len());
49+
let mut map: HashMap<u64, u64> = HashMap::with_capacity(data.len());
5050

5151
for s in data.iter() {
52-
black_box(map.insert(s, s));
52+
black_box(map.insert(*s, *s));
5353
}
5454

5555
bencher.bench_local(|| {
@@ -87,13 +87,14 @@ impl std::hash::BuildHasher for NoOpHasher {
8787
#[bench]
8888
fn u64_insert_no_op(bencher: Bencher) {
8989
let data = get_random_range(VEC_COUNT);
90-
let mut map = HashMap::with_capacity_and_hasher(data.len(), NoOpHasher(0));
90+
let mut map: HashMap<u64, u64, NoOpHasher> =
91+
HashMap::with_capacity_and_hasher(data.len(), NoOpHasher(0));
9192

9293
bencher.bench_local(|| {
9394
map.clear();
9495

9596
for s in data.iter() {
96-
black_box(map.insert(s, s));
97+
black_box(map.insert(*s, *s));
9798
}
9899
});
99100
}
@@ -103,10 +104,10 @@ fn u64_insert_without_capacity_no_op(bencher: Bencher) {
103104
let data = get_random_range(VEC_COUNT);
104105

105106
bencher.bench_local(|| {
106-
let mut map = HashMap::with_hasher(NoOpHasher(0));
107+
let mut map: HashMap<u64, u64, NoOpHasher> = HashMap::with_hasher(NoOpHasher(0));
107108

108109
for s in data.iter() {
109-
black_box(map.insert(s, s));
110+
black_box(map.insert(*s, *s));
110111
}
111112

112113
black_box(&map);
@@ -116,11 +117,11 @@ fn u64_insert_without_capacity_no_op(bencher: Bencher) {
116117
#[bench]
117118
fn u64_get_no_op(bencher: Bencher) {
118119
let data = get_random_range(VEC_COUNT);
119-
let mut map: HashMap<&u64, &u64, NoOpHasher> =
120+
let mut map: HashMap<u64, u64, NoOpHasher> =
120121
HashMap::with_capacity_and_hasher(data.len(), NoOpHasher(0));
121122

122123
for s in data.iter() {
123-
black_box(map.insert(s, s));
124+
black_box(map.insert(*s, *s));
124125
}
125126

126127
bencher.bench_local(|| {
@@ -135,13 +136,13 @@ fn u64_get_no_op(bencher: Bencher) {
135136
#[bench]
136137
fn u64_insert_brown(bencher: Bencher) {
137138
let data = get_random_range(VEC_COUNT);
138-
let mut map = BrownMap::with_capacity(data.len());
139+
let mut map: BrownMap<u64, u64> = BrownMap::with_capacity(data.len());
139140

140141
bencher.bench_local(|| {
141142
map.clear();
142143

143144
for s in data.iter() {
144-
black_box(map.insert(s, s));
145+
black_box(map.insert(*s, *s));
145146
}
146147
});
147148
}
@@ -151,10 +152,10 @@ fn u64_insert_without_capacity_brown(bencher: Bencher) {
151152
let data = get_random_range(VEC_COUNT);
152153

153154
bencher.bench_local(|| {
154-
let mut map = BrownMap::new();
155+
let mut map: BrownMap<u64, u64> = BrownMap::new();
155156

156157
for s in data.iter() {
157-
black_box(map.insert(s, s));
158+
black_box(map.insert(*s, *s));
158159
}
159160

160161
black_box(&map);
@@ -164,10 +165,10 @@ fn u64_insert_without_capacity_brown(bencher: Bencher) {
164165
#[bench]
165166
fn u64_get_brown(bencher: Bencher) {
166167
let data = get_random_range(VEC_COUNT);
167-
let mut map: BrownMap<&u64, &u64> = BrownMap::with_capacity(data.len());
168+
let mut map: BrownMap<u64, u64> = BrownMap::with_capacity(data.len());
168169

169170
for s in data.iter() {
170-
black_box(map.insert(s, s));
171+
black_box(map.insert(*s, *s));
171172
}
172173

173174
bencher.bench_local(|| {
@@ -182,13 +183,13 @@ fn u64_get_brown(bencher: Bencher) {
182183
#[bench]
183184
fn u64_insert_ahash(bencher: Bencher) {
184185
let data = get_random_range(VEC_COUNT);
185-
let mut map = AHashMap::with_capacity(data.len());
186+
let mut map: AHashMap<u64, u64> = AHashMap::with_capacity(data.len());
186187

187188
bencher.bench_local(|| {
188189
map.clear();
189190

190191
for s in data.iter() {
191-
black_box(map.insert(s, s));
192+
black_box(map.insert(*s, *s));
192193
}
193194
});
194195
}
@@ -198,10 +199,10 @@ fn u64_insert_without_capacity_ahash(bencher: Bencher) {
198199
let data = get_random_range(VEC_COUNT);
199200

200201
bencher.bench_local(|| {
201-
let mut map = AHashMap::new();
202+
let mut map: AHashMap<u64, u64> = AHashMap::new();
202203

203204
for s in data.iter() {
204-
black_box(map.insert(s, s));
205+
black_box(map.insert(*s, *s));
205206
}
206207

207208
black_box(&map);
@@ -211,10 +212,10 @@ fn u64_insert_without_capacity_ahash(bencher: Bencher) {
211212
#[bench]
212213
fn u64_get_ahash(bencher: Bencher) {
213214
let data = get_random_range(VEC_COUNT);
214-
let mut map: AHashMap<&u64, &u64> = AHashMap::with_capacity(data.len());
215+
let mut map: AHashMap<u64, u64> = AHashMap::with_capacity(data.len());
215216

216217
for s in data.iter() {
217-
black_box(map.insert(s, s));
218+
black_box(map.insert(*s, *s));
218219
}
219220

220221
bencher.bench_local(|| {
@@ -229,24 +230,24 @@ fn u64_get_ahash(bencher: Bencher) {
229230
#[bench]
230231
fn u64_insert_indexmap(bencher: Bencher) {
231232
let data = get_random_range(VEC_COUNT);
232-
let mut map = IndexMap::with_capacity(data.len());
233+
let mut map: IndexMap<u64, u64> = IndexMap::with_capacity(data.len());
233234

234235
bencher.bench_local(|| {
235236
map.clear();
236237

237238
for s in data.iter() {
238-
black_box(map.insert(s, s));
239+
black_box(map.insert(*s, *s));
239240
}
240241
});
241242
}
242243

243244
#[bench]
244245
fn u64_get_indexmap(bencher: Bencher) {
245246
let data = get_random_range(VEC_COUNT);
246-
let mut map: IndexMap<&u64, &u64> = IndexMap::with_capacity(data.len());
247+
let mut map: IndexMap<u64, u64> = IndexMap::with_capacity(data.len());
247248

248249
for s in data.iter() {
249-
black_box(map.insert(s, s));
250+
black_box(map.insert(*s, *s));
250251
}
251252

252253
bencher.bench_local(|| {
@@ -261,27 +262,27 @@ fn u64_get_indexmap(bencher: Bencher) {
261262
#[bench]
262263
fn u64_insert_intmap(bencher: Bencher) {
263264
let data = get_random_range(VEC_COUNT);
264-
let mut map = IntMap::with_capacity(data.len());
265+
let mut map: IntMap<u64, u64> = IntMap::with_capacity(data.len());
265266

266267
bencher.bench_local(|| {
267268
map.clear();
268269

269270
for s in data.iter() {
270-
black_box(map.insert(*s, s));
271+
black_box(map.insert(*s, *s));
271272
}
272273
});
273274
}
274275

275276
#[bench]
276277
fn u64_insert_intmap_checked(bencher: Bencher) {
277278
let data = get_random_range(VEC_COUNT);
278-
let mut map = IntMap::with_capacity(data.len());
279+
let mut map: IntMap<u64, u64> = IntMap::with_capacity(data.len());
279280

280281
bencher.bench_local(|| {
281282
map.clear();
282283

283284
for s in data.iter() {
284-
black_box(map.insert_checked(*s, s));
285+
black_box(map.insert_checked(*s, *s));
285286
}
286287
});
287288
}
@@ -290,15 +291,15 @@ fn u64_insert_intmap_checked(bencher: Bencher) {
290291
fn u64_insert_intmap_entry(bencher: Bencher) {
291292
let data = get_random_range(VEC_COUNT);
292293

293-
let mut map = IntMap::with_capacity(data.len());
294+
let mut map: IntMap<u64, u64> = IntMap::with_capacity(data.len());
294295

295296
bencher.bench_local(|| {
296297
map.clear();
297298

298299
for s in data.iter() {
299300
black_box(match map.entry(*s) {
300301
Entry::Occupied(_) => panic!("unexpected while insert, i = {}", s),
301-
Entry::Vacant(entry) => entry.insert(s),
302+
Entry::Vacant(entry) => entry.insert(*s),
302303
});
303304
}
304305
});
@@ -309,10 +310,10 @@ fn u64_insert_without_capacity_intmap(bencher: Bencher) {
309310
let data = get_random_range(VEC_COUNT);
310311

311312
bencher.bench_local(|| {
312-
let mut map = IntMap::new();
313+
let mut map: IntMap<u64, u64> = IntMap::new();
313314

314315
for s in data.iter() {
315-
black_box(map.insert(*s, s));
316+
black_box(map.insert(*s, *s));
316317
}
317318

318319
black_box(&map);
@@ -322,7 +323,7 @@ fn u64_insert_without_capacity_intmap(bencher: Bencher) {
322323
#[bench]
323324
fn u64_resize_intmap(bencher: Bencher) {
324325
bencher.bench_local(|| {
325-
let mut map: IntMap<u64> = IntMap::new();
326+
let mut map: IntMap<u64, u64> = IntMap::new();
326327
map.reserve(VEC_COUNT);
327328
black_box(&map);
328329
});
@@ -332,9 +333,9 @@ fn u64_resize_intmap(bencher: Bencher) {
332333
fn u64_get_intmap(bencher: Bencher) {
333334
let data = get_random_range(VEC_COUNT);
334335

335-
let mut map = IntMap::with_capacity(data.len());
336+
let mut map: IntMap<u64, u64> = IntMap::with_capacity(data.len());
336337
for s in data.iter() {
337-
map.insert(*s, s);
338+
map.insert(*s, *s);
338339
}
339340

340341
bencher.bench_local(|| {

0 commit comments

Comments
 (0)