{"id":21325635,"url":"https://github.com/andreysolovyev381/hash_table_no_invalidation","last_synced_at":"2026-07-08T10:31:06.776Z","repository":{"id":246836120,"uuid":"806094725","full_name":"andreysolovyev381/hash_table_no_invalidation","owner":"andreysolovyev381","description":"C++20 hash table that never invalidates its pointers and iterators. Slightly better than std::unordered - see ./benchmark","archived":false,"fork":false,"pushed_at":"2026-03-14T22:35:05.000Z","size":4654,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-03-15T06:46:38.235Z","etag":null,"topics":["cpp","cpp20","data-structures","hash-table","hashmap","hashtable","header-only","invalidating","invalidation"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/andreysolovyev381.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-05-26T11:10:01.000Z","updated_at":"2026-03-14T22:35:09.000Z","dependencies_parsed_at":null,"dependency_job_id":"928e608f-ffd7-4710-b7a7-e3c758f70fcd","html_url":"https://github.com/andreysolovyev381/hash_table_no_invalidation","commit_stats":null,"previous_names":["andreysolovyev381/hash_table_no_invalidation"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/andreysolovyev381/hash_table_no_invalidation","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreysolovyev381%2Fhash_table_no_invalidation","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreysolovyev381%2Fhash_table_no_invalidation/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreysolovyev381%2Fhash_table_no_invalidation/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreysolovyev381%2Fhash_table_no_invalidation/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andreysolovyev381","download_url":"https://codeload.github.com/andreysolovyev381/hash_table_no_invalidation/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreysolovyev381%2Fhash_table_no_invalidation/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35262336,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-08T02:00:06.796Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp","cpp20","data-structures","hash-table","hashmap","hashtable","header-only","invalidating","invalidation"],"created_at":"2024-11-21T21:06:48.553Z","updated_at":"2026-07-08T10:31:06.759Z","avatar_url":"https://github.com/andreysolovyev381.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Hash table with *NO* invalidation of pointers and iterators\n\n### Rational\nAnother project of mine required a **hash table that never invalidates** its pointers and iterators. I made one with a humble hope to be on par with `std::unordered`. Header only, single C++20 file, see ./include folder. See ./tests for more detailed usage examples. In general, more or less it reproduces `std::unordered` interface.\n\n### Short usage example\n```cpp\n#include \"include/hash_table.hpp\"\n...\n\n    ::containers::hash_table::Set\u003cint\u003e hashSet;\n    hashSet.insert(42);\n    auto found = hashSet.find(42);\n    if (found != hashSet.end()) {...}\n\n    ::containers::hash_table::Map\u003cint, int\u003e hashMap;\n    hashMap[1] = 42;\n    hashMap.insert(std::pair{42, 42});\n    for (auto const\u0026 [k, v] : hashMap) {...}\n\n```\n\n### Reference to other hash tables\nThere are many other hash tables, but I found that more or less all of them are focused on performance, sacrificing exactly what I need — persistence of pointers and iterators. However, there are some serious attempts. Consider reading the [results](https://martin.ankerl.com/2019/04/01/hashmap-benchmarks-01-overview/) of benchmark made by people behind `robin_hood::hash_table`. I also recommend this [reading](https://greg7mdp.github.io/parallel-hashmap/) from Greg Popovitch.\n\n### Benchmark\nSee ./benchmark folder for code. \nHere are the results for 1 million ints I got **at my lower end M1 from early 2022**:\n\n#### Insertion\n\n| Metric | `std::unordered_set` | `hash_table::Set` | `std::unordered_map` | `hash_table::Map` |\n|--------|----------------------|--------------------|----------------------|--------------------|\n| Mean   | 29.76 ns             | 33.55 ns           | 46.07 ns             | 45.84 ns           |\n| Median | 28.01 ns             | 33.78 ns           | 46.01 ns             | 45.82 ns           |\n| Stddev | 3.29 ns              | 0.44 ns            | 0.79 ns              | 0.25 ns            |\n| CV     | 11.05%               | 1.31%              | 1.72%                | 0.54%              |\n| Throughput | 33.92 M/s        | 29.81 M/s          | 21.71 M/s            | 21.82 M/s          |\n\n#### Access\n\n| Metric | `std::unordered_set` | `hash_table::Set` | `std::unordered_map` | `hash_table::Map` |\n|--------|----------------------|--------------------|----------------------|--------------------|\n| Mean   | 25.12 ns             | 26.78 ns           | 25.10 ns             | 27.12 ns           |\n| Median | 25.08 ns             | 26.74 ns           | 25.10 ns             | 26.95 ns           |\n| Stddev | 0.31 ns              | 0.14 ns            | 0.23 ns              | 0.46 ns            |\n| CV     | 1.23%                | 0.53%              | 0.93%                | 1.71%              |\n| Throughput | 39.81 M/s        | 37.34 M/s          | 39.85 M/s            | 36.88 M/s          |\n\n#### Erase\n\n| Metric | `std::unordered_set` | `hash_table::Set` | `std::unordered_map` | `hash_table::Map` |\n|--------|----------------------|--------------------|----------------------|--------------------|\n| Mean   | 3.31 ns              | 16.16 ns           | 3.32 ns              | 16.43 ns           |\n| Median | 3.30 ns              | 16.18 ns           | 3.31 ns              | 16.42 ns           |\n| Stddev | 0.02 ns              | 0.76 ns            | 0.02 ns              | 0.56 ns            |\n| CV     | 0.68%                | 4.70%              | 0.74%                | 3.42%              |\n| Throughput | 302.23 M/s       | 62.00 M/s          | 301.47 M/s           | 60.92 M/s          |\n\n\n### Implementation details\n* Open addressing and linear probing as a collision resolution, in case anybody cares. \n\n* It is allowed to throw, you are the one who should catch. \n\n* Indeed, to nail down all the data, hash table should use a linked list as an underlying structure. The problem is that random memory placement turns out to be bad for cache locality. \nBut thanks to [Bloomberg](https://github.com/bloomberg) and their contribution to committee work, we have `std:pmr` namespace and polymorphic allocators.\nLong story short, this hash table is built upon `std::pmr::list` that allows to place list nodes in memory in an array-like fashion, thus making such a container more cache-friendly. One can see the root source of everything, [Pablo Halpern](https://github.com/phalpern)'s CppCon2017 [report](https://www.youtube.com/watch?v=v3dz-AKOVL8). \n\n* My hypothesis is that after some insert / remove cycles this hash table will deteriorate in its performance — \"*pogrom is a pogrom*\", list is a list, appearance of \"holes\" in that initial array-like placement is inevitable.\n\n### License\nMIT\n\n### Disclosure\nDespite heavy testing performed (see ./tests/test_11.txt), no guarantees of any kind are given whatsoever. Use it at your own risk.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandreysolovyev381%2Fhash_table_no_invalidation","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandreysolovyev381%2Fhash_table_no_invalidation","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandreysolovyev381%2Fhash_table_no_invalidation/lists"}