Writing a hashmap in Rust for learning and fun.
Please see the accompanying blog posts:
- Part 1: Intro and two naive maps
- Part 2: Swiss Table metadata and MaybeUninit
- Part 3a: SIMD probing
- Part 3b: Exception safety
- Part 3c: Resizing with SIMD
The design was inspired by Google's Swiss Tables map and Rust's std::collections::HashMap aka hashbrown (based on Swiss Tables).
This repo contains 6 iterations on a hashmap, building from a naive design toward (a simplified) Swiss Tables:
first::Map: separate chaining usingstd::collections::LinkedListsecond::Map: open addressing (quadratic probing)third::Map: open addressing with Swiss tables metadatafourth::Map: same asthirdbut usingstd::mem::MaybeUninitas an optimizationfifth::Map: same asfourthbut adding SIMD probingsixth::Map(unfinished): same asfifthbut putting the metadata and backing storage in the same allocation (with a lot ofunsafe)
These are done with the benchmarks in /benches.
Reported times are for my laptop (Intel i7-10750H, 32 GB RAM, Fedora 37).
| Benchmark name | std runtime (ms) |
fifth::Map runtime (ms) |
Ratio |
|---|---|---|---|
| insert_grow_seq 1 | 3.85 | 4.58 | 1.19 |
| insert_grow_seq 8 | 4.81 | 5.79 | 1.20 |
| insert_grow_random 1 | 3.95 | 4.75 | 1.20 |
| insert_grow_random 8 | 4.87 | 5.87 | 1.21 |
| insert_reserved 1 | 2.03 | 2.26 | 1.11 |
| insert_reserved 8 | 2.47 | 2.74 | 1.11 |
| lookup 1 | 2.14 | 2.61 | 1.22 |
| lookup 8 | 3.11 | 4.3 | 1.38 |
| lookup string 1 | 4.32 | 4.61 | 1.07 |
| lookup string 8 | 7.07 | 7.17 | 1.01 |
| lookup miss 1 | 1.84 | 1.99 | 1.08 |
| lookup miss 8 | 2.02 | 2.26 | 1.12 |
| remove 1 | 3.07 | 3.49 | 1.14 |
| remove 8 | 5.00 | 5.60 | 1.12 |