Frequently Asked Questions
August 1, 2026 · View on GitHub
General
Which emhash version should I use?
| Scenario | Recommended Version |
|---|---|
Complex/large keys or values (e.g., std::string) | emhash8 |
| Insert-intensive workloads, high load factor | emhash7 |
| Fast lookup/erase with integer keys | emhash5 or emhash6 |
| Small maps that should avoid heap allocation | emhash5 with EMH_SMALL_SIZE |
What is the difference between emhash and emilib?
| Aspect | emhash (5/6/7/8) | emilib (1/2/3) |
|---|---|---|
| Collision resolution | Linked-bucket chains | Swiss-table-style byte probing |
| SIMD usage | Limited (CTZ/bitmask) | Pervasive (H2 tag filtering, iteration) |
| Best for | General purpose, high load factor | SIMD-friendly keys, read-heavy |
| Load factor | Default 0.80, up to 0.999 | emihmap1: fixed 5/6 ≈ 0.833; emihmap2/3: 0.25–0.999; emihmap4: fixed 0.875 |
Which emilib version should I use?
| Scenario | Recommended Version |
|---|---|
| Fixed workloads, stable load factor, simplest structure | emihmap1 |
| Variable workloads, high load factor (up to 0.999) | emihmap2 |
| Balanced default, minimal metadata overhead | emihmap3 |
Is emhash thread-safe?
No. emhash is not thread-safe for concurrent writes. However, concurrent read-only access (e.g., find(), contains(), count()) from multiple threads is safe as long as no thread is modifying the map.
For concurrent writes, use external synchronization:
std::mutex mtx;
{
std::lock_guard<std::mutex> lock(mtx);
map[key] = val;
}
Can I use a higher load factor?
Yes. Define EMH_HIGH_LOAD=<value> at compile time (e.g., -DEMH_HIGH_LOAD=123456) to enable load factors up to 0.999. emhash7 supports high load factors natively without this macro.
emhash7::HashMap<int, int> map(1024, 0.999f); // Works natively
emhash8::HashMap<int, int> map(1024, 0.999f); // Requires -DEMH_HIGH_LOAD=123456
Does emhash guarantee reference stability?
No. emhash uses open addressing with a single contiguous array. References, pointers, and iterators to elements may be invalidated by insert(), erase(), or rehash().
Workaround: Copy values before modifying the map, or call reserve() to pre-allocate and avoid rehashing.
// Safe: copy first
auto val = map[key1];
map[key2] = val; // OK even if rehash occurs
// Unsafe: reference may dangle
auto& ref = map[key1];
map[key2] = ref; // DANGER: rehash may invalidate ref
How do I defend against hash attacks?
Define EMH_SAFE_HASH=1 at compile time. This enables a backup hash function at approximately 10% performance cost.
For emilib implementations, use EMH_SAFE_PSL=1 to limit probe sequence length.
Performance
Why is emhash faster than std::unordered_map?
- Open addressing — single contiguous array, better cache locality
- No per-element heap allocation —
std::unordered_mapallocates a node per element - No tombstones (all emhash versions) — no performance degradation from frequent erase
- Smart collision resolution — hybrid probing strategies
Why is emhash8 iteration so fast?
emhash8 uses a split layout: a separate dense _pairs[] array stores all key-value pairs contiguously. Iteration is just a sequential memory scan — no metadata to skip, no empty buckets to check.
How much memory does emhash save?
When sizeof(key) % 8 != sizeof(value) % 8, emhash saves significant memory:
// emhash7: compact layout
emhash7::HashMap<uint64_t, uint32_t> // saves ~1/3 vs HashMap<uint64_t, uint64_t>
// std::unordered_map: always allocates full node
std::unordered_map<uint64_t, uint32_t> // same node size as <uint64_t, uint64_t>
Compatibility
Which C++ standards are supported?
emhash requires C++17 or later. All versions (emhash5, emhash6, emhash7, emhash8) support C++17 and C++23.
Which compilers are supported?
- GCC 7+ (tested: 11, 12, 13)
- Clang 6+ (tested: 16, 17, 18)
- MSVC 2019+ (Visual Studio 16+)
- MinGW GCC 10+
Can I use a custom allocator?
Yes. All HashMap versions support custom allocators as the 5th template parameter:
emhash7::HashMap<Key, Val, Hash, Eq, MyAllocator> mymap;
The allocator must satisfy the C++ Allocator requirements and support rebind.