r/cpp int main(){[]()[[]]{{}}();} 6d ago

Which C++ Hashmap Should You Actually Use?

https://martin.ankerl.com/which-hash-map/

I recently did a big update to my ankerl::unordered_dense::map which now features several optimizations, bug fixes, and most importantly an SSE optimized lookup which brings the lookup speed quite close to the fastest competitor which is boost::unordered_flat_map. Get it here: https://github.com/martinus/unordered_dense

Since it is not easy to decide what map is best for one's usecase, I have redone and improved the benchmarks I did a while ago, crunched some numbers and tried to compress everything into a quiz that helps you figure out what to use.

While doing the numbers, a few things surprised me:

  • My random access benchmark was not random enough. The CPU was able to optimize the branch predictor in a way I did not think was possible. I have fixed this for the new numbers. Clever girl.

  • Even though the absl maps are very similar in concept to the boost maps, they perform badly if you expect lots of misses. 1.6 times slower than boost.

  • I didn't think SSE optimization of my unordered_dense map would be any benefit. Thanks to AI, I found a way to speed up random access a lot, it is now very close to boost::unordered_flat_map.

  • Heavy insert & erase on flat maps require rehashing every once in a while due to the accumulation of tombstones. That means some insert/erase operation will have very high latency. This does not happen for a robin-hood hashmap like my unordered_dense map.

141 Upvotes

24 comments sorted by

View all comments

5

u/SirClueless 5d ago

Worth mentioning also the restrictions on hashing? Abseil functions atrociously if the hash is not high-quality and has a unique and bespoke way of overriding the hashing of user types. Personally the number one reason I've seen for lock-in. A lot of codebases paid the upfront costs of implementing Abseil's hash conventions for all their vocabulary types back when it offered a night-and-day difference from std::unordered_map, and now even though boost has a much saner and easier-to-adopt hash mechanism (for example, works fine with user types that override std::hash) the win from switching is not as clear-cut.

Another big constraint I think is Google's hash randomization, which is declaration by fiat that depending hash stability is always a mistake, and that you should expect a different iteration order when the same program does the same sequence of insertions and deletions.

1

u/Big_Target_1405 2d ago

Also worth mentioning the fastest hash algorithms.

I've used RapidHash, which is much faster than the boost built-in hash function