Skip to content

feat(collections): add SparseSet — bounded-universe sparse integer set with O(1) clear & dense iteration - #288

Merged
marius-bughiu merged 9 commits into
mainfrom
feat/sparse-set
Jul 24, 2026
Merged

feat(collections): add SparseSet — bounded-universe sparse integer set with O(1) clear & dense iteration#288
marius-bughiu merged 9 commits into
mainfrom
feat/sparse-set

Conversation

@marius-bughiu

Copy link
Copy Markdown
Owner

What

Adds SparseSet — a set of non-negative integers over a bounded universe [0, Universe), backed by the classic Briggs–Torczon sparse-set representation (a dense value array + a sparse index array). Closes #287.

.NET ships no sparse set, and HashSet<int> cannot match its two defining wins:

  • Clear() is O(1) — it resets the count and touches no memory (HashSet<int>.Clear() is O(capacity), zeroing its entire entry table). This is the headline for clear-and-rebuild "visited" sets: graph BFS/DFS, ECS entity membership, sweep-line, register-allocation liveness.
  • Dense, cache-friendly iteration over exactly the present elements (contiguous [0, Count) of the dense array).

Add / Contains / Remove are O(1) with no hashing, no probe chain, no allocation — a direct array index plus the sparse↔dense round-trip check (sparse[v] < Count && dense[sparse[v]] == v), which is correct even against the stale garbage a Clear leaves behind. Implements ISet<int>.

Tradeoffs (documented honestly): O(Universe) memory for the sparse index array; stores only non-negative values below Universe (out of range throws on Add, reads as absent on Contains/Remove). It is an opt-in specialized type, not a HashSet<int> replacement — for an unbounded or huge-and-sparse key space, IntSet / HashSet<int> remain right.

This is the established post-roadmap tier-(c) pattern (EnumSet / SwissSet / TopKSketch): the roadmap's specialized-collection work is done; this fills a BCL gap found while reading the source.

Parity rollout (all in this PR)

Facet Change
Collection src/Celerity/Collections/SparseSet.csISet<int>, allocation-free struct enumerator
Dedicated tests SparseSetTests, SparseSetEnumerationTests, SparseSetDifferentialTests (6,000-step randomized differential vs HashSet<int> over a bounded non-negative universe, with clear-then-reuse stress)
Cross-collection tests SetAlgebraTests rows — ISet<int> conformance + the bounded-universe out-of-range-add caveat. It carries its own differential rather than joining the shared SetAlgebraDifferentialTests, whose universe spans negatives it cannot store — exactly like EnumSet.
Benchmark SparseSetBenchmark (Add / Contains / ClearRefill / Remove vs HashSet<int>), registered in Program.cs CoreBenchmarks
Dashboard ship card (web/index.html) + COLLECTIONS arrays (web/dev/bench/index.html, web/dev/bench/detail.html)
Docs full API section in docs/api/collections.md + README (Sets list, ISet<T> note, paragraph + example, decision-table row)
CHANGELOG one [Unreleased] bullet per facet
AOT smoke test SparseSet coverage block in Celerity.AotSmokeTest

ROADMAP: no status to flip — SparseSet was not a roadmap line item; the specialized-collection milestone is already done. Noted, per the parity checklist's "items that genuinely don't apply".

Parity facets that genuinely don't apply: the hash-oriented shared suites (SetConstructorValidationTests / TryAddProbeCountTests / EnsureCapacityAndTrimExcessTests / LoadFactorBoundaryTests, etc.) assume a hash table with a loadFactor, a probe count, and power-of-two sizing — SparseSet has a universe, no hasher, and no probing, so it does not join them (same rationale as EnumSet).

Test plan

  • dotnet build (library + tests + benchmarks + AOT smoke test) — clean, 0 warnings on the library (XML docs complete).
  • Full test suite green on net9.0 (4,285 passed, 0 failed).
  • SparseSet subset green on the net8.0 floor (69 passed).
  • AOT smoke test program runs green (JIT) incl. the new SparseSet checks.
  • CI matrix (net8.0 / net9.0 / net10.0 × Windows / Linux / macOS), coverage gate, Native AOT publish job, and the benchmark job.
  • On merge to main, the benchmark workflow publishes SparseSetBenchmark's data.js to gh-pages; the dashboard wiring here surfaces it (Add / Contains / ClearRefill / Remove).

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings July 21, 2026 01:21
@github-actions

github-actions Bot commented Jul 21, 2026

Copy link
Copy Markdown

Coverage

Metric Value
Line 98.59% (6912/7011)
Branch 97.13% (2908/2994)
Files below 100% line coverage
File Line Branch
src/Celerity/Collections/TopKEntry.cs 80% n/a
src/Celerity/Collections/XorFilter.cs 94.29% 90%
src/Celerity/Collections/EnumMap.cs 95.09% 92.19%
src/Celerity/Collections/IndexedPriorityQueue.cs 96.23% 90.91%
src/Celerity/Collections/CuckooFilter.cs 96.6% 90.38%

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds SparseSet to Celerity’s specialized collections: a bounded-universe [0, Universe) integer set using the classic dense+sparse representation to deliver O(1) Clear() (no memory touched) and dense iteration, plus full parity wiring (tests, benchmarks, docs, dashboard, AOT smoke test, changelog).

Changes:

  • Introduces SparseSet : ISet<int> with allocation-free struct enumerator and bounded-universe semantics.
  • Adds dedicated unit + enumeration + randomized differential tests, and a benchmark (incl. ClearRefill) registered in core benchmarks.
  • Updates docs/README + web benchmark dashboard wiring + AOT smoke test + changelog entry.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
web/index.html Adds SparseSet to “What ships in the box” list.
web/dev/bench/index.html Registers SparseSet in benchmark dashboard collection list (incl. ClearRefill).
web/dev/bench/detail.html Adds SparseSet to per-collection benchmark detail list.
src/Celerity/Collections/SparseSet.cs New bounded-universe sparse set implementation + struct enumerator.
src/Celerity.Tests/Collections/SparseSetTests.cs Core behavior tests (range rules, add/remove/clear, capacity helpers, conformance).
src/Celerity.Tests/Collections/SparseSetEnumerationTests.cs Enumerator behavior + mutation detection coverage.
src/Celerity.Tests/Collections/SparseSetDifferentialTests.cs Randomized differential testing vs HashSet<int> over non-negative bounded universe.
src/Celerity.Tests/Collections/SetAlgebraTests.cs Adds SparseSet conformance + bounded-universe set-algebra caveat test.
src/Celerity.Benchmarks/SparseSetBenchmark.cs New benchmark comparing SparseSet vs HashSet<int> (Add/Contains/ClearRefill/Remove).
src/Celerity.Benchmarks/Program.cs Registers SparseSetBenchmark in core benchmark suite.
src/Celerity.AotSmokeTest/Program.cs Adds runtime smoke coverage for SparseSet (incl. clear-then-reuse).
README.md Documents SparseSet in sets list, narrative, example, and decision table.
docs/api/collections.md Adds full API documentation section for SparseSet.
CHANGELOG.md Adds [Unreleased] entries for SparseSet and parity facets.

Comment thread CHANGELOG.md Outdated
Copilot AI review requested due to automatic review settings July 21, 2026 01:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

CHANGELOG.md:15

  • The new [Unreleased] entries are far more detailed than the repo's changelog guidance: CONTRIBUTING.md asks for entries to be "a few sentences at most" and user-facing, and to avoid implementation walkthroughs / internal wiring. Consider collapsing these into a single concise, caller-focused bullet for the new public API (and leaving test/benchmark/dashboard wiring details to the PR description).
