{"id":51546575,"url":"https://github.com/bluuewhale/hash-smith","last_synced_at":"2026-07-12T19:00:28.869Z","repository":{"id":327770503,"uuid":"1110712068","full_name":"bluuewhale/hash-smith","owner":"bluuewhale","description":"Fast \u0026 memory efficient hash tables for Java","archived":false,"fork":false,"pushed_at":"2026-04-05T02:43:52.000Z","size":4219,"stargazers_count":96,"open_issues_count":1,"forks_count":7,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-05T03:12:46.330Z","etag":null,"topics":["benchmark","collections","hashtable","java","jmh","open-addressing","robinhood-hashing","simd","swiss-table"],"latest_commit_sha":null,"homepage":"","language":"Java","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/bluuewhale.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-05T15:52:13.000Z","updated_at":"2026-04-05T02:43:55.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/bluuewhale/hash-smith","commit_stats":null,"previous_names":["bluuewhale/swisstable-java","bluuewhale/hash-smith"],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/bluuewhale/hash-smith","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bluuewhale%2Fhash-smith","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bluuewhale%2Fhash-smith/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bluuewhale%2Fhash-smith/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bluuewhale%2Fhash-smith/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bluuewhale","download_url":"https://codeload.github.com/bluuewhale/hash-smith/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bluuewhale%2Fhash-smith/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35400291,"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-12T02:00:06.386Z","response_time":87,"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":["benchmark","collections","hashtable","java","jmh","open-addressing","robinhood-hashing","simd","swiss-table"],"created_at":"2026-07-09T19:00:23.368Z","updated_at":"2026-07-12T19:00:28.833Z","avatar_url":"https://github.com/bluuewhale.png","language":"Java","funding_links":[],"categories":["Projects"],"sub_categories":["Data Structures"],"readme":"# HashSmith: Fast \u0026 memory efficient hash tables for Java\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n[![Maven Central](https://img.shields.io/maven-central/v/io.github.bluuewhale/hashsmith.svg)](https://central.sonatype.com/artifact/io.github.bluuewhale/hashsmith)\n[![javadoc](https://javadoc.io/badge2/io.github.bluuewhale/hashsmith/javadoc.svg)](https://javadoc.io/doc/io.github.bluuewhale/hashsmith)\n[![Status: experimental](https://img.shields.io/badge/status-experimental-orange.svg)](#overview)\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"images/logo.png\" alt=\"HashSmith logo\" width=\"330\"\u003e\n\u003c/p\u003e\n\n\n## Overview\n- HashSmith provides multiple high-performance hash table implementations optimized for speed and memory efficiency on modern JVMs.\n- Focus areas: SWAR-probing (`SwissMap`), SIMD-probing (`SwissSimdMap`), predictable probe lengths (Robin Hood), and minimal per-entry overhead.\n- Built for JDK 21+; `SwissSimdMap` uses the incubating Vector API for SIMD acceleration.\n- More memory-efficient than the built-in JDK `HashMap`; performance depends on workload.\n\n## Implementations\n- **SwissMap**: SwissTable-inspired design using SWAR control-byte probing (no Vector API) with tombstone reuse. Default map.\n- **SwissSimdMap**: SIMD (Vector API incubator) variant of SwissMap with vectorized control-byte probing. See `docs/SwissSimdMap.md` for details.\n- **ConcurrentSwissMap**: sharded, thread-safe wrapper around `SwissMap` using per-shard `StampedLock` (null keys not supported).\n- **SwissSet**: SwissTable-style hash set with SIMD control-byte probing, tombstone reuse, and null-element support \n\n### Why SWAR by default?\nVector API is still incubating, and profiling on my setup showed the SIMD path taking longer than expected, so the default `SwissMap` favors a SWAR probe. Numbers can differ significantly by hardware/JVM version; please run your own benchmarks if you plan to use `SwissSimdMap`.\n\n## Blog / Write-up\n- If you want a guided tour with design notes and benchmarks, see **[this write-up](https://bluuewhale.github.io/posts/building-a-fast-and-memory-efficient-hash-table-in-java-by-borrowing-the-best-ideas/)**.\n\n## Quick Start\n```java\nimport io.github.bluuewhale.hashsmith.SwissMap;      // SWAR\nimport io.github.bluuewhale.hashsmith.ConcurrentSwissMap;\nimport io.github.bluuewhale.hashsmith.SwissSet;\n\n// SwissMap (SWAR)\nvar swiss = new SwissMap\u003cString, Integer\u003e();\nswiss.put(\"a\", 1);\nswiss.get(\"a\"); // 1\n\n// ConcurrentSwissMap (sharded, thread-safe)\nvar concurrentSwiss = new ConcurrentSwissMap\u003cString, Integer\u003e();\nconcurrentSwiss.put(\"a\", 1);\nconcurrentSwiss.get(\"a\"); // 1\n\n// SwissSet\nvar swissSet = new SwissSet\u003cString\u003e();\nswissSet.add(\"k\");\nswissSet.add(null); // nulls allowed\nswissSet.contains(\"k\"); // true\n```\n\n## Install\n- Gradle (Kotlin DSL):\n```kotlin\ndependencies {\n    implementation(\"io.github.bluuewhale:hashsmith:0.2.0\")\n}\n```\n- Gradle (Groovy):\n```groovy\ndependencies {\n    implementation 'io.github.bluuewhale:hashsmith:0.2.0'\n}\n```\n- Maven:\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003eio.github.bluuewhale\u003c/groupId\u003e\n  \u003cartifactId\u003ehashsmith\u003c/artifactId\u003e\n  \u003cversion\u003e0.2.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n## Requirements\n- JDK 21+ (`SwissSimdMap` needs `jdk.incubator.vector`)\n- Gradle (wrapper provided)\n- The JVM flag `--add-modules jdk.incubator.vector` is already configured for build, test, and JMH tasks that exercise `SwissSimdMap`.\n\n## Build \u0026 Test\n```bash\n./gradlew build        # full build\n./gradlew test         # JUnit 5 tests\n```\n\n## Memory Footprint \n- Compares retained heap for both maps (`HashMap` vs `SwissSimdMap` vs `SwissMap` vs fastutil `Object2ObjectOpenHashMap` vs Eclipse Collections `UnifiedMap`) and sets (`HashSet` vs `SwissSet` vs fastutil `ObjectOpenHashSet` vs Eclipse Collections `UnifiedSet`).\n- Set benchmarks use UUID `String` keys (HashSet, SwissSet, ObjectOpenHashSet, UnifiedSet). Primitive-specialized collections (e.g., fastutil primitive sets) are excluded because their memory profile is driven by primitive storage, whereas these tests target general reference workloads.\n### Results\n- Maps: `SwissMap`/`SwissSimdMap` use open addressing to cut space; default load factor 0.875, up to 53.3% retained-heap reduction in payload-light cases vs `HashMap`.\n- Sets: `SwissSet` (SwissHashSet) mirrors the SwissTable layout with SIMD control-byte probing and reuses tombstones to stay denser than `HashSet` across tested payloads, showing up to ~62% retained-heap reduction in lighter payload cases.\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003cth\u003eMap\u003c/th\u003e\n    \u003cth\u003eSet\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cimg src=\"images/map-memory-bool.png\" alt=\"HashMap Memory Footprint\" width=\"420\"\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003cimg src=\"images/set-memory-uuid.png\" alt=\"HashSet Memory Footprint\" width=\"420\"\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n## Benchmark (JMH, CPU ns/op)\n- All benchmarks run on the same machine: Eclipse Temurin JDK 21, macOS/Apple Silicon, `AverageTime` mode, 3 forks.\n- SwissMap numbers reflect exp-001 optimizations.\n\n| put hit                                     | put miss                                      |\n|---------------------------------------------|-----------------------------------------------|\n| ![CPU: put hit](images/map-cpu-put-hit.png) | ![CPU: put miss](images/map-cpu-put-miss.png) |\n\n| get hit | get miss |\n| --- | --- |\n| ![CPU: get hit](images/map-cpu-get-hit.png) | ![CPU: get miss](images/map-cpu-get-miss.png) |\n\n\n\n\n## Contributing\n1) Open an issue for bugs/ideas  \n2) Work on a feature branch and open a PR  \n3) Keep tests/JMH green before submitting\n\n## License\n- This project is licensed under the MIT License. See [`LICENSE`](./LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbluuewhale%2Fhash-smith","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbluuewhale%2Fhash-smith","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbluuewhale%2Fhash-smith/lists"}