- **`SparseSet`** in `Celerity.Collections` — a set of non-negative integers over a bounded universe `[0, Universe)`, backed by the Briggs–Torczon sparse-set representation (a dense value array + a sparse index array), filling a BCL gap (.NET ships no sparse set). Its two wins over `HashSet<int>`: `Clear()` is `O(1)` and touches no memory (`HashSet` zeroes its whole table), and iteration is a dense, cache-friendly scan over exactly the present elements — the winning shape for clear-and-rebuild "visited" sets in graph traversal, ECS, and sweep-line code. `Add` / `Contains` / `Remove` are `O(1)` with no hashing. Costs `O(Universe)` memory and stores only values in `[0, Universe)` (out-of-range throws on `Add`, reads as absent on `Contains` / `Remove`). Implements `ISet<int>`. An opt-in specialized type, not a `HashSet<int>` replacement. Closes [#287](https://github.com/marius-bughiu/Celerity/issues/287).
- `SparseSetTests`, `SparseSetEnumerationTests`, and `SparseSetDifferentialTests` (`Celerity.Tests/Collections`) — dedicated coverage mirroring the `IntSet*` / `SmallSet*` files: the core surface (add / try-add / duplicate / out-of-range / contains / remove-swap / dense-array growth / the O(1) `Clear`-then-reuse path that must reject stale sparse entries), the enumeration surface (every-element-once, growth, post-remove/-clear, mutation detection, `Reset`, non-generic path), and a 6,000-step randomized differential reconciling every mutating / query / clear operation against a `HashSet<int>` oracle over a bounded non-negative universe.
- Cross-collection set-algebra rows for `SparseSet` in `SetAlgebraTests` — `ISet<int>` conformance, the basic algebra within the universe, and the bounded-universe caveat that a mutating op which must add an out-of-universe value throws `ArgumentOutOfRangeException`. (`SparseSet` carries its own `SparseSetDifferentialTests` rather than joining the shared `SetAlgebraDifferentialTests`, whose universe spans negatives it cannot store — exactly as `EnumSet` does.)
- `SparseSetBenchmark` in `Celerity.Benchmarks`, registered in `Program.cs`'s `CoreBenchmarks` array (so it joins the per-PR core run and the gh-pages dashboard, mirroring `IntSetBenchmark`) — `SparseSet` vs `HashSet<int>` across `Add` / `Contains` / **`ClearRefill`** (the O(1)-clear headline win) / `Remove` at `[Params(1000, 100_000)]` over a universe 4× the item count.
- Dashboard wiring for `SparseSet`: the "What ships in the box" ship card in [`web/index.html`](web/index.html) and the `COLLECTIONS` arrays in [`web/dev/bench/index.html`](web/dev/bench/index.html) (key / title / vs / ops incl. `ClearRefill`) and [`web/dev/bench/detail.html`](web/dev/bench/detail.html) (key / title / vs).
- A `SparseSet` differential target in the `Celerity.Fuzz` harness (`SparseSetCase`) — reconciling `TryAdd` / `Remove` / `Clear` churn and enumeration against a `HashSet<int>` oracle over the type's bounded non-negative universe (it draws from `[0, 32)` rather than the shared `[-8, 24]` key domain it cannot store).
- Documentation for `SparseSet`: a full API section in [`docs/api/collections.md`](docs/api/collections.md#sparseset) (the Briggs–Torczon mechanism, the O(1)-clear and dense-iteration wins, the `O(Universe)`-memory / non-negative-only tradeoffs, constructors, the method table, the set-algebra caveat, and a runnable BFS-visited-set example), plus README entries — the Sets list, the `ISet<T>` note, a `SparseSet` paragraph with a runnable example, and a new "cleared-and-rebuilt bounded-int set" row in the "Choosing a collection" decision table.

Comment thread src/Celerity/Collections/SparseSet.cs Outdated
Comment thread docs/api/collections.md Outdated
@github-actions

github-actions Bot commented Jul 21, 2026

Copy link
Copy Markdown

Benchmarks

26 regressions ⚠️ vs main, 48 improvements ✅ (rows past ±10% beyond noise).

Highlights

Benchmark This PR StdDev main Δ
FrozenCeleritySetBenchmark.FrozenCeleritySet_Build(ItemCount: 1000) 3.06 ms 135.60 μs 2.48 ms +23.2% ⚠️
FrozenCeleritySetBenchmark.FrozenCeleritySet_Contains(ItemCount: 1000) 89.17 μs 979.4 ns 78.83 μs +13.1% ⚠️
FrozenCeleritySetBenchmark.FrozenCeleritySet_Contains(ItemCount: 100000) 7.43 ms 47.84 μs 8.40 ms -11.6% ✅
EnumMapBenchmark.EnumMap_Add 110.5 ns 0.8 ns 159.2 ns -30.6% ✅
IntSetBenchmark.IntSet_Contains(ItemCount: 100000) 497.62 μs 9.29 μs 578.19 μs -13.9% ✅
IndexedPriorityQueueBenchmark.PriorityQueue_DecreaseKey(ItemCount: 1000) 77.50 μs 337.1 ns 147.16 μs -47.3% ✅
IndexedPriorityQueueBenchmark.IndexedPriorityQueue_DecreaseKey(ItemCount: 1000) 178.88 μs 843.3 ns 252.05 μs -29.0% ✅
EnumMapBenchmark.Dictionary_Enumerate 43.1 ns 0.0 ns 50.5 ns -14.5% ✅
LruCacheBenchmark.Dictionary_Get(ItemCount: 1000) 24.36 μs 643.2 ns 30.62 μs -20.4% ✅
LruCacheBenchmark.LruCache_GetMissing(ItemCount: 100000) 1.56 ms 2.53 μs 1.37 ms +13.3% ⚠️
CelerityMultiMapBenchmark.Dictionary_Insert(ItemCount: 1000) 27.19 μs 112.0 ns 31.41 μs -13.4% ✅
EnumMapBenchmark.Dictionary_Lookup 135.7 ns 0.1 ns 118.7 ns +14.3% ⚠️
EnumMapBenchmark.EnumMap_Lookup 69.9 ns 0.2 ns 63.2 ns +10.6% ⚠️
LruCacheBenchmark.Dictionary_Put(ItemCount: 1000) 88.04 μs 2.51 μs 108.81 μs -19.1% ✅
LruCacheBenchmark.LruCache_Put(ItemCount: 1000) 492.65 μs 19.53 μs 550.09 μs -10.4% ✅
LruCacheBenchmark.Dictionary_Put(ItemCount: 100000) 7.65 ms 33.19 μs 8.52 ms -10.3% ✅
LruCacheBenchmark.LruCache_Put(ItemCount: 100000) 6.45 ms 67.76 μs 5.78 ms +11.6% ⚠️
CelerityMultiMapBenchmark.Dictionary_Remove(ItemCount: 100000) 2.15 ms 211.29 μs 3.39 ms -36.6% ✅
CelerityMultiMapBenchmark.CelerityMultiMap_Remove(ItemCount: 100000) 2.23 ms 236.91 μs 2.77 ms -19.5% ✅
CuckooFilterBenchmark.CuckooFilter_Add(ItemCount: 100000) 2.11 ms 15.21 μs 2.32 ms -9.2% ✅
CuckooFilterBenchmark.CuckooFilter_Contains(ItemCount: 1000) 4.92 μs 7.5 ns 5.56 μs -11.5% ✅
CuckooFilterBenchmark.CuckooFilter_Contains(ItemCount: 100000) 1.75 ms 3.13 μs 1.97 ms -11.5% ✅
CuckooFilterBenchmark.CuckooFilter_ContainsMissing(ItemCount: 1000) 8.37 μs 4.8 ns 9.62 μs -13.0% ✅
CuckooFilterBenchmark.CuckooFilter_Remove(ItemCount: 1000) 12.95 μs 28.6 ns 14.33 μs -9.6% ✅
CuckooFilterBenchmark.CuckooFilter_Remove(ItemCount: 100000) 4.00 ms 11.09 μs 4.51 ms -11.4% ✅
PooledCeleritySetBenchmark.PooledCeleritySet_Add(ItemCount: 100000) 2.87 ms 4.20 μs 3.16 ms -9.2% ✅
XorFilterBenchmark.HashSet_Build(ItemCount: 1000) 7.76 μs 26.9 ns 8.69 μs -10.7% ✅
XorFilterBenchmark.XorFilter_Build(ItemCount: 1000) 38.11 μs 573.5 ns 44.16 μs -13.7% ✅
EnumSetBenchmark.EnumSet_Contains 45.9 ns 0.1 ns 51.5 ns -10.8% ✅
XorFilterBenchmark.XorFilter_Contains(ItemCount: 1000) 6.77 μs 3.0 ns 7.55 μs -10.4% ✅
PooledCeleritySetBenchmark.PooledCeleritySet_Contains(ItemCount: 100000) 569.24 μs 999.4 ns 485.52 μs +17.2% ⚠️
XorFilterBenchmark.XorFilter_Contains(ItemCount: 100000) 703.71 μs 733.7 ns 801.09 μs -12.2% ✅
XorFilterBenchmark.XorFilter_ContainsMissing(ItemCount: 1000) 6.79 μs 3.5 ns 7.54 μs -9.9% ✅
XorFilterBenchmark.XorFilter_ContainsMissing(ItemCount: 100000) 705.12 μs 520.9 ns 804.65 μs -12.4% ✅
LongDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 14.32 μs 133.6 ns 16.28 μs -12.0% ✅
LongDictionaryBenchmark.LongDictionary_Insert(ItemCount: 1000) 11.03 μs 150.4 ns 9.31 μs +18.6% ⚠️
LongDictionaryBenchmark.LongDictionary_Insert(ItemCount: 100000) 6.77 ms 115.91 μs 7.83 ms -13.6% ✅
FrozenCelerityDictionaryBenchmark.FrozenCelerityDictionary_Lookup(ItemCount: 1000) 89.28 μs 3.71 μs 80.80 μs +10.5% ⚠️
FrozenCelerityDictionaryBenchmark.FrozenCelerityDictionary_Lookup(ItemCount: 100000) 7.36 ms 60.46 μs 8.74 ms -15.9% ✅
EnumSetBenchmark.HashSet_Remove 2.92 μs 85.9 ns 2.40 μs +21.9% ⚠️
LongDictionaryBenchmark.LongDictionary_Remove(ItemCount: 100000) 6.89 ms 102.60 μs 2.10 ms +228.9% ⚠️
PooledCeleritySetBenchmark.PooledCeleritySet_Remove(ItemCount: 100000) 1.28 ms 63.72 μs 1.41 ms -9.3% ✅
LongSetBenchmark.HashSet_Add(ItemCount: 100000) 4.59 ms 178.99 μs 5.14 ms -10.7% ✅
LongSetBenchmark.LongSet_Contains(ItemCount: 100000) 642.89 μs 2.11 μs 573.72 μs +12.1% ⚠️
CelerityMultiSetBenchmark.CelerityMultiSet_Count(ItemCount: 1000) 5.97 μs 402.5 ns 5.35 μs +11.7% ⚠️
DequeBenchmark.LinkedList_Enumerate(ItemCount: 1000) 1.37 μs 0.8 ns 1.66 μs -17.4% ✅
DequeBenchmark.Deque_Enumerate(ItemCount: 1000) 941.9 ns 1.3 ns 1.06 μs -11.5% ✅
DequeBenchmark.LinkedList_Enumerate(ItemCount: 100000) 134.98 μs 106.8 ns 152.57 μs -11.5% ✅
DequeBenchmark.Deque_Enumerate(ItemCount: 100000) 93.76 μs 79.7 ns 105.76 μs -11.3% ✅
HashCachingDictionaryBenchmark.HashCachingDictionary_Insert(ItemCount: 1000) 12.07 μs 195.3 ns 10.13 μs +19.1% ⚠️
CelerityMultiSetBenchmark.CelerityMultiSet_Lookup(ItemCount: 1000) 1.61 μs 7.6 ns 1.90 μs -15.4% ✅
HashCachingDictionaryBenchmark.HashCachingDictionary_Lookup(ItemCount: 1000) 2.73 μs 13.9 ns 3.07 μs -11.0% ✅
CelerityMultiSetBenchmark.Dictionary_Lookup(ItemCount: 100000) 640.20 μs 5.40 μs 550.78 μs +16.2% ⚠️
CelerityMultiSetBenchmark.CelerityMultiSet_Lookup(ItemCount: 100000) 191.36 μs 1.05 μs 211.31 μs -9.4% ✅
DequeBenchmark.Deque_PushFront(ItemCount: 1000) 18.39 μs 832.6 ns 24.01 μs -23.4% ✅
DequeBenchmark.LinkedList_Queue(ItemCount: 100000) 4.33 ms 46.42 μs 4.81 ms -9.9% ✅
HashCachingSetBenchmark.HashSet_Remove(ItemCount: 1000) 26.55 μs 1.42 μs 32.42 μs -18.1% ✅
SmallSetBenchmark.SmallSet_Add(ItemCount: 8) 64.0 ns 4.8 ns 44.8 ns +42.9% ⚠️
SmallSetBenchmark.HashSet_Add(ItemCount: 64) 833.4 ns 11.4 ns 725.2 ns +14.9% ⚠️
CountMinSketchBenchmark.CountMinSketch_Add(ItemCount: 1000) 13.09 μs 292.2 ns 10.83 μs +20.8% ⚠️
CountMinSketchBenchmark.CountMinSketch_Add(ItemCount: 100000) 1.16 ms 13.59 μs 930.27 μs +24.3% ⚠️
DisjointSetBenchmark.Dictionary_Connected(ItemCount: 100000) 155.55 μs 1.19 μs 254.50 μs -38.9% ✅
DisjointSetBenchmark.DisjointSet_Connected(ItemCount: 100000) 268.50 μs 16.17 μs 335.75 μs -20.0% ✅
SmallSetBenchmark.SmallSet_Contains(ItemCount: 64) 925.0 ns 13.2 ns 1.09 μs -15.3% ✅
CountMinSketchBenchmark.CountMinSketch_Estimate(ItemCount: 1000) 8.20 μs 300.6 ns 10.08 μs -18.7% ✅
CountMinSketchBenchmark.CountMinSketch_Estimate(ItemCount: 100000) 2.34 ms 1.30 μs 2.01 ms +16.4% ⚠️
SmallDictionaryBenchmark.Dictionary_Insert(ItemCount: 8) 180.7 ns 0.7 ns 158.3 ns +14.1% ⚠️
SmallDictionaryBenchmark.Dictionary_Insert(ItemCount: 64) 876.8 ns 12.9 ns 762.6 ns +15.0% ⚠️
PooledCelerityDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 15.17 μs 451.4 ns 12.99 μs +16.8% ⚠️
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Insert(ItemCount: 100000) 9.20 ms 257.44 μs 8.17 ms +12.7% ⚠️
SmallDictionaryBenchmark.SmallDictionary_Lookup(ItemCount: 8) 23.3 ns 0.5 ns 30.8 ns -24.3% ✅
SmallDictionaryBenchmark.SmallDictionary_Lookup(ItemCount: 64) 959.2 ns 17.5 ns 1.11 μs -13.3% ✅
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Remove(ItemCount: 100000) 1.91 ms 89.99 μs 1.58 ms +20.9% ⚠️
DisjointSetBenchmark.Dictionary_Union(ItemCount: 100000) 52.90 ms 1.25 ms 46.93 ms +12.7% ⚠️
Collections (412)
Benchmark This PR StdDev main Δ
FrozenCeleritySetBenchmark.FrozenSet_Build(ItemCount: 1000) 166.99 μs 678.9 ns 176.73 μs -5.5%
FrozenCeleritySetBenchmark.FrozenCeleritySet_Build(ItemCount: 1000) 3.06 ms 135.60 μs 2.48 ms +23.2% ⚠️
FrozenCeleritySetBenchmark.FrozenSet_Build(ItemCount: 100000) 29.90 ms 688.99 μs 29.99 ms -0.3%
FrozenCeleritySetBenchmark.FrozenCeleritySet_Build(ItemCount: 100000) 1.59 s 73.59 ms 1.64 s -2.7%
FrozenCeleritySetBenchmark.FrozenSet_Contains(ItemCount: 1000) 6.88 μs 12.0 ns 7.18 μs -4.1%
FrozenCeleritySetBenchmark.FrozenCeleritySet_Contains(ItemCount: 1000) 89.17 μs 979.4 ns 78.83 μs +13.1% ⚠️
FrozenCeleritySetBenchmark.FrozenSet_Contains(ItemCount: 100000) 1.95 ms 11.34 μs 1.86 ms +5.0%
FrozenCeleritySetBenchmark.FrozenCeleritySet_Contains(ItemCount: 100000) 7.43 ms 47.84 μs 8.40 ms -11.6% ✅
EnumMapBenchmark.Dictionary_Add 613.0 ns 3.5 ns 672.0 ns -8.8%
EnumMapBenchmark.EnumMap_Add 110.5 ns 0.8 ns 159.2 ns -30.6% ✅
IntSetBenchmark.HashSet_Add(ItemCount: 1000) 12.76 μs 158.2 ns 13.50 μs -5.4%
IntSetBenchmark.IntSet_Add(ItemCount: 1000) 9.50 μs 107.4 ns 8.92 μs +6.4%
IntSetBenchmark.HashSet_Add(ItemCount: 100000) 5.29 ms 144.75 μs 5.05 ms +4.8%
IntSetBenchmark.IntSet_Add(ItemCount: 100000) 3.52 ms 17.26 μs 3.24 ms +8.3%
IntSetBenchmark.HashSet_Contains(ItemCount: 1000) 4.71 μs 7.2 ns 4.75 μs -0.8%
IntSetBenchmark.IntSet_Contains(ItemCount: 1000) 1.92 μs 20.7 ns 1.81 μs +6.1%
IntSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.50 ms 6.59 μs 1.57 ms -4.2%
IntSetBenchmark.IntSet_Contains(ItemCount: 100000) 497.62 μs 9.29 μs 578.19 μs -13.9% ✅
IndexedPriorityQueueBenchmark.PriorityQueue_DecreaseKey(ItemCount: 1000) 77.50 μs 337.1 ns 147.16 μs -47.3% ✅
IndexedPriorityQueueBenchmark.IndexedPriorityQueue_DecreaseKey(ItemCount: 1000) 178.88 μs 843.3 ns 252.05 μs -29.0% ✅
IndexedPriorityQueueBenchmark.PriorityQueue_DecreaseKey(ItemCount: 100000) 35.83 ms 846.43 μs 33.06 ms +8.4%
IndexedPriorityQueueBenchmark.IndexedPriorityQueue_DecreaseKey(ItemCount: 100000) 54.19 ms 160.45 μs 54.39 ms -0.4%
IndexedPriorityQueueBenchmark.PriorityQueue_Enqueue(ItemCount: 1000) 4.94 μs 82.7 ns 4.92 μs +0.3%
IndexedPriorityQueueBenchmark.IndexedPriorityQueue_Enqueue(ItemCount: 1000) 28.45 μs 238.4 ns 30.03 μs -5.3%
IndexedPriorityQueueBenchmark.PriorityQueue_Enqueue(ItemCount: 100000) 1.16 ms 19.73 μs 1.09 ms +6.7%
IndexedPriorityQueueBenchmark.IndexedPriorityQueue_Enqueue(ItemCount: 100000) 6.20 ms 252.68 μs 6.09 ms +1.8%
EnumMapBenchmark.Dictionary_Enumerate 43.1 ns 0.0 ns 50.5 ns -14.5% ✅
EnumMapBenchmark.EnumMap_Enumerate 37.9 ns 0.2 ns 39.8 ns -4.8%
LruCacheBenchmark.Dictionary_Get(ItemCount: 1000) 24.36 μs 643.2 ns 30.62 μs -20.4% ✅
LruCacheBenchmark.LruCache_Get(ItemCount: 1000) 7.39 μs 105.1 ns 7.32 μs +0.9%
LruCacheBenchmark.Dictionary_Get(ItemCount: 100000) 27.51 μs 2.18 μs 26.78 μs +2.7%
LruCacheBenchmark.LruCache_Get(ItemCount: 100000) 7.60 μs 85.7 ns 7.02 μs +8.1%
LruCacheBenchmark.Dictionary_GetMissing(ItemCount: 1000) 4.58 μs 3.8 ns 4.84 μs -5.3%
LruCacheBenchmark.LruCache_GetMissing(ItemCount: 1000) 3.61 μs 3.9 ns 3.50 μs +3.4%
LruCacheBenchmark.Dictionary_GetMissing(ItemCount: 100000) 538.08 μs 5.45 μs 522.39 μs +3.0%
LruCacheBenchmark.LruCache_GetMissing(ItemCount: 100000) 1.56 ms 2.53 μs 1.37 ms +13.3% ⚠️
CelerityMultiMapBenchmark.Dictionary_Insert(ItemCount: 1000) 27.19 μs 112.0 ns 31.41 μs -13.4% ✅
SwissDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 13.64 μs 390.6 ns 14.33 μs -4.8%
CelerityMultiMapBenchmark.CelerityMultiMap_Insert(ItemCount: 1000) 38.31 μs 647.0 ns 40.52 μs -5.5%
SwissDictionaryBenchmark.SwissDictionary_Insert(ItemCount: 1000) 29.78 μs 240.6 ns 30.43 μs -2.1%
CelerityMultiMapBenchmark.Dictionary_Insert(ItemCount: 100000) 13.84 ms 785.77 μs 13.18 ms +5.0%
SwissDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 5.02 ms 144.74 μs 5.07 ms -0.9%
CelerityMultiMapBenchmark.CelerityMultiMap_Insert(ItemCount: 100000) 17.90 ms 146.25 μs 17.77 ms +0.7%
SwissDictionaryBenchmark.SwissDictionary_Insert(ItemCount: 100000) 3.87 ms 26.50 μs 3.90 ms -0.7%
EnumMapBenchmark.Dictionary_Lookup 135.7 ns 0.1 ns 118.7 ns +14.3% ⚠️
EnumMapBenchmark.EnumMap_Lookup 69.9 ns 0.2 ns 63.2 ns +10.6% ⚠️
CelerityMultiMapBenchmark.Dictionary_Lookup(ItemCount: 1000) 5.14 μs 53.6 ns 4.99 μs +3.2%
SwissDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.84 μs 5.9 ns 4.86 μs -0.3%
CelerityMultiMapBenchmark.CelerityMultiMap_Lookup(ItemCount: 1000) 2.45 μs 2.6 ns 2.25 μs +9.1%
SwissDictionaryBenchmark.SwissDictionary_Lookup(ItemCount: 1000) 2.93 μs 20.2 ns 2.92 μs +0.3%
CelerityMultiMapBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.74 ms 54.89 μs 1.77 ms -1.8%
SwissDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.66 ms 59.09 μs 1.59 ms +4.0%
CelerityMultiMapBenchmark.CelerityMultiMap_Lookup(ItemCount: 100000) 704.39 μs 12.92 μs 736.96 μs -4.4%
SwissDictionaryBenchmark.SwissDictionary_Lookup(ItemCount: 100000) 671.48 μs 3.59 μs 673.14 μs -0.2%
LruCacheBenchmark.Dictionary_Put(ItemCount: 1000) 88.04 μs 2.51 μs 108.81 μs -19.1% ✅
LruCacheBenchmark.LruCache_Put(ItemCount: 1000) 492.65 μs 19.53 μs 550.09 μs -10.4% ✅
LruCacheBenchmark.Dictionary_Put(ItemCount: 100000) 7.65 ms 33.19 μs 8.52 ms -10.3% ✅
LruCacheBenchmark.LruCache_Put(ItemCount: 100000) 6.45 ms 67.76 μs 5.78 ms +11.6% ⚠️
EnumMapBenchmark.Dictionary_Remove 3.05 μs 582.8 ns 3.40 μs -10.4%
EnumMapBenchmark.EnumMap_Remove 1.68 μs 304.7 ns 1.84 μs -8.8%
CelerityMultiMapBenchmark.Dictionary_Remove(ItemCount: 1000) 33.09 μs 2.72 μs 35.28 μs -6.2%
IntSetBenchmark.HashSet_Remove(ItemCount: 1000) 32.70 μs 3.00 μs 28.35 μs +15.4%
SwissDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 77.89 μs 6.27 μs 79.61 μs -2.2%
CelerityMultiMapBenchmark.CelerityMultiMap_Remove(ItemCount: 1000) 152.04 μs 8.92 μs 154.03 μs -1.3%
IntSetBenchmark.IntSet_Remove(ItemCount: 1000) 83.44 μs 9.05 μs 89.15 μs -6.4%
SwissDictionaryBenchmark.SwissDictionary_Remove(ItemCount: 1000) 71.23 μs 4.69 μs 70.89 μs +0.5%
CelerityMultiMapBenchmark.Dictionary_Remove(ItemCount: 100000) 2.15 ms 211.29 μs 3.39 ms -36.6% ✅
IntSetBenchmark.HashSet_Remove(ItemCount: 100000) 1.67 ms 20.88 μs 1.72 ms -2.6%
SwissDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.00 ms 19.84 μs 2.00 ms -0.1%
CelerityMultiMapBenchmark.CelerityMultiMap_Remove(ItemCount: 100000) 2.23 ms 236.91 μs 2.77 ms -19.5% ✅
IntSetBenchmark.IntSet_Remove(ItemCount: 100000) 1.45 ms 18.79 μs 1.35 ms +7.0%
SwissDictionaryBenchmark.SwissDictionary_Remove(ItemCount: 100000) 1.31 ms 53.04 μs 1.39 ms -6.1%
TrieBenchmark.Dictionary_Add(ItemCount: 1000) 36.84 μs 5.82 μs 37.56 μs -1.9%
TrieBenchmark.Trie_Add(ItemCount: 1000) 461.14 μs 164.20 μs 535.04 μs -13.8%
BloomFilterBenchmark.HashSet_Add(ItemCount: 1000) 13.45 μs 263.1 ns 13.20 μs +1.9%
CeleritySetBenchmark.HashSet_Add(ItemCount: 1000) 13.88 μs 273.6 ns 13.41 μs +3.5%
CuckooFilterBenchmark.HashSet_Add(ItemCount: 1000) 13.73 μs 266.7 ns 13.54 μs +1.4%
SwissSetBenchmark.HashSet_Add(ItemCount: 1000) 13.82 μs 236.8 ns 13.55 μs +2.0%
TopKSketchBenchmark.Dictionary_Add(ItemCount: 1000) 13.89 μs 104.0 ns 13.11 μs +5.9%
BloomFilterBenchmark.BloomFilter_Add(ItemCount: 1000) 14.62 μs 122.1 ns 14.37 μs +1.8%
CeleritySetBenchmark.CeleritySet_Add(ItemCount: 1000) 9.29 μs 128.0 ns 9.23 μs +0.7%
CuckooFilterBenchmark.CuckooFilter_Add(ItemCount: 1000) 7.37 μs 106.0 ns 8.00 μs -7.9%
SwissSetBenchmark.SwissSet_Add(ItemCount: 1000) 27.32 μs 64.7 ns 27.27 μs +0.2%
TopKSketchBenchmark.TopKSketch_Add(ItemCount: 1000) 82.17 μs 463.8 ns 82.77 μs -0.7%
TrieBenchmark.Dictionary_Add(ItemCount: 100000) 5.49 ms 1.83 ms 5.81 ms -5.5%
TrieBenchmark.Trie_Add(ItemCount: 100000) 26.52 ms 549.31 μs 26.09 ms +1.7%
BloomFilterBenchmark.HashSet_Add(ItemCount: 100000) 4.80 ms 178.43 μs 4.73 ms +1.4%
CeleritySetBenchmark.HashSet_Add(ItemCount: 100000) 5.13 ms 121.35 μs 5.11 ms +0.3%
CuckooFilterBenchmark.HashSet_Add(ItemCount: 100000) 4.71 ms 131.35 μs 4.78 ms -1.4%
SwissSetBenchmark.HashSet_Add(ItemCount: 100000) 4.81 ms 90.96 μs 4.85 ms -0.9%
TopKSketchBenchmark.Dictionary_Add(ItemCount: 100000) 3.47 ms 112.31 μs 3.29 ms +5.4%
BloomFilterBenchmark.BloomFilter_Add(ItemCount: 100000) 1.10 ms 3.97 μs 1.10 ms +0.6%
CeleritySetBenchmark.CeleritySet_Add(ItemCount: 100000) 3.28 ms 60.09 μs 3.19 ms +2.8%
CuckooFilterBenchmark.CuckooFilter_Add(ItemCount: 100000) 2.11 ms 15.21 μs 2.32 ms -9.2% ✅
SwissSetBenchmark.SwissSet_Add(ItemCount: 100000) 4.67 ms 31.40 μs 4.63 ms +0.8%
TopKSketchBenchmark.TopKSketch_Add(ItemCount: 100000) 13.82 ms 29.60 μs 13.78 ms +0.3%
BloomFilterBenchmark.HashSet_Contains(ItemCount: 1000) 4.73 μs 5.7 ns 4.74 μs -0.2%
CeleritySetBenchmark.HashSet_Contains(ItemCount: 1000) 4.76 μs 30.2 ns 4.76 μs -0.0%
CuckooFilterBenchmark.HashSet_Contains(ItemCount: 1000) 4.74 μs 29.6 ns 4.73 μs +0.2%
SwissSetBenchmark.HashSet_Contains(ItemCount: 1000) 4.74 μs 18.7 ns 4.73 μs +0.3%
BloomFilterBenchmark.BloomFilter_Contains(ItemCount: 1000) 13.12 μs 8.2 ns 13.10 μs +0.2%
CeleritySetBenchmark.CeleritySet_Contains(ItemCount: 1000) 1.86 μs 9.9 ns 1.85 μs +0.5%
CuckooFilterBenchmark.CuckooFilter_Contains(ItemCount: 1000) 4.92 μs 7.5 ns 5.56 μs -11.5% ✅
SwissSetBenchmark.SwissSet_Contains(ItemCount: 1000) 2.79 μs 11.9 ns 2.78 μs +0.2%
BloomFilterBenchmark.HashSet_Contains(ItemCount: 100000) 1.58 ms 16.07 μs 1.60 ms -1.0%
CeleritySetBenchmark.HashSet_Contains(ItemCount: 100000) 1.57 ms 16.65 μs 1.62 ms -3.0%
CuckooFilterBenchmark.HashSet_Contains(ItemCount: 100000) 1.57 ms 5.08 μs 1.50 ms +4.3%
SwissSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.56 ms 5.50 μs 1.57 ms -0.6%
BloomFilterBenchmark.BloomFilter_Contains(ItemCount: 100000) 870.67 μs 1.02 μs 868.62 μs +0.2%
CeleritySetBenchmark.CeleritySet_Contains(ItemCount: 100000) 588.64 μs 2.12 μs 585.45 μs +0.5%
CuckooFilterBenchmark.CuckooFilter_Contains(ItemCount: 100000) 1.75 ms 3.13 μs 1.97 ms -11.5% ✅
SwissSetBenchmark.SwissSet_Contains(ItemCount: 100000) 640.81 μs 7.07 μs 654.09 μs -2.0%
BloomFilterBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 4.54 μs 8.2 ns 4.54 μs +0.1%
CuckooFilterBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 4.54 μs 4.6 ns 4.56 μs -0.5%
SwissSetBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 4.57 μs 20.3 ns 4.54 μs +0.7%
BloomFilterBenchmark.BloomFilter_ContainsMissing(ItemCount: 1000) 3.53 μs 12.8 ns 3.53 μs +0.1%
CuckooFilterBenchmark.CuckooFilter_ContainsMissing(ItemCount: 1000) 8.37 μs 4.8 ns 9.62 μs -13.0% ✅
SwissSetBenchmark.SwissSet_ContainsMissing(ItemCount: 1000) 2.37 μs 4.3 ns 2.37 μs -0.0%
BloomFilterBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 1.93 ms 31.91 μs 1.93 ms -0.1%
CuckooFilterBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 1.99 ms 40.14 μs 1.99 ms -0.3%
SwissSetBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 1.96 ms 6.85 μs 1.99 ms -1.5%
BloomFilterBenchmark.BloomFilter_ContainsMissing(ItemCount: 100000) 1.49 ms 642.3 ns 1.49 ms +0.1%
CuckooFilterBenchmark.CuckooFilter_ContainsMissing(ItemCount: 100000) 937.09 μs 10.81 μs 984.22 μs -4.8%
SwissSetBenchmark.SwissSet_ContainsMissing(ItemCount: 100000) 355.16 μs 9.24 μs 351.52 μs +1.0%
IntDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 15.64 μs 1.02 μs 14.36 μs +8.9%
IntDictionaryBenchmark.IntDictionary_Insert(ItemCount: 1000) 12.11 μs 119.2 ns 11.70 μs +3.6%
IntDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 4.28 ms 79.49 μs 4.25 ms +0.6%
IntDictionaryBenchmark.IntDictionary_Insert(ItemCount: 100000) 4.98 ms 68.42 μs 4.93 ms +1.1%
IntDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.74 μs 17.1 ns 4.73 μs +0.2%
TrieBenchmark.Dictionary_Lookup(ItemCount: 1000) 13.39 μs 476.6 ns 13.26 μs +0.9%
IntDictionaryBenchmark.IntDictionary_Lookup(ItemCount: 1000) 2.14 μs 8.0 ns 2.14 μs +0.2%
TrieBenchmark.Trie_Lookup(ItemCount: 1000) 40.57 μs 366.7 ns 40.04 μs +1.3%
IntDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.63 ms 8.25 μs 1.60 ms +2.1%
TrieBenchmark.Dictionary_Lookup(ItemCount: 100000) 2.73 ms 29.17 μs 2.56 ms +6.7%
IntDictionaryBenchmark.IntDictionary_Lookup(ItemCount: 100000) 682.60 μs 3.68 μs 698.85 μs -2.3%
TrieBenchmark.Trie_Lookup(ItemCount: 100000) 9.08 ms 136.12 μs 9.09 ms -0.1%
TrieBenchmark.Dictionary_PrefixMatch(ItemCount: 1000) 73.58 μs 78.8 ns 73.79 μs -0.3%
TrieBenchmark.Trie_PrefixMatch(ItemCount: 1000) 54.83 μs 217.0 ns 55.37 μs -1.0%
TrieBenchmark.Dictionary_PrefixMatch(ItemCount: 100000) 7.45 ms 48.12 μs 7.39 ms +0.8%
TrieBenchmark.Trie_PrefixMatch(ItemCount: 100000) 9.34 ms 347.87 μs 9.08 ms +2.8%
CeleritySetBenchmark.HashSet_Remove(ItemCount: 1000) 31.94 μs 3.17 μs 27.62 μs +15.6%
IntDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 87.39 μs 11.67 μs 88.20 μs -0.9%
CeleritySetBenchmark.CeleritySet_Remove(ItemCount: 1000) 139.97 μs 8.05 μs 140.88 μs -0.6%
IntDictionaryBenchmark.IntDictionary_Remove(ItemCount: 1000) 97.23 μs 8.51 μs 93.71 μs +3.8%
SwissSetBenchmark.HashSet_Remove(ItemCount: 1000) 30.26 μs 4.62 μs 25.99 μs +16.4%
SwissSetBenchmark.SwissSet_Remove(ItemCount: 1000) 71.08 μs 6.07 μs 73.54 μs -3.3%
CuckooFilterBenchmark.HashSet_Remove(ItemCount: 1000) 13.49 μs 66.0 ns 14.01 μs -3.7%
CuckooFilterBenchmark.CuckooFilter_Remove(ItemCount: 1000) 12.95 μs 28.6 ns 14.33 μs -9.6% ✅
CeleritySetBenchmark.HashSet_Remove(ItemCount: 100000) 1.72 ms 17.11 μs 1.71 ms +0.6%
IntDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.20 ms 56.13 μs 2.04 ms +7.7%
CeleritySetBenchmark.CeleritySet_Remove(ItemCount: 100000) 1.33 ms 62.42 μs 1.31 ms +1.4%
IntDictionaryBenchmark.IntDictionary_Remove(ItemCount: 100000) 1.74 ms 135.38 μs 2.93 ms -40.5%
SwissSetBenchmark.HashSet_Remove(ItemCount: 100000) 1.75 ms 30.06 μs 1.71 ms +2.3%
SwissSetBenchmark.SwissSet_Remove(ItemCount: 100000) 1.30 ms 220.61 μs 1.07 ms +22.1%
CuckooFilterBenchmark.HashSet_Remove(ItemCount: 100000) 3.91 ms 72.34 μs 3.82 ms +2.3%
CuckooFilterBenchmark.CuckooFilter_Remove(ItemCount: 100000) 4.00 ms 11.09 μs 4.51 ms -11.4% ✅
TopKSketchBenchmark.Dictionary_TopK(ItemCount: 1000) 32.9 ns 0.4 ns 30.2 ns +8.8%
TopKSketchBenchmark.TopKSketch_TopK(ItemCount: 1000) 1.30 μs 9.3 ns 1.23 μs +5.7%
TopKSketchBenchmark.Dictionary_TopK(ItemCount: 100000) 34.1 ns 1.5 ns 31.2 ns +9.3%
TopKSketchBenchmark.TopKSketch_TopK(ItemCount: 100000) 1.24 μs 24.8 ns 1.23 μs +0.7%
EnumSetBenchmark.HashSet_Add 555.3 ns 1.2 ns 595.2 ns -6.7%
EnumSetBenchmark.EnumSet_Add 84.4 ns 1.0 ns 83.1 ns +1.6%
PooledCeleritySetBenchmark.HashSet_Add(ItemCount: 1000) 12.45 μs 214.0 ns 13.54 μs -8.1%
RobinHoodSetBenchmark.HashSet_Add(ItemCount: 1000) 12.57 μs 117.0 ns 11.88 μs +5.9%
PooledCeleritySetBenchmark.PooledCeleritySet_Add(ItemCount: 1000) 8.73 μs 13.1 ns 9.58 μs -8.9%
RobinHoodSetBenchmark.RobinHoodSet_Add(ItemCount: 1000) 17.27 μs 350.6 ns 16.78 μs +2.9%
PooledCeleritySetBenchmark.HashSet_Add(ItemCount: 100000) 4.77 ms 138.83 μs 5.08 ms -6.1%
RobinHoodSetBenchmark.HashSet_Add(ItemCount: 100000) 4.48 ms 477.19 μs 4.54 ms -1.3%
PooledCeleritySetBenchmark.PooledCeleritySet_Add(ItemCount: 100000) 2.87 ms 4.20 μs 3.16 ms -9.2% ✅
RobinHoodSetBenchmark.RobinHoodSet_Add(ItemCount: 100000) 6.42 ms 55.51 μs 6.15 ms +4.4%
BitSetBenchmark.BitArray_And(ItemCount: 1024) 54.8 ns 0.3 ns 56.0 ns -2.1%
BitSetBenchmark.BitSet_And(ItemCount: 1024) 1.24 μs 3.7 ns 1.25 μs -0.7%
BitSetBenchmark.BitArray_And(ItemCount: 1000000) 43.60 μs 398.9 ns 44.45 μs -1.9%
BitSetBenchmark.BitSet_And(ItemCount: 1000000) 4.47 ms 3.00 μs 4.48 ms -0.2%
FrozenCelerityDictionaryBenchmark.FrozenDictionary_Build(ItemCount: 1000) 159.91 μs 644.5 ns 168.87 μs -5.3%
XorFilterBenchmark.HashSet_Build(ItemCount: 1000) 7.76 μs 26.9 ns 8.69 μs -10.7% ✅
FrozenCelerityDictionaryBenchmark.FrozenCelerityDictionary_Build(ItemCount: 1000) 3.63 ms 166.66 μs 3.95 ms -8.1%
XorFilterBenchmark.XorFilter_Build(ItemCount: 1000) 38.11 μs 573.5 ns 44.16 μs -13.7% ✅
FrozenCelerityDictionaryBenchmark.FrozenDictionary_Build(ItemCount: 100000) 28.64 ms 467.49 μs 30.70 ms -6.7%
XorFilterBenchmark.HashSet_Build(ItemCount: 100000) 2.06 ms 28.02 μs 2.13 ms -3.3%
FrozenCelerityDictionaryBenchmark.FrozenCelerityDictionary_Build(ItemCount: 100000) 1.90 s 157.45 ms 1.98 s -4.1%
XorFilterBenchmark.XorFilter_Build(ItemCount: 100000) 12.81 ms 226.63 μs 13.72 ms -6.6%
EnumSetBenchmark.HashSet_Contains 175.1 ns 0.2 ns 170.5 ns +2.7%
EnumSetBenchmark.EnumSet_Contains 45.9 ns 0.1 ns 51.5 ns -10.8% ✅
PooledCeleritySetBenchmark.HashSet_Contains(ItemCount: 1000) 4.74 μs 15.6 ns 4.71 μs +0.8%
RobinHoodSetBenchmark.HashSet_Contains(ItemCount: 1000) 4.72 μs 4.9 ns 4.72 μs +0.0%
XorFilterBenchmark.HashSet_Contains(ItemCount: 1000) 4.72 μs 3.8 ns 4.74 μs -0.3%
PooledCeleritySetBenchmark.PooledCeleritySet_Contains(ItemCount: 1000) 1.92 μs 28.3 ns 2.04 μs -6.0%
RobinHoodSetBenchmark.RobinHoodSet_Contains(ItemCount: 1000) 2.43 μs 13.0 ns 2.42 μs +0.4%
XorFilterBenchmark.XorFilter_Contains(ItemCount: 1000) 6.77 μs 3.0 ns 7.55 μs -10.4% ✅
PooledCeleritySetBenchmark.HashSet_Contains(ItemCount: 100000) 1.56 ms 19.33 μs 1.45 ms +7.6%
RobinHoodSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.54 ms 48.95 μs 1.58 ms -2.3%
XorFilterBenchmark.HashSet_Contains(ItemCount: 100000) 1.53 ms 29.56 μs 1.51 ms +0.8%
PooledCeleritySetBenchmark.PooledCeleritySet_Contains(ItemCount: 100000) 569.24 μs 999.4 ns 485.52 μs +17.2% ⚠️
RobinHoodSetBenchmark.RobinHoodSet_Contains(ItemCount: 100000) 739.69 μs 2.57 μs 734.76 μs +0.7%
XorFilterBenchmark.XorFilter_Contains(ItemCount: 100000) 703.71 μs 733.7 ns 801.09 μs -12.2% ✅
RobinHoodSetBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 4.54 μs 4.7 ns 4.67 μs -2.9%
XorFilterBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 4.55 μs 12.5 ns 4.56 μs -0.3%
RobinHoodSetBenchmark.RobinHoodSet_ContainsMissing(ItemCount: 1000) 2.72 μs 4.8 ns 2.72 μs +0.1%
XorFilterBenchmark.XorFilter_ContainsMissing(ItemCount: 1000) 6.79 μs 3.5 ns 7.54 μs -9.9% ✅
RobinHoodSetBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 1.91 ms 21.81 μs 1.93 ms -1.0%
XorFilterBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 1.93 ms 7.04 μs 1.99 ms -2.7%
RobinHoodSetBenchmark.RobinHoodSet_ContainsMissing(ItemCount: 100000) 1.18 ms 1.02 μs 1.18 ms +0.2%
XorFilterBenchmark.XorFilter_ContainsMissing(ItemCount: 100000) 705.12 μs 520.9 ns 804.65 μs -12.4% ✅
LongDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 14.32 μs 133.6 ns 16.28 μs -12.0% ✅
LongDictionaryBenchmark.LongDictionary_Insert(ItemCount: 1000) 11.03 μs 150.4 ns 9.31 μs +18.6% ⚠️
LongDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 4.97 ms 44.11 μs 5.32 ms -6.7%
LongDictionaryBenchmark.LongDictionary_Insert(ItemCount: 100000) 6.77 ms 115.91 μs 7.83 ms -13.6% ✅
FrozenCelerityDictionaryBenchmark.FrozenDictionary_Lookup(ItemCount: 1000) 7.44 μs 12.3 ns 7.61 μs -2.2%
LongDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.89 μs 21.3 ns 5.04 μs -2.9%
FrozenCelerityDictionaryBenchmark.FrozenCelerityDictionary_Lookup(ItemCount: 1000) 89.28 μs 3.71 μs 80.80 μs +10.5% ⚠️
LongDictionaryBenchmark.LongDictionary_Lookup(ItemCount: 1000) 2.27 μs 5.4 ns 2.29 μs -1.0%
FrozenCelerityDictionaryBenchmark.FrozenDictionary_Lookup(ItemCount: 100000) 1.94 ms 7.81 μs 1.90 ms +2.4%
LongDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.58 ms 1.46 μs 1.58 ms -0.2%
FrozenCelerityDictionaryBenchmark.FrozenCelerityDictionary_Lookup(ItemCount: 100000) 7.36 ms 60.46 μs 8.74 ms -15.9% ✅
LongDictionaryBenchmark.LongDictionary_Lookup(ItemCount: 100000) 694.05 μs 509.7 ns 665.20 μs +4.3%
BitSetBenchmark.BitArray_Or(ItemCount: 1024) 57.6 ns 2.2 ns 58.2 ns -1.1%
BitSetBenchmark.BitSet_Or(ItemCount: 1024) 1.47 μs 362.4 ns 1.25 μs +17.4%
BitSetBenchmark.BitArray_Or(ItemCount: 1000000) 43.71 μs 328.8 ns 44.87 μs -2.6%
BitSetBenchmark.BitSet_Or(ItemCount: 1000000) 4.47 ms 2.37 μs 4.48 ms -0.3%
BitSetBenchmark.BitArray_PopCount(ItemCount: 1024) 1.24 μs 2.5 ns 1.24 μs -0.2%
BitSetBenchmark.BitSet_PopCount(ItemCount: 1024) 7.0 ns 0.0 ns 7.1 ns -0.2%
BitSetBenchmark.BitArray_PopCount(ItemCount: 1000000) 4.82 ms 1.49 μs 4.83 ms -0.1%
BitSetBenchmark.BitSet_PopCount(ItemCount: 1000000) 4.93 μs 3.4 ns 4.94 μs -0.1%
EnumSetBenchmark.HashSet_Remove 2.92 μs 85.9 ns 2.40 μs +21.9% ⚠️
EnumSetBenchmark.EnumSet_Remove 1.38 μs 260.4 ns 1.01 μs +37.0%
LongDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 84.71 μs 7.14 μs 81.94 μs +3.4%
PooledCeleritySetBenchmark.HashSet_Remove(ItemCount: 1000) 25.80 μs 1.26 μs 25.67 μs +0.5%
LongDictionaryBenchmark.LongDictionary_Remove(ItemCount: 1000) 90.21 μs 8.66 μs 85.41 μs +5.6%
PooledCeleritySetBenchmark.PooledCeleritySet_Remove(ItemCount: 1000) 140.08 μs 7.31 μs 147.65 μs -5.1%
RobinHoodSetBenchmark.HashSet_Remove(ItemCount: 1000) 30.47 μs 3.28 μs 26.12 μs +16.6%
RobinHoodSetBenchmark.RobinHoodSet_Remove(ItemCount: 1000) 129.20 μs 1.70 μs 133.43 μs -3.2%
LongDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.00 ms 28.66 μs 2.20 ms -8.9%
PooledCeleritySetBenchmark.HashSet_Remove(ItemCount: 100000) 1.71 ms 14.49 μs 1.67 ms +2.1%
LongDictionaryBenchmark.LongDictionary_Remove(ItemCount: 100000) 6.89 ms 102.60 μs 2.10 ms +228.9% ⚠️
PooledCeleritySetBenchmark.PooledCeleritySet_Remove(ItemCount: 100000) 1.28 ms 63.72 μs 1.41 ms -9.3% ✅
RobinHoodSetBenchmark.HashSet_Remove(ItemCount: 100000) 1.72 ms 20.41 μs 1.70 ms +0.8%
RobinHoodSetBenchmark.RobinHoodSet_Remove(ItemCount: 100000) 1.38 ms 41.42 μs 1.36 ms +1.2%
EnumSetBenchmark.HashSet_Union 403.6 ns 1.9 ns 415.9 ns -2.9%
EnumSetBenchmark.EnumSet_Union 21.3 ns 0.1 ns 23.1 ns -7.7%
BitSetBenchmark.BitArray_Xor(ItemCount: 1024) 54.3 ns 0.2 ns 58.2 ns -6.8%
BitSetBenchmark.BitSet_Xor(ItemCount: 1024) 1.22 μs 30.1 ns 1.25 μs -2.6%
BitSetBenchmark.BitArray_Xor(ItemCount: 1000000) 43.70 μs 353.7 ns 44.78 μs -2.4%
BitSetBenchmark.BitSet_Xor(ItemCount: 1000000) 4.47 ms 3.33 μs 4.48 ms -0.3%
HashCachingSetBenchmark.HashSet_Add(ItemCount: 1000) 13.13 μs 232.7 ns 13.20 μs -0.6%
HyperLogLogBenchmark.HashSet_Add(ItemCount: 1000) 13.24 μs 239.6 ns 12.69 μs +4.3%
LongSetBenchmark.HashSet_Add(ItemCount: 1000) 14.29 μs 267.7 ns 13.38 μs +6.8%
HashCachingSetBenchmark.HashCachingSet_Add(ItemCount: 1000) 11.74 μs 376.4 ns 11.67 μs +0.6%
HyperLogLogBenchmark.HyperLogLog_Add(ItemCount: 1000) 27.49 μs 77.3 ns 27.42 μs +0.3%
LongSetBenchmark.LongSet_Add(ItemCount: 1000) 9.85 μs 97.9 ns 9.40 μs +4.8%
HashCachingSetBenchmark.HashSet_Add(ItemCount: 100000) 4.42 ms 478.29 μs 4.28 ms +3.2%
HyperLogLogBenchmark.HashSet_Add(ItemCount: 100000) 4.86 ms 44.54 μs 4.87 ms -0.0%
LongSetBenchmark.HashSet_Add(ItemCount: 100000) 4.59 ms 178.99 μs 5.14 ms -10.7% ✅
HashCachingSetBenchmark.HashCachingSet_Add(ItemCount: 100000) 5.41 ms 71.49 μs 5.29 ms +2.3%
HyperLogLogBenchmark.HyperLogLog_Add(ItemCount: 100000) 575.68 μs 1.98 μs 575.59 μs +0.0%
LongSetBenchmark.LongSet_Add(ItemCount: 100000) 6.23 ms 74.09 μs 6.71 ms -7.1%
HashCachingSetBenchmark.HashSet_Contains(ItemCount: 1000) 4.73 μs 17.0 ns 4.73 μs +0.0%
LongSetBenchmark.HashSet_Contains(ItemCount: 1000) 4.80 μs 48.9 ns 5.06 μs -5.1%
HashCachingSetBenchmark.HashCachingSet_Contains(ItemCount: 1000) 2.43 μs 6.0 ns 2.42 μs +0.3%
LongSetBenchmark.LongSet_Contains(ItemCount: 1000) 2.01 μs 10.2 ns 2.09 μs -4.1%
HashCachingSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.73 ms 196.39 μs 1.56 ms +10.8%
LongSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.64 ms 14.08 μs 1.61 ms +1.5%
HashCachingSetBenchmark.HashCachingSet_Contains(ItemCount: 100000) 741.49 μs 1.46 μs 746.03 μs -0.6%
LongSetBenchmark.LongSet_Contains(ItemCount: 100000) 642.89 μs 2.11 μs 573.72 μs +12.1% ⚠️
HashCachingSetBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 4.55 μs 10.6 ns 4.64 μs -2.0%
HashCachingSetBenchmark.HashCachingSet_ContainsMissing(ItemCount: 1000) 2.80 μs 2.9 ns 2.80 μs -0.1%
HashCachingSetBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 1.92 ms 14.39 μs 2.00 ms -4.1%
HashCachingSetBenchmark.HashCachingSet_ContainsMissing(ItemCount: 100000) 1.16 ms 2.65 μs 1.16 ms -0.1%
CelerityMultiSetBenchmark.Dictionary_Count(ItemCount: 1000) 10.09 μs 22.7 ns 9.83 μs +2.7%
CelerityMultiSetBenchmark.CelerityMultiSet_Count(ItemCount: 1000) 5.97 μs 402.5 ns 5.35 μs +11.7% ⚠️
CelerityMultiSetBenchmark.Dictionary_Count(ItemCount: 100000) 1.46 ms 9.35 μs 1.35 ms +7.8%
CelerityMultiSetBenchmark.CelerityMultiSet_Count(ItemCount: 100000) 697.51 μs 2.64 μs 651.57 μs +7.1%
DequeBenchmark.LinkedList_Enumerate(ItemCount: 1000) 1.37 μs 0.8 ns 1.66 μs -17.4% ✅
DequeBenchmark.Deque_Enumerate(ItemCount: 1000) 941.9 ns 1.3 ns 1.06 μs -11.5% ✅
DequeBenchmark.LinkedList_Enumerate(ItemCount: 100000) 134.98 μs 106.8 ns 152.57 μs -11.5% ✅
DequeBenchmark.Deque_Enumerate(ItemCount: 100000) 93.76 μs 79.7 ns 105.76 μs -11.3% ✅
HyperLogLogBenchmark.HashSet_Estimate(ItemCount: 1000) 0.0 ns 0.0 ns 0.0 ns -86.7%
HyperLogLogBenchmark.HyperLogLog_Estimate(ItemCount: 1000) 23.45 μs 17.6 ns 23.46 μs -0.0%
HyperLogLogBenchmark.HashSet_Estimate(ItemCount: 100000) 0.0 ns 0.0 ns 0.0 ns -68.8%
HyperLogLogBenchmark.HyperLogLog_Estimate(ItemCount: 100000) 22.99 μs 16.4 ns 22.98 μs +0.0%
CelerityDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 14.30 μs 317.0 ns 13.07 μs +9.4%
HashCachingDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 13.92 μs 244.3 ns 13.16 μs +5.8%
CelerityDictionaryBenchmark.CelerityDictionary_Insert(ItemCount: 1000) 12.23 μs 90.5 ns 11.54 μs +6.0%
HashCachingDictionaryBenchmark.HashCachingDictionary_Insert(ItemCount: 1000) 12.07 μs 195.3 ns 10.13 μs +19.1% ⚠️
CelerityDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 4.23 ms 78.28 μs 4.12 ms +2.5%
HashCachingDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 4.71 ms 74.92 μs 5.07 ms -7.1%
CelerityDictionaryBenchmark.CelerityDictionary_Insert(ItemCount: 100000) 4.83 ms 62.46 μs 4.81 ms +0.3%
HashCachingDictionaryBenchmark.HashCachingDictionary_Insert(ItemCount: 100000) 6.82 ms 225.53 μs 6.94 ms -1.8%
CelerityDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.75 μs 53.6 ns 4.73 μs +0.3%
CelerityMultiSetBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.68 μs 4.5 ns 4.66 μs +0.5%
HashCachingDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.72 μs 47.5 ns 4.71 μs +0.3%
CelerityDictionaryBenchmark.CelerityDictionary_Lookup(ItemCount: 1000) 2.15 μs 6.3 ns 2.15 μs +0.0%
CelerityMultiSetBenchmark.CelerityMultiSet_Lookup(ItemCount: 1000) 1.61 μs 7.6 ns 1.90 μs -15.4% ✅
HashCachingDictionaryBenchmark.HashCachingDictionary_Lookup(ItemCount: 1000) 2.73 μs 13.9 ns 3.07 μs -11.0% ✅
CelerityDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.59 ms 3.84 μs 1.59 ms -0.2%
CelerityMultiSetBenchmark.Dictionary_Lookup(ItemCount: 100000) 640.20 μs 5.40 μs 550.78 μs +16.2% ⚠️
HashCachingDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.57 ms 25.68 μs 1.61 ms -2.5%
CelerityDictionaryBenchmark.CelerityDictionary_Lookup(ItemCount: 100000) 691.10 μs 1.81 μs 688.41 μs +0.4%
CelerityMultiSetBenchmark.CelerityMultiSet_Lookup(ItemCount: 100000) 191.36 μs 1.05 μs 211.31 μs -9.4% ✅
HashCachingDictionaryBenchmark.HashCachingDictionary_Lookup(ItemCount: 100000) 812.04 μs 2.04 μs 856.79 μs -5.2%
DequeBenchmark.LinkedList_PushFront(ItemCount: 1000) 35.28 μs 1.44 μs 39.73 μs -11.2%
DequeBenchmark.Deque_PushFront(ItemCount: 1000) 18.39 μs 832.6 ns 24.01 μs -23.4% ✅
DequeBenchmark.LinkedList_PushFront(ItemCount: 100000) 1.87 ms 29.75 μs 1.80 ms +4.0%
DequeBenchmark.Deque_PushFront(ItemCount: 100000) 669.23 μs 38.77 μs 634.19 μs +5.5%
DequeBenchmark.LinkedList_Queue(ItemCount: 1000) 54.37 μs 1.74 μs 51.74 μs +5.1%
DequeBenchmark.Deque_Queue(ItemCount: 1000) 32.29 μs 1.09 μs 31.36 μs +3.0%
DequeBenchmark.LinkedList_Queue(ItemCount: 100000) 4.33 ms 46.42 μs 4.81 ms -9.9% ✅
DequeBenchmark.Deque_Queue(ItemCount: 100000) 416.04 μs 14.89 μs 449.34 μs -7.4%
CelerityDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 80.38 μs 6.13 μs 83.58 μs -3.8%
CelerityMultiSetBenchmark.Dictionary_Remove(ItemCount: 1000) 59.53 μs 5.36 μs 50.79 μs +17.2%
HashCachingDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 83.91 μs 9.63 μs 79.41 μs +5.7%
LongSetBenchmark.HashSet_Remove(ItemCount: 1000) 75.05 μs 5.42 μs 71.11 μs +5.5%
CelerityDictionaryBenchmark.CelerityDictionary_Remove(ItemCount: 1000) 140.64 μs 8.84 μs 139.65 μs +0.7%
CelerityMultiSetBenchmark.CelerityMultiSet_Remove(ItemCount: 1000) 101.90 μs 5.77 μs 105.92 μs -3.8%
HashCachingDictionaryBenchmark.HashCachingDictionary_Remove(ItemCount: 1000) 112.65 μs 6.58 μs 110.75 μs +1.7%
LongSetBenchmark.LongSet_Remove(ItemCount: 1000) 90.19 μs 4.43 μs 79.74 μs +13.1%
HashCachingSetBenchmark.HashSet_Remove(ItemCount: 1000) 26.55 μs 1.42 μs 32.42 μs -18.1% ✅
HashCachingSetBenchmark.HashCachingSet_Remove(ItemCount: 1000) 115.82 μs 8.89 μs 115.00 μs +0.7%
CelerityDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.05 ms 7.76 μs 2.05 ms -0.3%
CelerityMultiSetBenchmark.Dictionary_Remove(ItemCount: 100000) 549.46 μs 12.18 μs 572.03 μs -3.9%
HashCachingDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.06 ms 31.72 μs 2.02 ms +1.9%
LongSetBenchmark.HashSet_Remove(ItemCount: 100000) 1.96 ms 10.77 μs 1.98 ms -0.8%
CelerityDictionaryBenchmark.CelerityDictionary_Remove(ItemCount: 100000) 1.66 ms 131.25 μs 1.55 ms +7.2%
CelerityMultiSetBenchmark.CelerityMultiSet_Remove(ItemCount: 100000) 1.49 ms 15.14 μs 1.61 ms -7.5%
HashCachingDictionaryBenchmark.HashCachingDictionary_Remove(ItemCount: 100000) 1.93 ms 213.58 μs 2.05 ms -5.9%
LongSetBenchmark.LongSet_Remove(ItemCount: 100000) 1.45 ms 92.30 μs 1.60 ms -9.4%
HashCachingSetBenchmark.HashSet_Remove(ItemCount: 100000) 1.72 ms 19.97 μs 1.72 ms +0.4%
HashCachingSetBenchmark.HashCachingSet_Remove(ItemCount: 100000) 1.56 ms 128.26 μs 1.64 ms -4.6%
SmallSetBenchmark.HashSet_Add(ItemCount: 8) 170.2 ns 3.9 ns 161.7 ns +5.3%
SmallSetBenchmark.SmallSet_Add(ItemCount: 8) 64.0 ns 4.8 ns 44.8 ns +42.9% ⚠️
SmallSetBenchmark.HashSet_Add(ItemCount: 64) 833.4 ns 11.4 ns 725.2 ns +14.9% ⚠️
SmallSetBenchmark.SmallSet_Add(ItemCount: 64) 1.92 μs 323.8 ns 1.65 μs +16.6%
CountMinSketchBenchmark.Dictionary_Add(ItemCount: 1000) 10.42 μs 38.9 ns 10.66 μs -2.2%
SparseSetBenchmark.HashSet_Add(ItemCount: 1000) 7.22 μs 53.6 ns n/a 🆕 new
CountMinSketchBenchmark.CountMinSketch_Add(ItemCount: 1000) 13.09 μs 292.2 ns 10.83 μs +20.8% ⚠️
SparseSetBenchmark.SparseSet_Add(ItemCount: 1000) 7.11 μs 57.6 ns n/a 🆕 new
CountMinSketchBenchmark.Dictionary_Add(ItemCount: 100000) 1.49 ms 4.51 μs 1.47 ms +1.8%
SparseSetBenchmark.HashSet_Add(ItemCount: 100000) 1.73 ms 48.00 μs n/a 🆕 new
CountMinSketchBenchmark.CountMinSketch_Add(ItemCount: 100000) 1.16 ms 13.59 μs 930.27 μs +24.3% ⚠️
SparseSetBenchmark.SparseSet_Add(ItemCount: 100000) 1.52 ms 53.10 μs n/a 🆕 new
SparseSetBenchmark.HashSet_ClearRefill(ItemCount: 1000) 8.29 μs 2.07 μs n/a 🆕 new
SparseSetBenchmark.SparseSet_ClearRefill(ItemCount: 1000) 5.59 μs 26.4 ns n/a 🆕 new
SparseSetBenchmark.HashSet_ClearRefill(ItemCount: 100000) 1.26 ms 4.49 μs n/a 🆕 new
SparseSetBenchmark.SparseSet_ClearRefill(ItemCount: 100000) 651.75 μs 21.61 μs n/a 🆕 new
DisjointSetBenchmark.Dictionary_Components(ItemCount: 1000) 18.11 μs 319.3 ns 18.29 μs -0.9%
DisjointSetBenchmark.DisjointSet_Components(ItemCount: 1000) 16.66 μs 307.5 ns 16.27 μs +2.4%
DisjointSetBenchmark.Dictionary_Components(ItemCount: 100000) 4.56 ms 115.24 μs 4.26 ms +7.0%
DisjointSetBenchmark.DisjointSet_Components(ItemCount: 100000) 3.44 ms 116.10 μs 3.29 ms +4.4%
DisjointSetBenchmark.Dictionary_Connected(ItemCount: 1000) 9.52 μs 9.9 ns 9.41 μs +1.1%
DisjointSetBenchmark.DisjointSet_Connected(ItemCount: 1000) 12.99 μs 16.7 ns 12.20 μs +6.4%
DisjointSetBenchmark.Dictionary_Connected(ItemCount: 100000) 155.55 μs 1.19 μs 254.50 μs -38.9% ✅
DisjointSetBenchmark.DisjointSet_Connected(ItemCount: 100000) 268.50 μs 16.17 μs 335.75 μs -20.0% ✅
SmallSetBenchmark.HashSet_Contains(ItemCount: 8) 38.0 ns 0.7 ns 39.1 ns -2.9%
SmallSetBenchmark.SmallSet_Contains(ItemCount: 8) 20.0 ns 0.3 ns 19.1 ns +4.8%
SmallSetBenchmark.HashSet_Contains(ItemCount: 64) 303.2 ns 0.8 ns 299.2 ns +1.3%
SmallSetBenchmark.SmallSet_Contains(ItemCount: 64) 925.0 ns 13.2 ns 1.09 μs -15.3% ✅
SparseSetBenchmark.HashSet_Contains(ItemCount: 1000) 4.62 μs 7.6 ns n/a 🆕 new
SparseSetBenchmark.SparseSet_Contains(ItemCount: 1000) 1.43 μs 1.3 ns n/a 🆕 new
SparseSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.28 ms 4.87 μs n/a 🆕 new
SparseSetBenchmark.SparseSet_Contains(ItemCount: 100000) 264.45 μs 651.8 ns n/a 🆕 new
CountMinSketchBenchmark.Dictionary_Estimate(ItemCount: 1000) 4.67 μs 20.8 ns 4.39 μs +6.5%
CountMinSketchBenchmark.CountMinSketch_Estimate(ItemCount: 1000) 8.20 μs 300.6 ns 10.08 μs -18.7% ✅
CountMinSketchBenchmark.Dictionary_Estimate(ItemCount: 100000) 531.52 μs 1.34 μs 496.01 μs +7.2%
CountMinSketchBenchmark.CountMinSketch_Estimate(ItemCount: 100000) 2.34 ms 1.30 μs 2.01 ms +16.4% ⚠️
SmallDictionaryBenchmark.Dictionary_Insert(ItemCount: 8) 180.7 ns 0.7 ns 158.3 ns +14.1% ⚠️
SmallDictionaryBenchmark.SmallDictionary_Insert(ItemCount: 8) 80.1 ns 1.4 ns 83.9 ns -4.5%
SmallDictionaryBenchmark.Dictionary_Insert(ItemCount: 64) 876.8 ns 12.9 ns 762.6 ns +15.0% ⚠️
SmallDictionaryBenchmark.SmallDictionary_Insert(ItemCount: 64) 1.06 μs 5.0 ns 1.07 μs -1.2%
PooledCelerityDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 15.17 μs 451.4 ns 12.99 μs +16.8% ⚠️
RobinHoodDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 15.10 μs 161.4 ns 14.10 μs +7.1%
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Insert(ItemCount: 1000) 8.27 μs 253.9 ns 8.05 μs +2.8%
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Insert(ItemCount: 1000) 17.87 μs 188.6 ns 18.18 μs -1.7%
PooledCelerityDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 5.29 ms 100.94 μs 4.93 ms +7.2%
RobinHoodDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 5.27 ms 123.70 μs 4.87 ms +8.1%
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Insert(ItemCount: 100000) 3.22 ms 15.04 μs 2.96 ms +8.9%
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Insert(ItemCount: 100000) 9.20 ms 257.44 μs 8.17 ms +12.7% ⚠️
SmallDictionaryBenchmark.Dictionary_Lookup(ItemCount: 8) 37.8 ns 0.7 ns 36.9 ns +2.5%
SmallDictionaryBenchmark.SmallDictionary_Lookup(ItemCount: 8) 23.3 ns 0.5 ns 30.8 ns -24.3% ✅
SmallDictionaryBenchmark.Dictionary_Lookup(ItemCount: 64) 309.0 ns 14.5 ns 296.7 ns +4.1%
SmallDictionaryBenchmark.SmallDictionary_Lookup(ItemCount: 64) 959.2 ns 17.5 ns 1.11 μs -13.3% ✅
PooledCelerityDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.71 μs 114.3 ns 4.74 μs -0.6%
RobinHoodDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.60 μs 3.7 ns 4.72 μs -2.6%
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Lookup(ItemCount: 1000) 2.43 μs 76.7 ns 2.34 μs +4.0%
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Lookup(ItemCount: 1000) 2.90 μs 13.2 ns 2.65 μs +9.6%
PooledCelerityDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.62 ms 9.43 μs 1.60 ms +1.6%
RobinHoodDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.60 ms 3.81 μs 1.60 ms +0.2%
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Lookup(ItemCount: 100000) 654.66 μs 11.97 μs 693.01 μs -5.5%
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Lookup(ItemCount: 100000) 908.36 μs 17.39 μs 942.23 μs -3.6%
SmallDictionaryBenchmark.Dictionary_Remove(ItemCount: 8) 1.24 μs 136.4 ns 1.25 μs -0.9%
SmallSetBenchmark.HashSet_Remove(ItemCount: 8) 430.4 ns 80.1 ns 342.3 ns +25.7%
SmallDictionaryBenchmark.SmallDictionary_Remove(ItemCount: 8) 1.16 μs 81.3 ns 1.08 μs +7.3%
SmallSetBenchmark.SmallSet_Remove(ItemCount: 8) 1.18 μs 94.0 ns 1.32 μs -10.1%
SmallDictionaryBenchmark.Dictionary_Remove(ItemCount: 64) 5.21 μs 141.3 ns 5.12 μs +1.7%
SmallSetBenchmark.HashSet_Remove(ItemCount: 64) 1.38 μs 143.8 ns 1.75 μs -21.4%
SmallDictionaryBenchmark.SmallDictionary_Remove(ItemCount: 64) 22.26 μs 3.24 μs 22.42 μs -0.7%
SmallSetBenchmark.SmallSet_Remove(ItemCount: 64) 23.52 μs 3.44 μs 20.78 μs +13.2%
PooledCelerityDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 77.34 μs 8.68 μs 83.61 μs -7.5%
RobinHoodDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 75.94 μs 7.58 μs 84.61 μs -10.3%
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Remove(ItemCount: 1000) 147.76 μs 3.81 μs 143.87 μs +2.7%
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Remove(ItemCount: 1000) 136.65 μs 10.00 μs 135.54 μs +0.8%
SparseSetBenchmark.HashSet_Remove(ItemCount: 1000) 28.78 μs 1.57 μs n/a 🆕 new
SparseSetBenchmark.SparseSet_Remove(ItemCount: 1000) 22.16 μs 2.16 μs n/a 🆕 new
PooledCelerityDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.17 ms 116.89 μs 2.09 ms +4.0%
RobinHoodDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.08 ms 80.63 μs 2.28 ms -8.7%
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Remove(ItemCount: 100000) 1.91 ms 89.99 μs 1.58 ms +20.9% ⚠️
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Remove(ItemCount: 100000) 2.24 ms 288.59 μs 2.03 ms +10.2%
SparseSetBenchmark.HashSet_Remove(ItemCount: 100000) 1.47 ms 14.13 μs n/a 🆕 new
SparseSetBenchmark.SparseSet_Remove(ItemCount: 100000) 652.50 μs 13.36 μs n/a 🆕 new
DisjointSetBenchmark.Dictionary_Union(ItemCount: 1000) 99.81 μs 1.09 μs 97.60 μs +2.3%
DisjointSetBenchmark.DisjointSet_Union(ItemCount: 1000) 28.30 μs 46.7 ns 26.83 μs +5.5%
DisjointSetBenchmark.Dictionary_Union(ItemCount: 100000) 52.90 ms 1.25 ms 46.93 ms +12.7% ⚠️
DisjointSetBenchmark.DisjointSet_Union(ItemCount: 100000) 8.08 ms 42.75 μs 8.21 ms -1.5%
Hashers (100)
Benchmark This PR StdDev main Δ
StringHasherBenchmark.Bcl_GetHashCode(Shape: ShortAscii) 15.40 μs 40.7 ns 15.39 μs +0.0%
StringHasherBenchmark.EqualityComparer_Default(Shape: ShortAscii) 15.38 μs 16.9 ns 15.40 μs -0.1%
StringHasherBenchmark.Djb2(Shape: ShortAscii) 22.02 μs 44.6 ns 22.15 μs -0.6%
StringHasherBenchmark.Djb2A(Shape: ShortAscii) 22.03 μs 32.6 ns 22.03 μs -0.0%
StringHasherBenchmark.Sdbm(Shape: ShortAscii) 32.85 μs 28.0 ns 32.85 μs +0.0%
StringHasherBenchmark.Elf(Shape: ShortAscii) 44.03 μs 139.7 ns 44.02 μs +0.0%
StringHasherBenchmark.Crc32(Shape: ShortAscii) 49.92 μs 84.0 ns 49.85 μs +0.1%
StringHasherBenchmark.Adler32(Shape: ShortAscii) 96.25 μs 86.4 ns 96.20 μs +0.0%
StringHasherBenchmark.FnV1(Shape: ShortAscii) 25.35 μs 32.3 ns 25.36 μs -0.0%
StringHasherBenchmark.FnV1_64(Shape: ShortAscii) 25.48 μs 50.0 ns 25.49 μs -0.0%
StringHasherBenchmark.FnV1A(Shape: ShortAscii) 10.66 μs 39.2 ns 10.66 μs -0.0%
StringHasherBenchmark.FnV1A_Full(Shape: ShortAscii) 22.84 μs 19.5 ns 22.86 μs -0.1%
StringHasherBenchmark.FnV1A_64(Shape: ShortAscii) 25.73 μs 34.8 ns 25.73 μs -0.0%
StringHasherBenchmark.JenkinsOaat(Shape: ShortAscii) 39.28 μs 32.1 ns 39.28 μs -0.0%
StringHasherBenchmark.Murmur2(Shape: ShortAscii) 15.20 μs 34.0 ns 15.19 μs +0.1%
StringHasherBenchmark.Murmur3(Shape: ShortAscii) 17.32 μs 32.4 ns 17.31 μs +0.0%
StringHasherBenchmark.XxHash32(Shape: ShortAscii) 16.92 μs 15.1 ns 16.91 μs +0.1%
StringHasherBenchmark.XxHash64(Shape: ShortAscii) 18.12 μs 19.3 ns 18.10 μs +0.1%
StringHasherBenchmark.XxHash3(Shape: ShortAscii) 14.84 μs 26.4 ns 14.83 μs +0.1%
StringHasherBenchmark.CityHash64(Shape: ShortAscii) 15.23 μs 11.8 ns 15.22 μs +0.1%
StringHasherBenchmark.MetroHash64(Shape: ShortAscii) 15.01 μs 9.4 ns 15.00 μs +0.1%
StringHasherBenchmark.SipHash13(Shape: ShortAscii) 27.38 μs 22.7 ns 27.40 μs -0.1%
StringHasherBenchmark.SipHash24(Shape: ShortAscii) 38.45 μs 17.7 ns 38.44 μs +0.0%
StringHasherBenchmark.HalfSipHash24(Shape: ShortAscii) 50.03 μs 74.1 ns 49.97 μs +0.1%
StringHasherBenchmark.HighwayHash64(Shape: ShortAscii) 478.30 μs 1.21 μs 479.90 μs -0.3%
StringHasherBenchmark.Bcl_GetHashCode(Shape: LongAscii) 96.96 μs 119.6 ns 96.94 μs +0.0%
StringHasherBenchmark.EqualityComparer_Default(Shape: LongAscii) 96.70 μs 153.8 ns 96.57 μs +0.1%
StringHasherBenchmark.Djb2(Shape: LongAscii) 229.40 μs 79.8 ns 229.24 μs +0.1%
StringHasherBenchmark.Djb2A(Shape: LongAscii) 229.26 μs 75.5 ns 229.26 μs +0.0%
StringHasherBenchmark.Sdbm(Shape: LongAscii) 308.16 μs 340.7 ns 307.96 μs +0.1%
StringHasherBenchmark.Elf(Shape: LongAscii) 582.42 μs 5.06 μs 582.42 μs -0.0%
StringHasherBenchmark.Crc32(Shape: LongAscii) 590.04 μs 950.2 ns 589.42 μs +0.1%
StringHasherBenchmark.Adler32(Shape: LongAscii) 789.68 μs 3.58 μs 788.93 μs +0.1%
StringHasherBenchmark.FnV1(Shape: LongAscii) 289.65 μs 321.8 ns 289.47 μs +0.1%
StringHasherBenchmark.FnV1_64(Shape: LongAscii) 284.45 μs 225.7 ns 284.45 μs +0.0%
StringHasherBenchmark.FnV1A(Shape: LongAscii) 122.29 μs 121.4 ns 122.31 μs -0.0%
StringHasherBenchmark.FnV1A_Full(Shape: LongAscii) 281.78 μs 155.4 ns 281.64 μs +0.0%
StringHasherBenchmark.FnV1A_64(Shape: LongAscii) 287.02 μs 298.8 ns 286.88 μs +0.0%
StringHasherBenchmark.JenkinsOaat(Shape: LongAscii) 378.68 μs 288.5 ns 378.54 μs +0.0%
StringHasherBenchmark.Murmur2(Shape: LongAscii) 101.85 μs 134.1 ns 101.87 μs -0.0%
StringHasherBenchmark.Murmur3(Shape: LongAscii) 113.03 μs 161.2 ns 113.24 μs -0.2%
StringHasherBenchmark.XxHash32(Shape: LongAscii) 73.30 μs 95.8 ns 73.32 μs -0.0%
StringHasherBenchmark.XxHash64(Shape: LongAscii) 90.62 μs 862.9 ns 91.29 μs -0.7%
StringHasherBenchmark.XxHash3(Shape: LongAscii) 70.15 μs 185.7 ns 69.85 μs +0.4%
StringHasherBenchmark.CityHash64(Shape: LongAscii) 122.78 μs 1.43 μs 122.34 μs +0.4%
StringHasherBenchmark.MetroHash64(Shape: LongAscii) 77.31 μs 2.51 μs 77.57 μs -0.3%
StringHasherBenchmark.SipHash13(Shape: LongAscii) 114.79 μs 88.4 ns 114.84 μs -0.0%
StringHasherBenchmark.SipHash24(Shape: LongAscii) 160.99 μs 743.2 ns 160.83 μs +0.1%
StringHasherBenchmark.HalfSipHash24(Shape: LongAscii) 247.81 μs 745.0 ns 247.56 μs +0.1%
StringHasherBenchmark.HighwayHash64(Shape: LongAscii) 846.52 μs 2.20 μs 835.51 μs +1.3%
StringHasherBenchmark.Bcl_GetHashCode(Shape: NonAscii) 22.89 μs 6.4 ns 22.87 μs +0.1%
StringHasherBenchmark.EqualityComparer_Default(Shape: NonAscii) 22.84 μs 31.9 ns 22.84 μs -0.0%
StringHasherBenchmark.Djb2(Shape: NonAscii) 43.50 μs 121.6 ns 43.44 μs +0.1%
StringHasherBenchmark.Djb2A(Shape: NonAscii) 43.45 μs 45.9 ns 43.44 μs +0.0%
StringHasherBenchmark.Sdbm(Shape: NonAscii) 61.63 μs 76.1 ns 61.60 μs +0.0%
StringHasherBenchmark.Elf(Shape: NonAscii) 99.74 μs 166.6 ns 99.68 μs +0.1%
StringHasherBenchmark.Crc32(Shape: NonAscii) 102.81 μs 388.0 ns 102.59 μs +0.2%
StringHasherBenchmark.Adler32(Shape: NonAscii) 175.45 μs 209.0 ns 175.41 μs +0.0%
StringHasherBenchmark.FnV1(Shape: NonAscii) 47.65 μs 38.2 ns 47.65 μs -0.0%
StringHasherBenchmark.FnV1_64(Shape: NonAscii) 50.01 μs 54.7 ns 50.05 μs -0.1%
StringHasherBenchmark.FnV1A(Shape: NonAscii) 21.66 μs 36.5 ns 21.65 μs +0.0%
StringHasherBenchmark.FnV1A_Full(Shape: NonAscii) 45.08 μs 58.3 ns 45.09 μs -0.0%
StringHasherBenchmark.FnV1A_64(Shape: NonAscii) 49.60 μs 34.8 ns 49.59 μs +0.0%
StringHasherBenchmark.JenkinsOaat(Shape: NonAscii) 73.16 μs 106.9 ns 73.21 μs -0.1%
StringHasherBenchmark.Murmur2(Shape: NonAscii) 27.23 μs 190.1 ns 27.28 μs -0.2%
StringHasherBenchmark.Murmur3(Shape: NonAscii) 31.79 μs 87.4 ns 31.91 μs -0.4%
StringHasherBenchmark.XxHash32(Shape: NonAscii) 23.91 μs 30.1 ns 23.90 μs +0.1%
StringHasherBenchmark.XxHash64(Shape: NonAscii) 29.12 μs 14.6 ns 29.14 μs -0.1%
StringHasherBenchmark.XxHash3(Shape: NonAscii) 23.01 μs 178.1 ns 23.05 μs -0.2%
StringHasherBenchmark.CityHash64(Shape: NonAscii) 22.05 μs 28.7 ns 22.04 μs +0.1%
StringHasherBenchmark.MetroHash64(Shape: NonAscii) 25.65 μs 37.4 ns 25.64 μs +0.0%
StringHasherBenchmark.SipHash13(Shape: NonAscii) 36.94 μs 123.6 ns 36.95 μs -0.0%
StringHasherBenchmark.SipHash24(Shape: NonAscii) 51.34 μs 474.8 ns 51.60 μs -0.5%
StringHasherBenchmark.HalfSipHash24(Shape: NonAscii) 73.11 μs 580.7 ns 73.41 μs -0.4%
StringHasherBenchmark.HighwayHash64(Shape: NonAscii) 511.48 μs 342.4 ns 512.24 μs -0.1%
IntegerHasherBenchmark.Guid_Bcl 1.48 μs 7.1 ns 1.48 μs -0.4%
IntegerHasherBenchmark.Guid_EqualityComparer 3.40 μs 2.4 ns 3.48 μs -2.3%
IntegerHasherBenchmark.Guid_Celerity 9.10 μs 3.6 ns 9.10 μs +0.0%
IntegerHasherBenchmark.Int32_Bcl 773.3 ns 1.2 ns 774.1 ns -0.1%
IntegerHasherBenchmark.Int32_EqualityComparer 764.0 ns 0.4 ns 764.0 ns +0.0%
IntegerHasherBenchmark.Int32_Identity 770.3 ns 8.5 ns 763.4 ns +0.9%
IntegerHasherBenchmark.Int32_WangNaive 1.41 μs 0.4 ns 1.41 μs +0.0%
IntegerHasherBenchmark.Int32_Wang 3.42 μs 3.5 ns 3.42 μs +0.0%
IntegerHasherBenchmark.Int32_Murmur3 3.05 μs 1.0 ns 3.05 μs -0.0%
IntegerHasherBenchmark.Int64_Bcl 1.68 μs 0.8 ns 1.68 μs -0.0%
IntegerHasherBenchmark.Int64_EqualityComparer 1.41 μs 0.6 ns 1.41 μs -0.0%
IntegerHasherBenchmark.Int64_Identity 765.4 ns 1.0 ns 763.1 ns +0.3%
IntegerHasherBenchmark.Int64_WangNaive 2.10 μs 1.1 ns 2.11 μs -0.0%
IntegerHasherBenchmark.Int64_Wang 4.70 μs 3.7 ns 4.70 μs +0.0%
IntegerHasherBenchmark.Int64_Murmur3 2.68 μs 2.2 ns 2.68 μs +0.1%
IntegerHasherBenchmark.UInt32_Bcl 773.8 ns 0.5 ns 774.1 ns -0.0%
IntegerHasherBenchmark.UInt32_EqualityComparer 763.7 ns 0.4 ns 771.1 ns -1.0%
IntegerHasherBenchmark.UInt32_Default 1.41 μs 0.4 ns 1.41 μs -0.0%
IntegerHasherBenchmark.UInt32_Wang 3.42 μs 1.7 ns 3.42 μs -0.1%
IntegerHasherBenchmark.UInt32_Murmur3 3.05 μs 1.0 ns 3.05 μs +0.0%
IntegerHasherBenchmark.UInt64_Bcl 1.68 μs 0.7 ns 1.68 μs -0.0%
IntegerHasherBenchmark.UInt64_EqualityComparer 1.41 μs 0.4 ns 1.41 μs -0.0%
IntegerHasherBenchmark.UInt64_Default 2.68 μs 1.5 ns 2.68 μs -0.0%
IntegerHasherBenchmark.UInt64_Wang 4.70 μs 1.9 ns 4.70 μs -0.0%
IntegerHasherBenchmark.UInt64_WangNaive 2.10 μs 1.0 ns 2.10 μs -0.0%

Same-runner A/B (sharded 6-way): main (90f5095) and this PR were built and benchmarked back-to-back on the same runner per shard, so hardware variance cancels out. ⚠️ = PR mean ≥ +10% slower than main and beyond combined std-dev; ✅ = correspondingly faster.

Copilot AI review requested due to automatic review settings July 23, 2026 06:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.

Comment thread src/Celerity/Collections/SparseSet.cs
Comment thread src/Celerity.Benchmarks/SparseSetBenchmark.cs
marius-bughiu added a commit that referenced this pull request Jul 23, 2026
…for a fair comparison

SparseSet's universe is mandatory, so `new SparseSet(universe)` inherently
pre-allocates its sparse array and pays no sparse resize on Add, whereas the
`new HashSet<int>()` baseline paid full incremental-rehash growth — an unfair
per-add comparison. Give the baseline the matching capacity hint
(`new HashSet<int>(ItemCount)`, as the Setup / Remove paths already do) so the
Add category measures per-add cost rather than the baseline's rehash overhead.
Addresses a Copilot review comment on PR #288.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 23, 2026 06:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 3 comments.

Comment thread src/Celerity/Collections/SparseSet.cs
Comment thread README.md Outdated
Comment thread src/Celerity/Collections/SparseSet.cs

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

CHANGELOG.md:10

  • The new SparseSet changelog entries are much longer than the repo’s documented guidance (“a few sentences at most”) and include implementation-level detail. This is a release-safety rule because the release workflow uses the full section as the GitHub Release body, so please tighten these to short, user-facing bullets (and consider folding the rollout bullet into a brief parity note).
- **`SparseSet`** in `Celerity.Collections` — a bounded-universe `[0, Universe)` integer set (the Briggs–Torczon sparse set), filling a BCL gap. It wins over `HashSet<int>` where the set is cleared and rebuilt often: `Clear()` is `O(1)` (it leaves the backing arrays untouched, versus `HashSet` zeroing its table) and iteration is a dense scan over just the present elements — the "visited"-set shape in graph traversal, ECS, and sweep-line code. Costs `O(Universe)` memory and stores only values in `[0, Universe)`. Implements `ISet<int>`; an opt-in specialized type, not a `HashSet<int>` replacement. Closes [#287](https://github.com/marius-bughiu/Celerity/issues/287).
- Full parity rollout for `SparseSet`: dedicated tests (`SparseSetTests` / `SparseSetEnumerationTests` / `SparseSetDifferentialTests`), a `SetAlgebraTests` conformance row, a `Celerity.Fuzz` `SparseSetCase`, `SparseSetBenchmark` (registered in `Program.cs`, with a `ClearRefill` category), dashboard wiring (`web/index.html`, `web/dev/bench/{index,detail}.html`), and docs (`docs/api/collections.md` + README).

Copilot AI review requested due to automatic review settings July 23, 2026 07:10

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 3 comments.

Comment thread src/Celerity/Collections/SparseSet.cs
Comment thread src/Celerity/Collections/SparseSet.cs
Comment thread src/Celerity/Collections/SparseSet.cs

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

CHANGELOG.md:9

  • This changelog entry is much longer than the contributor guidance (“a few sentences at most”). Consider tightening it to focus on the observable user-facing wins and constraints, and keep implementation-level detail minimal so release notes stay compact.
- **`SparseSet`** in `Celerity.Collections` — a bounded-universe `[0, Universe)` integer set (the Briggs–Torczon sparse set), filling a BCL gap. It wins over `HashSet<int>` where the set is cleared and rebuilt often: `Clear()` is `O(1)` (it leaves the backing arrays untouched, versus `HashSet` zeroing its table) and iteration is a dense scan over just the present elements — the "visited"-set shape in graph traversal, ECS, and sweep-line code. Costs `O(Universe)` memory and stores only values in `[0, Universe)`. Implements `ISet<int>`; an opt-in specialized type, not a `HashSet<int>` replacement. Closes [#287](https://github.com/marius-bughiu/Celerity/issues/287).

Comment thread README.md Outdated
Comment thread src/Celerity.Benchmarks/SparseSetBenchmark.cs Outdated
marius-bughiu added a commit that referenced this pull request Jul 23, 2026
…eSet

Round-3 tightened the Clear() wording (it resets the count; the version bump only
happens on the non-empty path) but missed two spots: the README SparseSet paragraph
and the SparseSetBenchmark header comment. Both now say "resets the count" to match
the observable behavior and the wording used elsewhere. Addresses Copilot review
comments on PR #288.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@marius-bughiu
marius-bughiu requested a review from Copilot July 23, 2026 07:51

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

CHANGELOG.md:9

  • The new [Unreleased] changelog bullet is much longer than the repo’s documented guidance (“a few sentences at most”). Consider tightening it to a short, user-facing summary so the release body stays within GitHub’s size limit.
- **`SparseSet`** in `Celerity.Collections` — a bounded-universe `[0, Universe)` integer set (the Briggs–Torczon sparse set), filling a BCL gap. It wins over `HashSet<int>` where the set is cleared and rebuilt often: `Clear()` is `O(1)` (it leaves the backing arrays untouched, versus `HashSet` zeroing its table) and iteration is a dense scan over just the present elements — the "visited"-set shape in graph traversal, ECS, and sweep-line code. Costs `O(Universe)` memory and stores only values in `[0, Universe)`. Implements `ISet<int>`; an opt-in specialized type, not a `HashSet<int>` replacement. Closes [#287](https://github.com/marius-bughiu/Celerity/issues/287).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated no new comments.

marius-bughiu added a commit that referenced this pull request Jul 23, 2026
Fold the membership round-trip into Remove so _sparse[item] is read a single time
(previously once inside ContainsUnchecked and again to compute the swap index) on
this hot path. Same semantics — validated by the 69 dedicated tests and a 30,000-case
fuzz run against the HashSet<int> oracle. Addresses a Copilot review comment on PR #288.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
marius-bughiu and others added 9 commits July 24, 2026 23:03
…t with O(1) clear & dense iteration (#287)

SparseSet is a set of non-negative integers over a bounded universe [0, Universe),
backed by the Briggs-Torczon sparse-set representation (a dense value array + a
sparse index array). It fills a BCL gap (.NET ships no sparse set) and beats
HashSet<int> on the two things that representation is built for: an O(1) Clear that
touches no memory (HashSet zeroes its whole table) and dense, cache-friendly
iteration over exactly the present elements — the winning shape for clear-and-rebuild
"visited" sets in graph traversal, ECS, and sweep-line code. Add/Contains/Remove are
O(1) with no hashing. Tradeoffs: O(Universe) memory and non-negative-values-only
(out of range throws on Add, reads as absent on Contains/Remove). Implements ISet<int>.

Full parity rollout in one PR:
- Collection: src/Celerity/Collections/SparseSet.cs (ISet<int>, struct enumerator).
- Dedicated tests: SparseSetTests, SparseSetEnumerationTests, and a 6,000-step
  SparseSetDifferentialTests vs a HashSet<int> oracle over a bounded non-negative
  universe (it cannot join the shared SetAlgebraDifferentialTests, whose universe
  spans negatives it cannot store — exactly like EnumSet).
- Cross-collection tests: SparseSet rows in SetAlgebraTests (conformance + the
  bounded-universe out-of-range-add caveat).
- Benchmark: SparseSetBenchmark (Add/Contains/ClearRefill/Remove vs HashSet<int>),
  registered in Program.cs CoreBenchmarks.
- Dashboard: ship card (web/index.html) + COLLECTIONS arrays (web/dev/bench/index.html,
  detail.html).
- Docs: full API section in docs/api/collections.md + README (Sets list, ISet note,
  paragraph + example, decision-table row).
- AOT smoke test: SparseSet coverage block.

ROADMAP: no status to flip — the specialized-collection work is done; this is a
post-roadmap tier-(c) BCL-gap enhancement (like EnumSet/SwissSet/TopKSketch).

Closes #287.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add SparseSetCase to the Celerity.Fuzz harness, reconciling TryAdd / Remove /
Clear churn and enumeration against a HashSet<int> oracle over SparseSet's
bounded non-negative universe [0, 32) (it cannot draw from the shared [-8, 24]
key domain, which spans negatives it rejects by design). 20,000 cases pass.
Also adds the matching CHANGELOG bullet.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…r wording + terser changelog

- Reword the "uninitialized garbage" / "touches no memory" claims in SparseSet's
  XML docs, docs/api/collections.md, README, ship card, and benchmark comment:
  .NET arrays are zero-initialized, so the real property is tolerating *stale*
  sparse entries across Clear/mutations, and Clear() resets count/version rather
  than touching no memory (it just leaves the backing arrays untouched).
- Condense the CHANGELOG [Unreleased] SparseSet entries to the repo's brevity
  standard (a user-facing lead bullet + one parity-rollout bullet), so the section
  stays within the release-body size the release workflow extracts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…for a fair comparison

SparseSet's universe is mandatory, so `new SparseSet(universe)` inherently
pre-allocates its sparse array and pays no sparse resize on Add, whereas the
`new HashSet<int>()` baseline paid full incremental-rehash growth — an unfair
per-add comparison. Give the baseline the matching capacity hint
(`new HashSet<int>(ItemCount)`, as the Setup / Remove paths already do) so the
Add category measures per-add cost rather than the baseline's rehash overhead.
Addresses a Copilot review comment on PR #288.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- README: qualify the "mutable sets drop in wherever a HashSet<T> is used" claim —
  the bounded-domain sets (EnumSet, SparseSet) are the exception: a mutating op that
  must add an out-of-domain value throws. Adding SparseSet to that list had made the
  blanket claim inaccurate.
- SparseSet XML docs / docs/api/collections.md: tighten the Clear() wording — it
  resets the count (the version bump only happens on the non-empty path, which the
  method early-returns past when already empty), so drop the imprecise "and version"
  from the summary claims.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ullet

Fold the separate "full parity rollout" bullet (tests / fuzz / benchmark /
dashboard / docs list) away, leaving a single user-facing entry that matches the
shipped 2.3.0 convention (one bullet per collection, ending with Closes #NNN).
Per CONTRIBUTING.md / CLAUDE.md, implementation-level detail belongs in the PR
body, not the changelog (a release-safety rule — the release workflow extracts
the whole version section as the GitHub Release body). The full rollout remains
documented in the PR description table.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fold the membership round-trip into Remove so _sparse[item] is read a single time
(previously once inside ContainsUnchecked and again to compute the swap index) on
this hot path. Same semantics — validated by the 69 dedicated tests and a 30,000-case
fuzz run against the HashSet<int> oracle. Addresses a Copilot review comment on PR #288.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…eSet

Round-3 tightened the Clear() wording (it resets the count; the version bump only
happens on the non-empty path) but missed two spots: the README SparseSet paragraph
and the SparseSetBenchmark header comment. Both now say "resets the count" to match
the observable behavior and the wording used elsewhere. Addresses Copilot review
comments on PR #288.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Trim the single [Unreleased] bullet to the leaner end of the shipped entry style
(cf. Deque / LruCache), keeping the what / why-it-wins / cost / positioning while
matching CONTRIBUTING.md's "a few sentences at most" release-safety rule.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 24, 2026 20:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated no new comments.

@marius-bughiu
marius-bughiu merged commit 90f5095 into main Jul 24, 2026
14 checks passed
marius-bughiu added a commit that referenced this pull request Jul 24, 2026
Resolves conflicts with the Trie (#286) and SparseSet (#288) merges, which
touched the same shared parity files. Every conflict was a "keep both, in
order" resolution — no content from either side was dropped:

- Program.cs           — CoreBenchmarks keeps Trie + Fenwick (SparseSet auto-merged)
- web/index.html       — ship cards for both Trie and FenwickTree
- web/dev/bench/*.html — COLLECTIONS entries for both
- README.md            — both the "Prefix trees" and "Prefix sums" groups, both
                         details blocks, and both decision-table rows (keeping
                         main's updated iteration-order row that mentions Trie)
- docs/api/collections.md — main's Trie section plus the FenwickTree section
- CHANGELOG.md         — all three Added entries plus main's new Fixed section

Also condenses the FenwickTree changelog entry to a single user-facing bullet,
matching the convention main just applied to the Trie and SparseSet entries.

Full suite green after the merge: 4413 passed, 0 failed.
@marius-bughiu
marius-bughiu deleted the feat/sparse-set branch July 24, 2026 22:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add SparseSet — bounded-universe sparse integer set with O(1) clear & dense iteration

2 participants