Skip to content

feat(collections): add CompressedIntSet — a chunk-compressed exact set of 32-bit integers - #337

Merged
marius-bughiu merged 8 commits into
mainfrom
feat/issue-310-compressed-int-set
Aug 1, 2026
Merged

feat(collections): add CompressedIntSet — a chunk-compressed exact set of 32-bit integers#337
marius-bughiu merged 8 commits into
mainfrom
feat/issue-310-compressed-int-set

Conversation

@marius-bughiu

@marius-bughiu marius-bughiu commented Aug 1, 2026

Copy link
Copy Markdown
Owner

Closes #310.

CompressedIntSet is an exact, compressed set of 32-bit integers. It closes the huge-and-sparse hole in the integer-set family that BitSet (dense, bounded), SparseSet (small universe, O(Universe) memory) and IntSet (hash) leave open.

The value space is partitioned into 65,536-value chunks, and each chunk is stored as a sorted ushort[], a 1024-word bitmap, or run-length pairs — whichever is smallest. Set algebra then works inside a chunk (a linear merge of two sorted cursors, or one ANDed word per 64 values) instead of one hash probe per element, and a chunk neither side populates is skipped with a single key comparison, so cost tracks populated chunks rather than elements.

The kill criterion

The issue set a bar: close as won't-ship unless intersect beats HashSet<int> by ≥3x at 1M elements over a 100M universe and memory drops ≥5x. Measured after implementation, both are cleared:

HashSet<int> CompressedIntSet
intersect (1% overlap) 60.3 ms 6.4 ms 9.5x
intersect (50% overlap) 47.9 ms 7.8 ms 6.2x
union 87.4 ms 7.6 ms 11.5x
except 24.2 ms 7.0 ms 3.5x
heap 17.7 MB 2.0 MB 8.9x smaller

Median of 7 reps, operation only (both operands built outside the clock), net10.0 Release.

Worth recording: the first draft measured only 2.7x on intersect — below the bar. It probed the right-hand container with a binary search per element. Replacing that with a linear merge of the two sorted cursors is where the 9.5x comes from, and it is the single most load-bearing change in the implementation.

Design calls worth a maintainer's eye

  • "Per-container-pair dispatch" was implemented as two paths per operator, not nine. A word-parallel path for the dense bitmap⊕bitmap case, and a cursor-driven path for everything else. The reason is not effort: a run container that is only read must never be decompressed, and a single sorted-cursor abstraction gets that for free where nine hand-written pairs would each have had to re-derive it. The observable contract is still pinned for all nine pairs, in both operand orders, by CompressedIntSetSetAlgebraTests, so specializing any pair later cannot silently change an answer.
  • Run containers are produced only by Optimize() and AddRange, never speculatively on a single insert — the same "compress once it has settled" contract as Roaring's own runOptimize. A TryAdd / Remove landing in a run-encoded chunk expands it back to its natural form first, and that is documented on the type, in the API reference, and in the README.
  • Count can throw. The set can hold all 2^32 int values, which does not fit the int that ICollection<T>.Count must return. Cardinality (a long) is the always-correct count; Count throws OverflowException in the one case it cannot answer, rather than saturating silently. Only a very wide AddRange can reach it, and there is a test that does.
  • Caveat Create hash function evaluator #2 of the issue was accepted, not treated as a kill. Celerity ships no serializers, so there is no portable Roaring format and therefore no Lucene / Druid / Spark posting-list interop. The issue asked for a maintainer ruling before writing code; this ran unattended, so the call made was: the in-process memory and set-algebra win stands on its own, and the caveat leads both the API-reference section and the README row rather than being buried. Happy to be overruled — but the numbers above are what the type is for.
  • Bitmap operations are scalar ulong loops, not Vector<ulong> (unlike BitSet). A 1024-word loop is already word-parallel, and the workload the type is sold for lands in array containers, not bitmaps, so SIMD would not move the headline number. Called out in case you want it anyway.

Parity rollout

Everything below is in this PR — nothing deferred.

a. Collectionsrc/Celerity/Collections/CompressedIntSet.cs. Implements ISet<int> and IReadOnlySet<int> (so it does not re-open the interface gap #306 is closing), plus AddRange, Optimize, IntersectCount, Cardinality, MemoryUsageInBytes, and an allocation-free struct enumerator. Enumeration is in ascending signed order — the chunk key is the value's high 16 bits with the sign bit flipped — which HashSet<int> does not offer. XML docs on every public member; net8.0 floor; the container thresholds are named constants with the reasoning next to them.

b. Dedicated testsCompressedIntSetTests (container transitions, the 32-bit extremes, AddRange, Optimize, the Count overflow), CompressedIntSetEnumerationTests (ascending order across all three container forms in one pass, invalidation, CopyTo), CompressedIntSetSetAlgebraTests (the nine-pair matrix, both operand orders, plus the chunk-index merge and the IEnumerable fallback), CompressedIntSetDifferentialTests (CsCheck, with the value domain generated so it lands in one chunk or hundreds).

c. Cross-collection suitesSetAlgebraTests, SetAlgebraDifferentialTests, SetIEnumerableConstructorTests, SetExplicitICollectionMemberTests, ClearNoOpVersionTests. Suites that genuinely do not apply: SetConstructorValidationTests and LoadFactorBoundaryTests (no load factor), EnsureCapacityAndTrimExcessTests and CapacityArgumentValidationTests (no capacity ctor and no hasher — Optimize() is the trim), SetSourceCountBranchTests (the constructor takes no ICollection count hint, since there is no table to pre-size), and every dictionary-shaped suite.

d. Fuzz + AOT — a CompressedIntSet target in Celerity.Fuzz's Differential.All, interleaving add / remove / range-add / optimize / clear with the four mutating set operations against a HashSet<int> oracle, because the container state machine is the whole risk surface here. 4,000 cases pass locally. A Native AOT smoke-test block exercises all three container forms, the chunk-wise algebra, and both set interfaces.

e. BenchmarksCompressedIntSetBenchmark, registered in CoreBenchmarks, HashSet<int> baseline, [MemoryDiagnoser] on so the Add row's Allocated column is the memory comparison. The three Intersect arms sweep sparse / dense / clustered key distributions, because which container form a chunk lands in follows entirely from the shape of the data. The distribution is in the category name rather than a second [Params] on purpose — the dashboard parser accepts exactly one (ItemCount: N) suffix and a second parameter would blank the card.

f. Dashboard — ship card in web/index.html, COLLECTIONS entries in web/dev/bench/index.html and web/dev/bench/detail.html. node scripts/check_dashboard_coverage.js passes.

g. Docs — an API-reference section in docs/api/collections.md leading with the two caveats, and the README collections list, ISet<T> family sentence, sets <details> block with an example, decision-table row placed next to the BitSet / SparseSet / IntSet rows, and a cross-reference from the BitSet row.

h. CHANGELOG + ROADMAP — two short bullets under [Unreleased] → Added (deliberately terse: release.yml lifts the whole version section into the GitHub Release body, so the per-facet detail lives in this description instead); the 2.4.0 CompressedIntSet entry flipped to done with the measured numbers and the design calls recorded.

Test plan

  • dotnet build clean — no new warnings. (The CS8631 warnings in SetIEnumerableConstructorTests are pre-existing, tracked in Test project emits 3264 build warnings, burying 20 real CS8631 nullability warnings #332.)
  • dotnet test green on all three TFMs: 5,220 passed / 0 failed on net8.0, net9.0, net10.0.
  • Coverage gate: 100.00% line, 100.00% branchCompressedIntSet, its ContainerCursor and its Enumerator are each at 1.0/1.0, and scripts/coverage_report.py reports 100/100 overall.
  • Celerity.Fuzz --target CompressedIntSet --iterations 4000 — all cases pass.
  • Celerity.AotSmokeTest runs clean (managed run locally; the CI job does the Native AOT publish).
  • node scripts/check_dashboard_coverage.js — 138 cards across 42 collections wired.
  • Kill-criterion measurement at 1M / 100M reproduced above; the intersection, union and difference were verified element-for-element against HashSet<int> in the same harness.
  • CI matrix (build + test on the three TFMs, coverage gate, dashboard check, AOT publish, 8-shard A/B benchmarks).
  • gh-pages dashboard refresh on merge to main — the new CompressedIntSet card should populate on the next benchmark run. Worth a look: this PR adds a benchmark class, which is the shape Benchmark shard can time out on any PR that adds a benchmark class (head/base pack from different class lists) #300 says can time a shard out (head and base pack from different class lists).

🤖 Generated with Claude Code

…t of 32-bit integers

Closes the huge-and-sparse hole in the integer-set family that BitSet (dense,
bounded), SparseSet (small universe, O(Universe) memory) and IntSet (hash) leave
open. The value space is partitioned into 65,536-value chunks and each chunk is
stored as a sorted ushort[], a 1024-word bitmap, or run-length pairs — whichever
is smallest. Set algebra then works inside a chunk (a linear merge of two sorted
cursors, or one ANDed word per 64 values) instead of one hash probe per element,
and a chunk neither side populates is skipped with a single key comparison.

Measured at the issue's kill criterion — 1M elements over a 100M universe:

  intersect (1% overlap)    60.3 ms -> 6.4 ms    9.5x
  intersect (50% overlap)   47.9 ms -> 7.8 ms    6.2x
  union                     87.4 ms -> 7.6 ms   11.5x
  except                    24.2 ms -> 7.0 ms    3.5x
  heap                     17.7 MB -> 2.0 MB     8.9x smaller

Both bars in the issue (>=3x intersect, >=5x memory) are cleared. The first draft
probed with a binary search per element and measured only 2.7x on intersect; the
linear merge is what earns the number.

Implements ISet<int> and IReadOnlySet<int> with BCL HashSet<int> semantics, and
every set operation takes the chunk-wise path when the other side is also a
CompressedIntSet. Also ships AddRange (a range in a fresh chunk is one run pair,
four bytes whatever its width), Optimize (the only thing that produces run
containers from existing data), IntersectCount, and MemoryUsageInBytes.
Enumeration is in ascending signed order — the chunk key is the value's high 16
bits with the sign bit flipped — which HashSet<int> does not offer. Cardinality
is a long because the set can hold all 2^32 int values; Count throws
OverflowException in that one case rather than answering wrongly.

Caveat #2 of the issue was accepted rather than treated as a kill: Celerity ships
no serializers, so there is no portable Roaring format and no Lucene / Druid /
Spark interop. That leads both the API-reference section and the README row.

Parity rollout, all in this change:

- Dedicated tests: CompressedIntSetTests, CompressedIntSetEnumerationTests,
  CompressedIntSetSetAlgebraTests (every binary op across all nine container-form
  pairs, both operand orders), CompressedIntSetDifferentialTests (CsCheck).
- Cross-collection suites: SetAlgebraTests, SetAlgebraDifferentialTests,
  SetIEnumerableConstructorTests, SetExplicitICollectionMemberTests,
  ClearNoOpVersionTests.
- Celerity.Fuzz target driving the container state machine against a HashSet<int>
  oracle, and a Native AOT smoke-test block covering all three container forms.
- CompressedIntSetBenchmark registered in CoreBenchmarks, with [MemoryDiagnoser]
  and sparse / dense / clustered Intersect arms.
- Dashboard: ship card in web/index.html and COLLECTIONS entries in both
  web/dev/bench/index.html and web/dev/bench/detail.html.
- Docs: API-reference section and README list, decision-table row and example.
- CHANGELOG and ROADMAP.

Closes #310.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 1, 2026 01:50
@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown

Coverage

Metric Value
Line 100% (10911/10911)
Branch 100% (4448/4448)

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 CompressedIntSet, a Roaring-style chunk-compressed exact int set to Celerity’s collections family, and integrates it across the repo’s testing, fuzzing/AOT smoke coverage, benchmarks, dashboard wiring, and documentation.

Changes:

  • Introduces CompressedIntSet (ISet<int> + IReadOnlySet<int>) with chunk-wise container encoding (array/bitmap/run), explicit Optimize(), AddRange(...), IntersectCount(...), and ascending signed-order enumeration.
  • Adds dedicated + cross-suite test coverage, CsCheck differential tests, a fuzz target, and Native AOT smoke coverage.
  • Adds benchmarks + dashboard registration and updates docs/roadmap/changelog to document the new collection.

Reviewed changes

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

Show a summary per file
File Description
web/index.html Adds the “ships in the box” entry for CompressedIntSet.
web/dev/bench/index.html Registers CompressedIntSet ops for the benchmark dashboard grid.
web/dev/bench/detail.html Registers CompressedIntSet for the benchmark dashboard detail view.
src/Celerity/Collections/CompressedIntSet.cs Implements the new compressed integer set and its public API surface.
src/Celerity.Tests/Collections/SetIEnumerableConstructorTests.cs Adds shared-suite constructor semantics coverage for CompressedIntSet.
src/Celerity.Tests/Collections/SetExplicitICollectionMemberTests.cs Pins ICollection<int> explicit-member semantics for CompressedIntSet.
src/Celerity.Tests/Collections/SetAlgebraTests.cs Adds shared-suite set-algebra behavior coverage for the IEnumerable fallback path.
src/Celerity.Tests/Collections/SetAlgebraDifferentialTests.cs Adds shared-suite differential coverage row for CompressedIntSet.
src/Celerity.Tests/Collections/CompressedIntSetTests.cs Adds dedicated unit tests for core behavior, transitions, AddRange, Optimize, overflow count, etc.
src/Celerity.Tests/Collections/CompressedIntSetSetAlgebraTests.cs Adds container-pair matrix tests (9 form pairs × ops × operand order) + merge/fallback validations.
src/Celerity.Tests/Collections/CompressedIntSetEnumerationTests.cs Pins ascending enumeration and enumerator invalidation behavior.
src/Celerity.Tests/Collections/CompressedIntSetDifferentialTests.cs Adds CsCheck property-based differential testing against HashSet<int>.
src/Celerity.Tests/Collections/ClearNoOpVersionTests.cs Adds the “no-op Clear doesn’t bump version” contract test for CompressedIntSet.
src/Celerity.Fuzz/Differential.cs Adds a fuzz target driving interleaved operations vs a HashSet<int> oracle.
src/Celerity.Benchmarks/Program.cs Registers CompressedIntSetBenchmark in the CI-tracked benchmark suite.
src/Celerity.Benchmarks/CompressedIntSetBenchmark.cs Adds benchmark coverage (Add/Contains/Intersect*/Union/Except) with memory diagnoser.
src/Celerity.AotSmokeTest/Program.cs Adds AOT smoke coverage for all three container forms + algebra paths.
ROADMAP.md Marks CompressedIntSet as done and records measured results/design notes.
docs/api/collections.md Adds API reference documentation for CompressedIntSet.
CHANGELOG.md Adds [Unreleased] entries for CompressedIntSet and its supporting coverage/wiring.

Comment thread CHANGELOG.md Outdated
Comment thread src/Celerity.Benchmarks/CompressedIntSetBenchmark.cs Outdated
- CHANGELOG: condense the five CompressedIntSet bullets to two. The originals
  ran well past this repo's "brief and user-facing" convention, and an over-long
  section is a real release risk because release.yml lifts the whole version
  section into the GitHub Release body.
- CompressedIntSetBenchmark: the header claimed the sweep matched the headline
  workload "at ten times the scale". It is a tenth of it — 100k items over a 10M
  universe against the 1M/100M the claim is stated at. Reworded to say so, and to
  say what is actually preserved: the 100x universe ratio, so a chunk still lands
  in an array container exactly as it does at full scale.
- Two clarifying comments while in here: why the Add arm counts Optimize() against
  itself, and why the two counting queries probe rather than merge.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 1, 2026 01:58

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 21 out of 21 changed files in this pull request and generated no new comments.

Suppressed comments (3)

src/Celerity.Benchmarks/CompressedIntSetBenchmark.cs:107

  • Clustered() does not guarantee distinct keys and can also produce more than 32 blocks (e.g. when count is not divisible by Blocks). Because the benchmark builds sets from these arrays, duplicates reduce the actual set size below ItemCount, skewing both time and memory comparisons and making runs less reproducible.
    private static int[] Clustered(int seed, int count)
    {
        const int Blocks = 32;
        var rand = new Random(seed);
        int[] keys = new int[count];
        int perBlock = Math.Max(1, count / Blocks);
        int written = 0;
        while (written < count)
        {
            int origin = rand.Next(0, 100_000_000 - perBlock);
            for (int i = 0; i < perBlock && written < count; i++)
                keys[written++] = origin + i;
        }

src/Celerity/Collections/CompressedIntSet.cs:11

  • The says each chunk is stored in whichever of the three container forms is smallest, but run containers are only produced by Optimize() and AddRange (per the remarks). As written, the summary can read like run encoding happens automatically during normal inserts/removals, which isn’t true unless the caller opts into compression.
/// An <b>exact, compressed set of 32-bit integers</b> that partitions the value space into
/// 65,536-value chunks and stores each chunk in whichever of three container forms is smallest — a
/// sorted <c>ushort[]</c> when sparse, a 1024-word bitmap when dense, or run-length pairs when
/// clustered. It fills a BCL gap: .NET ships no compressed integer set, so the alternatives are

docs/api/collections.md:2137

  • This paragraph says each chunk is stored in whichever of the three container forms is smallest, but run containers are only produced by Optimize() and AddRange. Rewording here would avoid implying that run encoding is chosen automatically during ordinary single-element inserts/removals.
With that said: it is an **exact** set of 32-bit integers that partitions the value space into
**65,536-value chunks** and stores each chunk in whichever of three container forms is smallest.

Addresses the three findings in round 2 of the Copilot review on #337, all of
which arrived in the suppressed block.

Clustered() drew free-floating block origins over the whole 100M range, so two
blocks could overlap and emit duplicate keys — which silently shrinks the built
set below ItemCount and skews both the time and the memory comparison. It could
also emit more than 32 blocks when count was not divisible by 32. Blocks are now
laid one per fixed stride and jittered inside it, so they cannot overlap, every
key is distinct by construction, and the ceiling division caps it at 32 blocks.

The type summary and the docs said each chunk is stored in "whichever of three
container forms is smallest", which reads as though run encoding happens on an
ordinary insert. It does not — only Optimize() and AddRange produce it. Reworded
in the XML summary, docs/api/collections.md (including the container table's
"Chosen when" cell), the README, the web ship card, and the changelog, so the
opt-in nature is stated where a reader first meets the type rather than several
paragraphs later.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 1, 2026 02:08
@marius-bughiu

Copy link
Copy Markdown
Owner Author

Round 2 — the three suppressed comments

The review body says "no new comments", but three findings were in the suppressed block. All three were right; all three are fixed in 49355d2.

1. Clustered() could emit duplicate keys, and more than 32 blocks. Agreed, and this one actually mattered — it was drawing free-floating origins over the whole 100M range, so two blocks could overlap. Duplicates shrink the built set below ItemCount, which skews both the time and the memory comparison and makes the clustered arms less reproducible than the sparse and dense ones next to them. The block count was also count / Blocks rounded down, so a count not divisible by 32 needed a 33rd pass.

Blocks are now laid one per fixed stride (100_000_000 / 32) and jittered inside it, so block b is confined to [b·Stride, (b+1)·Stride) and cannot touch its neighbour. Distinct by construction — no dedup pass, no rejection loop — and the ceiling division caps it at exactly 32 blocks. Verified at both sweep points: 1,000 → 32 keys/block, 100,000 → 3,125 keys/block.

2 & 3. The <summary> and the docs implied run encoding is automatic. Also agreed, and worth more than a one-line fix: the XML summary is what shows in IntelliSense, so "whichever of three container forms is smallest" was the first thing a caller read, with the "actually, run encoding is opt-in" correction several paragraphs down in the remarks. That is exactly backwards for a contract a caller has to act on.

Reworded so the opt-in nature appears where the reader first meets the type — in the XML summary, in docs/api/collections.md (including the container table's "Chosen when" cell, which now names Optimize() / AddRange as part of the condition), in the README bullet and the details block, in the web ship card, and in the changelog. The wording is consistent across all five now.

Re-verified after the change: build clean, 5,220 tests pass, check_dashboard_coverage.js green.

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 21 out of 21 changed files in this pull request and generated no new comments.

Suppressed comments (2)

src/Celerity/Collections/CompressedIntSet.cs:439

  • IntersectWith(IEnumerable<int>) falls back to SetOperations.IntersectWith(this, other), but SetOperations reads self.Count for its empty/self checks. For CompressedIntSet, Count intentionally throws once _cardinality > int.MaxValue, so intersecting a large set (e.g. built via AddRange(int.MinValue, int.MaxValue)) with a plain sequence will throw OverflowException even though the intersection is computable. The same pattern affects other fallbacks that call into SetOperations (subset/equality/overlaps) whenever _cardinality exceeds int.MaxValue.

Consider handling the overflow case in CompressedIntSet before calling SetOperations (e.g., build the result by streaming distinct elements of other and probing Contains), and add a regression test for this scenario.

            return;
        }

        SetOperations.IntersectWith(this, other);
    }

src/Celerity/Collections/CompressedIntSet.cs:574

  • Overlaps(IEnumerable<int>) falls back to SetOperations.Overlaps(this, other), which reads self.Count internally. Since CompressedIntSet.Count can throw when _cardinality > int.MaxValue, Overlaps can also throw OverflowException for large sets even though it only needs to stream other and probe membership. Implementing the fallback inline avoids the Count dependency and keeps the method usable at the full 32-bit cardinality this type supports.
        if (other is CompressedIntSet o)
            return OverlapsCore(o);

        return SetOperations.Overlaps(this, other);
    }

….MaxValue

Addresses round 3 of the Copilot review on #337 (both findings arrived in the
suppressed block, and both were real bugs).

Count throws OverflowException once the set holds more than int.MaxValue
elements — deliberate, since the type can hold all 2^32 int values and
ICollection<T>.Count cannot express that. But six of the IEnumerable<int>
fallbacks routed through SetOperations, which compares self.Count for its
empty/size checks, so IntersectWith, IsSubsetOf, IsProperSubsetOf,
IsProperSupersetOf, Overlaps and SetEquals all threw on a set built with a wide
AddRange — even though every one of those answers is trivially computable there.
Copilot flagged IntersectWith and Overlaps; the same defect covered four more.

Each of the six now compares against the long Cardinality instead. IntersectWith
in particular no longer snapshots this set into a List<T> (which a >2^31 set
cannot fill either) — it builds the survivors from `other`, which is bounded by
`other` and correct at any cardinality.

SymmetricExceptWith and IsSupersetOf still go through SetOperations: neither
reads Count, so the shared family implementation stays the single source of
those semantics. The comment above the region records which are shared, which
are not, and why, so the divergence reads as a decision.

Regression test drives the whole query surface plus IntersectWith against a set
built with AddRange(int.MinValue, int.MaxValue), asserting Count still throws
while every operation answers. Coverage stays at 100% line / 100% branch.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 1, 2026 02:20
@marius-bughiu

Copy link
Copy Markdown
Owner Author

Round 3 — both suppressed comments were real bugs

Fixed in dbafde3. These were the good kind of review finding: a defect I created by combining two things that were each fine on their own.

Count throws OverflowException past int.MaxValue deliberately — the type can hold all 2^32 int values and ICollection<T>.Count cannot express that, which is why Cardinality exists. But the IEnumerable<int> fallbacks routed through SetOperations, and SetOperations compares self.Count for its empty/size checks. So on a set built with a wide AddRange, those operations threw — even though every answer is trivially computable from the cardinality.

Copilot named IntersectWith and Overlaps. Checking SetOperations for self.Count turned up six affected methods, not two:

reads self.Count fixed
IntersectWith L61 (and snapshots into a List<T>)
IsSubsetOf L109, L113
IsProperSubsetOf L122
IsProperSupersetOf L144, L147
Overlaps L160
SetEquals L175
IsSupersetOf — streams other against Contains unchanged
SymmetricExceptWith Remove/Add only unchanged

Each of the six now compares the long Cardinality. IntersectWith needed more than a comparison swap: SetOperations snapshots the set into a List<T> before mutating, which a set past int.MaxValue cannot fill either. It now builds the survivors from other instead — bounded by other, correct at any cardinality, and it also means the common small-other case stops allocating a snapshot of the whole set.

IsSupersetOf and SymmetricExceptWith deliberately still go through SetOperations: neither reads Count, so the shared helper stays the single source of those semantics rather than diverging for symmetry's sake. The comment above the region now records which are shared, which are not, and why, so a future reader sees a decision instead of drift.

Regression test (SetAlgebra_ShouldStillAnswer_WhenTheSetHoldsMoreElementsThanAnInt32) builds a set with AddRange(int.MinValue, int.MaxValue), asserts Count still throws, and then drives all six operations plus IntersectWith to a correct answer. Coverage holds at 100% line / 100% branch; 5,222 tests pass, fuzz and the AOT smoke test re-run clean.

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 21 out of 21 changed files in this pull request and generated no new comments.

Suppressed comments (2)

src/Celerity/Collections/CompressedIntSet.cs:638

  • CopyTo evaluates Count before validating array/arrayIndex, so if the set is large enough for Count to throw OverflowException you’ll get an overflow even when the caller passed array: null or an out-of-range arrayIndex. That contradicts the stated “matches HashSet.CopyTo argument validation” behavior in docs and makes argument-validation ordering inconsistent.

Consider validating array and arrayIndex first, then checking Count (or _cardinality) afterward.

    public void CopyTo(int[] array, int arrayIndex) => SetOperations.CopyTo(this, Count, array, arrayIndex);

web/index.html:296

  • The new landing-page blurb says the run-length form is applied by Optimize() only, but the public contract (and docs/tests in this PR) also say AddRange produces run containers on fresh chunks. The description should mention AddRange as well to avoid misleading callers about when run encoding is used.
    <div class="ship"><code>CompressedIntSet</code><div class="desc">Exact compressed set of 32-bit integers: each 65,536-value chunk is stored as a sorted array or a bitmap by density, with an opt-in run-length form that Optimize() applies to clustered data. Set algebra runs word-parallel inside a chunk and skips a whole chunk with one comparison, and enumeration is in ascending order. For huge-and-sparse integer sets — posting lists, row-id sets, cohort intersection — where HashSet&lt;int&gt; costs ~10x the memory and one hash probe per element. No portable Roaring format: this is an in-process structure, not an interop codec.</div></div>

…e Count guard

Addresses round 4 of the Copilot review on #337, plus a coverage-fragility problem
found while verifying the fix.

CopyTo passed Count as an argument to SetOperations.CopyTo, and C# evaluates
arguments before the call — so on a set past int.MaxValue the overflow guard fired
before any argument was checked, turning CopyTo(null, 0) into an OverflowException
instead of an ArgumentNullException. It is now written out and compares the long
_cardinality, which restores HashSet<int>.CopyTo's validation order and reports a
set too large for an int[] as insufficient space rather than as an overflow. Same
reasoning as the six set operations in dbafde3.

The web ship card said the run-length form comes from Optimize() alone; AddRange
produces it too on a fresh chunk. Corrected there and in the three other short
blurbs that had the same omission (README bullet, README details block, changelog).

While re-measuring, coverage of this type turned out to depend on the randomized
CsCheck differential test: excluding it left eight branches uncovered, so the
repo's 100% gate was passing on luck and could have flaked on any later run. Each
is now pinned by a deterministic test — the mid-merge and trailing arms of the
union / symmetric-except chunk walks, both rejection paths in IsSubsetOfCore, both
skip directions in OverlapsCore, and the word-aligned high mask in AddRange.
Coverage is 100% line / 100% branch with the property test excluded entirely.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 1, 2026 02:34
@marius-bughiu

Copy link
Copy Markdown
Owner Author

Round 4 — both fixed, plus a coverage problem the fix exposed

Fixed in b56e88b.

1. CopyTo evaluated Count before validating its arguments. Right, and the cause is subtle enough to be worth naming: CopyTo passed Count as an argument to SetOperations.CopyTo, and C# evaluates arguments before the call — so the overflow guard fired before ArgumentNullException.ThrowIfNull(array) ever ran. CopyTo(null, 0) on a large set threw OverflowException. It is now written out and compares the long _cardinality, which restores HashSet<int>.CopyTo's validation order and makes a set too large for an int[] report insufficient space — the honest answer — instead of overflowing. Same reasoning as the six operations in dbafde3, so the divergence from SetOperations is at least consistent now.

2. The ship card credited only Optimize() for run encoding. Correct — AddRange produces a run container on a fresh chunk, which is the whole reason AddRange(int.MinValue, int.MaxValue) fits in a few megabytes. Fixed on the card and in the three other short blurbs that had drifted the same way (README bullet, README details block, changelog); the API reference and the XML docs already named both.

3. Something the fix turned up: this type's coverage was passing on luck.

Re-measuring after the CopyTo change, coverage dropped below 100% — but on branches I had not touched. Running the suite with CompressedIntSetDifferentialTests excluded explained it: eight branches were only ever being reached by the randomized CsCheck test. The repo gates on 100% branch coverage, so that gate was one unlucky property-test draw away from failing CI on an unrelated PR.

Each is now pinned by a deterministic [Fact]:

  • the mid-merge and trailing arms of the union and symmetric-except chunk walks (a chunk adopted while both indices are live is a different path from one drained by the tail loop);
  • both rejection paths in IsSubsetOfCore — the counterpart chunk being absent, and it being present but smaller;
  • both skip directions in OverlapsCore;
  • the word-aligned high mask in AddRange, where a range ending exactly on a 64-bit boundary fills the closing word whole.

dotnet test --filter "FullyQualifiedName!~CompressedIntSetDifferentialTests" now reports 100% line / 100% branch. The property test still runs and still earns its place — it just is not load-bearing for the gate any more.

5,228 tests pass on all three TFMs; fuzz and the AOT smoke test re-run clean.

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 21 out of 21 changed files in this pull request and generated no new comments.

Suppressed comments (2)

src/Celerity/Collections/CompressedIntSet.cs:316

  • The Clear() XML doc says it “releases every container”, but the implementation preserves the chunk-index capacity (like other sets preserve capacity on Clear). This can be surprising alongside MemoryUsageInBytes, which includes _chunks.Length and therefore may remain large after Clear(). Consider clarifying the doc comment to match the actual behavior: container payloads are released, but index capacity is preserved.
    /// <summary>
    /// Removes all elements from the set, releasing every container. A <see cref="Clear"/> on an
    /// already-empty set changes nothing and leaves active enumerators valid.
    /// </summary>

docs/api/collections.md:2231

  • The docs claim Clear() “releases every container”, but the implementation keeps the chunk-index array allocated (capacity preserved), and MemoryUsageInBytes counts that capacity. Consider clarifying this bullet to reflect that only per-chunk payloads are released, not necessarily all retained capacity.
- `void Clear()` — empties the set and releases every container. A `Clear()` on an already-empty
  set changes nothing and leaves active enumerators valid.

Addresses round 5 of the Copilot review on #337 (both suppressed comments made the
same point about two doc surfaces).

Clear() was documented as "releasing every container". It does drop every container
payload, but the chunk index keeps its capacity so the set can be refilled without
regrowing it — and MemoryUsageInBytes counts that capacity, so the reported
footprint does not fall to zero after a Clear(). Anyone comparing the number before
and after would have concluded the release had not happened.

The XML doc, the API-reference bullet, and the MemoryUsageInBytes doc now say so,
and point at Optimize() as the way to hand the index back. A test pins it, so the
claim is checked rather than asserted: after Clear() the footprint is non-zero, and
after Optimize() it is exactly zero.

Coverage holds at 100% line / 100% branch with the property test excluded.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 1, 2026 02:41
@marius-bughiu

Copy link
Copy Markdown
Owner Author

Round 5 — fixed in 962a770

Both suppressed comments made the same point about two doc surfaces, and it was a real inaccuracy rather than a wording nit.

Clear() was documented as "releasing every container". It does drop every container payload — the chunk entries are cleared, so the ushort[] and ulong[] payloads become collectable — but the chunk index keeps its capacity so the set can be refilled without regrowing it, and MemoryUsageInBytes counts that capacity. So a caller who measured the footprint before and after a Clear() would have seen it stay non-zero and concluded the release had not happened.

The XML doc, the API-reference bullet, and the MemoryUsageInBytes doc now state it, and point at Optimize() as the way to hand the index back. Added a test so the claim is checked rather than asserted: after Clear() the footprint is non-zero and below one bitmap's worth, and after Optimize() it is exactly zero.

Coverage holds at 100% line / 100% branch with the property test excluded; 5,226 tests pass.

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 21 out of 21 changed files in this pull request and generated no new comments.

Suppressed comments (2)

src/Celerity.Benchmarks/CompressedIntSetBenchmark.cs:16

  • The header comment equates BenchmarkDotNet’s MemoryDiagnoser “Allocated” metric with steady-state footprint. “Allocated” is total bytes allocated during the benchmark invocation (including transient allocations from resizes/optimizations), so calling it the settled footprint is misleading—especially in the Add category where both implementations can resize internally.
//   * Memory. [MemoryDiagnoser] is on and the Add category constructs the whole set, so the
//     Allocated column is the steady-state footprint of each representation rather than incidental
//     garbage. That column is half the reason to use this type.

src/Celerity.Benchmarks/CompressedIntSetBenchmark.cs:126

  • HashSet_Add currently starts from an empty HashSet, which forces internal growth/resizes and inflates both time and the MemoryDiagnoser “Allocated” metric. Pre-sizing makes the baseline fairer and makes “Allocated” closer to the table’s intended memory signal.
    public int HashSet_Add()
    {
        var set = new HashSet<int>();
        foreach (int key in sparseKeys)
            set.Add(key);

…tate footprint

Addresses round 6 of the Copilot review on #337.

The header claimed the Add category's Allocated column was "the steady-state
footprint of each representation". It is not: BenchmarkDotNet reports total bytes
allocated per operation, so it includes every intermediate array a growing
collection discards on the way up. The column is still the right relative signal —
both arms start empty and grow, so both pay it — but it is an upper bound, not the
settled size. Reworded to say that, and to point at MemoryUsageInBytes and the
ROADMAP heap measurements for the settled figure.

The same comment now also records why neither arm is pre-sized, which was the
review's other suggestion and is declined on purpose: pre-sizing only the HashSet
arm would hand the baseline an advantage the Celerity arm structurally cannot take,
since CompressedIntSet has no capacity constructor — it has no table to size. Every
other set benchmark in the suite pairs an unsized BCL arm with an unsized Celerity
arm, and this one matches.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 1, 2026 02:50
@marius-bughiu

Copy link
Copy Markdown
Owner Author

Round 6 — one fixed, one declined

Fixed in 1527583.

1. "Allocated" is not a steady-state footprint. Agreed. The header claimed the Add category's Allocated column was the settled footprint of each representation. It is not — BenchmarkDotNet reports total bytes allocated per operation, so it includes every intermediate array a growing collection discards on the way up. The column is still the right relative signal, since both arms grow the same way, but it is an upper bound and I should not have called it the settled size. Reworded, and it now points at MemoryUsageInBytes and the ROADMAP heap measurements for the actual figure.

2. Pre-sizing the HashSet arm — declining, with reasoning.

The suggestion is that starting HashSet_Add from empty inflates its time and its Allocated, and that pre-sizing would make the baseline fairer. The first half is true; the conclusion does not follow, for two reasons.

CompressedIntSet has no capacity constructor — there is no table to pre-size, which is a property of the structure rather than a gap in the API. So pre-sizing is not something both arms can do. Doing it to only the BCL arm would hand the baseline an advantage the Celerity arm structurally cannot take, which moves the comparison further from fair, not closer.

It would also make this the only set card in the suite that does it. IntSetBenchmark, CeleritySetBenchmark, SwissSetBenchmark and the rest all pair new HashSet<int>() with an unsized Celerity set, precisely so the two arms pay the same growth cost. A card that measured a different thing from its neighbours would be misread on a dashboard that puts them side by side.

The real problem the comment points at is the claim, not the setup — and that is what (1) fixes. Both arms grow from empty, both pay for their resizes, and the column is now described as the comparable upper bound it is. The reasoning is recorded in the benchmark's own header so the next reader sees a decision rather than an oversight.

Happy to be overruled if you would rather the Add category measure pre-sized construction on both sides — that would mean giving CompressedIntSet a capacity constructor first, which is a design question rather than a benchmark one.

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 21 out of 21 changed files in this pull request and generated no new comments.

Suppressed comments (2)

src/Celerity/Collections/CompressedIntSet.cs:247

  • The XML docs imply the range is “four bytes” in storage, but the implementation allocates a ushort[] for the run pair (so there is managed array overhead in addition to the 4-byte payload). Consider clarifying that this is 4 bytes of payload (two ushorts), excluding object/array overhead, to avoid misleading callers about actual heap usage.
    /// A range that lands in a chunk the set does not yet touch is stored as a single run pair —
    /// four bytes, whatever the range's width — which is why this is the cheap way to build a
    /// clustered set. A range overlapping an existing chunk merges into it and the chunk is left in

docs/api/collections.md:2228

  • The docs say a fresh-chunk range add is “four bytes”, but the run pair is stored in a managed ushort[] (so the 4 bytes is the payload, not the full heap cost). Clarifying this avoids readers interpreting it as the exact allocation size.
- `long AddRange(int start, int endInclusive)` — adds every value in the inclusive range and
  returns how many were **new**. A range landing in a chunk the set does not yet touch is stored as
  a **single run pair — four bytes, whatever the range's width** — so this is the cheap way to
  build a clustered set. Throws `ArgumentOutOfRangeException` if `endInclusive < start`.

… range add

Addresses round 7 of the Copilot review on #337 (one point, on two doc surfaces).

"A range in a fresh chunk is four bytes, whatever its width" described the run
pair's payload, not its heap cost — the pair lives in a ushort[], which carries an
array header. Both surfaces now say "four bytes of payload" and note the header,
matching how MemoryUsageInBytes already documents its own exclusion. The claim the
sentence exists to make — that the cost is independent of the range's width — is
unchanged and still true.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 1, 2026 02:57
@marius-bughiu

Copy link
Copy Markdown
Owner Author

Round 7 — fixed in 26ba6a7

One point, on two doc surfaces, and it is a fair precision catch: "a range in a fresh chunk is four bytes, whatever its width" described the run pair's payload, not its heap cost — the pair lives in a ushort[], which carries an array header.

Both surfaces now say "four bytes of payload" and note the header, which matches how MemoryUsageInBytes already documents its own exclusion, so the two read consistently. The claim the sentence exists to make — that the cost is independent of the range's width, which is what makes AddRange the cheap way to build a clustered set — is unchanged and still true.

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 21 out of 21 changed files in this pull request and generated no new comments.

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown

Benchmarks

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

Highlights

Benchmark This PR StdDev main Δ
EnumMapBenchmark.EnumMap_Add 108.8 ns 0.1 ns 156.1 ns -30.3% ✅
SmallSetBenchmark.SmallSet_Add(ItemCount: 8) 58.3 ns 1.3 ns 47.9 ns +21.8% ⚠️
SmallSetBenchmark.SmallSet_Contains(ItemCount: 64) 924.8 ns 11.1 ns 1.09 μs -15.2% ✅
IndexedPriorityQueueBenchmark.PriorityQueue_DecreaseKey(ItemCount: 1000) 76.43 μs 299.9 ns 146.38 μs -47.8% ✅
IndexedPriorityQueueBenchmark.IndexedPriorityQueue_DecreaseKey(ItemCount: 1000) 187.93 μs 971.1 ns 262.47 μs -28.4% ✅
EnumMapBenchmark.Dictionary_Enumerate 43.0 ns 0.1 ns 50.5 ns -14.8% ✅
CelerityMultiMapBenchmark.Dictionary_Insert(ItemCount: 1000) 27.08 μs 286.2 ns 30.19 μs -10.3% ✅
EnumMapBenchmark.Dictionary_Lookup 135.8 ns 0.1 ns 117.9 ns +15.1% ⚠️
EnumMapBenchmark.EnumMap_Lookup 69.9 ns 0.2 ns 63.1 ns +10.7% ⚠️
CelerityMultiMapBenchmark.Dictionary_Remove(ItemCount: 100000) 2.03 ms 154.85 μs 2.77 ms -26.8% ✅
CelerityMultiMapBenchmark.CelerityMultiMap_Remove(ItemCount: 100000) 1.93 ms 63.70 μs 2.49 ms -22.3% ✅
LongSetBenchmark.HashSet_Add(ItemCount: 1000) 14.95 μs 660.0 ns 13.51 μs +10.7% ⚠️
CelerityDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 13.95 μs 162.1 ns 10.58 μs +31.9% ⚠️
CelerityDictionaryBenchmark.CelerityDictionary_Insert(ItemCount: 1000) 12.19 μs 187.4 ns 8.09 μs +50.7% ⚠️
CelerityDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 4.25 ms 76.22 μs 3.62 ms +17.4% ⚠️
CelerityDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.72 μs 14.4 ns 3.05 μs +54.8% ⚠️
CelerityDictionaryBenchmark.CelerityDictionary_Lookup(ItemCount: 1000) 2.48 μs 11.0 ns 1.89 μs +31.2% ⚠️
CelerityDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.60 ms 8.23 μs 1.30 ms +22.8% ⚠️
CelerityDictionaryBenchmark.CelerityDictionary_Lookup(ItemCount: 100000) 736.56 μs 1.03 μs 644.43 μs +14.3% ⚠️
StringKeyProbeBenchmark.CelerityDictionary_LookupMissing(ItemCount: 100000) 6.01 ms 277.38 μs 5.36 ms +12.2% ⚠️
CelerityDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 83.58 μs 6.41 μs 60.85 μs +37.3% ⚠️
CelerityDictionaryBenchmark.CelerityDictionary_Remove(ItemCount: 1000) 124.48 μs 7.15 μs 99.56 μs +25.0% ⚠️
CelerityDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.05 ms 16.94 μs 1.62 ms +26.6% ⚠️
CeleritySetBenchmark.HashSet_Add(ItemCount: 1000) 9.46 μs 137.9 ns 12.07 μs -21.7% ✅
CuckooFilterBenchmark.HashSet_Add(ItemCount: 1000) 9.87 μs 152.5 ns 12.72 μs -22.5% ✅
HyperLogLogBenchmark.HashSet_Add(ItemCount: 1000) 9.64 μs 79.4 ns 10.70 μs -9.9% ✅
CeleritySetBenchmark.CeleritySet_Add(ItemCount: 1000) 7.58 μs 70.5 ns 8.77 μs -13.6% ✅
CuckooFilterBenchmark.CuckooFilter_Add(ItemCount: 1000) 5.13 μs 34.7 ns 7.14 μs -28.2% ✅
CeleritySetBenchmark.HashSet_Add(ItemCount: 100000) 3.93 ms 259.29 μs 5.06 ms -22.3% ✅
CuckooFilterBenchmark.HashSet_Add(ItemCount: 100000) 3.63 ms 87.90 μs 4.70 ms -22.8% ✅
RankSelectBitVectorBenchmark.Array_Build(ItemCount: 1024) 82.4 ns 1.1 ns 90.9 ns -9.4% ✅
RankSelectBitVectorBenchmark.Array_Build(ItemCount: 1000000) 46.27 μs 522.5 ns 67.96 μs -31.9% ✅
RankSelectBitVectorBenchmark.RankSelectBitVector_Build(ItemCount: 1000000) 65.69 μs 1.86 μs 87.49 μs -24.9% ✅
CeleritySetBenchmark.HashSet_Contains(ItemCount: 1000) 3.01 μs 10.5 ns 4.76 μs -36.8% ✅
CuckooFilterBenchmark.HashSet_Contains(ItemCount: 1000) 3.02 μs 3.9 ns 4.73 μs -36.1% ✅
CeleritySetBenchmark.CeleritySet_Contains(ItemCount: 1000) 1.55 μs 6.9 ns 2.08 μs -25.1% ✅
CuckooFilterBenchmark.CuckooFilter_Contains(ItemCount: 1000) 3.63 μs 3.6 ns 4.91 μs -26.1% ✅
CeleritySetBenchmark.HashSet_Contains(ItemCount: 100000) 1.26 ms 4.28 μs 1.58 ms -20.6% ✅
CuckooFilterBenchmark.HashSet_Contains(ItemCount: 100000) 1.24 ms 8.04 μs 1.60 ms -22.1% ✅
CeleritySetBenchmark.CeleritySet_Contains(ItemCount: 100000) 515.68 μs 4.13 μs 593.11 μs -13.1% ✅
CuckooFilterBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 3.06 μs 8.1 ns 4.54 μs -32.5% ✅
CuckooFilterBenchmark.CuckooFilter_ContainsMissing(ItemCount: 1000) 6.10 μs 22.5 ns 8.43 μs -27.7% ✅
CuckooFilterBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 1.64 ms 7.26 μs 1.93 ms -15.2% ✅
CuckooFilterBenchmark.CuckooFilter_ContainsMissing(ItemCount: 100000) 700.07 μs 3.01 μs 879.18 μs -20.4% ✅
LruCacheBenchmark.LruCache_Get(ItemCount: 1000) 5.03 μs 47.8 ns 6.80 μs -26.0% ✅
LruCacheBenchmark.LruCache_Get(ItemCount: 100000) 5.11 μs 104.1 ns 7.01 μs -27.0% ✅
LruCacheBenchmark.Dictionary_GetMissing(ItemCount: 1000) 3.28 μs 21.7 ns 4.83 μs -31.9% ✅
LruCacheBenchmark.LruCache_GetMissing(ItemCount: 1000) 3.98 μs 26.1 ns 3.60 μs +10.6% ⚠️
LruCacheBenchmark.Dictionary_GetMissing(ItemCount: 100000) 392.78 μs 1.75 μs 557.92 μs -29.6% ✅
LruCacheBenchmark.LruCache_GetMissing(ItemCount: 100000) 1.49 ms 3.83 μs 1.34 ms +11.1% ⚠️
PooledCelerityDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 10.57 μs 121.6 ns 13.63 μs -22.5% ✅
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Insert(ItemCount: 1000) 6.56 μs 56.4 ns 8.09 μs -18.9% ✅
PooledCelerityDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 3.80 ms 259.72 μs 4.89 ms -22.2% ✅
PooledCelerityDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 2.98 μs 15.9 ns 4.72 μs -36.8% ✅
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Lookup(ItemCount: 1000) 1.93 μs 15.8 ns 2.59 μs -25.5% ✅
PooledCelerityDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.28 ms 9.11 μs 1.60 ms -19.5% ✅
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Lookup(ItemCount: 100000) 644.52 μs 10.68 μs 714.29 μs -9.8% ✅
LruCacheBenchmark.Dictionary_Put(ItemCount: 1000) 70.73 μs 4.36 μs 121.64 μs -41.9% ✅
LruCacheBenchmark.LruCache_Put(ItemCount: 1000) 290.04 μs 14.46 μs 468.65 μs -38.1% ✅
LruCacheBenchmark.Dictionary_Put(ItemCount: 100000) 5.60 ms 105.69 μs 8.20 ms -31.7% ✅
RankSelectBitVectorBenchmark.RankSelectBitVector_RankEarly(ItemCount: 1024) 1.52 μs 40.3 ns 1.88 μs -19.3% ✅
RankSelectBitVectorBenchmark.Array_RankEarly(ItemCount: 1000000) 43.33 μs 474.4 ns 32.76 μs +32.3% ⚠️
RankSelectBitVectorBenchmark.RankSelectBitVector_RankEarly(ItemCount: 1000000) 1.48 μs 27.5 ns 1.88 μs -21.0% ✅
RankSelectBitVectorBenchmark.Array_RankLate(ItemCount: 1024) 8.10 μs 82.7 ns 6.44 μs +25.8% ⚠️
RankSelectBitVectorBenchmark.RankSelectBitVector_RankLate(ItemCount: 1024) 1.44 μs 8.0 ns 1.88 μs -23.5% ✅
RankSelectBitVectorBenchmark.Array_RankLate(ItemCount: 1000000) 6.54 ms 67.92 μs 4.87 ms +34.3% ⚠️
RankSelectBitVectorBenchmark.RankSelectBitVector_RankLate(ItemCount: 1000000) 1.44 μs 3.4 ns 1.88 μs -23.3% ✅
RankSelectBitVectorBenchmark.RankSelectBitVector_RankMid(ItemCount: 1024) 1.47 μs 26.0 ns 1.88 μs -21.5% ✅
RankSelectBitVectorBenchmark.Array_RankMid(ItemCount: 1000000) 3.39 ms 53.81 μs 2.47 ms +37.0% ⚠️
RankSelectBitVectorBenchmark.RankSelectBitVector_RankMid(ItemCount: 1000000) 1.46 μs 20.5 ns 1.88 μs -22.5% ✅
CeleritySetBenchmark.HashSet_Remove(ItemCount: 1000) 22.93 μs 2.65 μs 32.77 μs -30.0% ✅
PooledCelerityDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 60.38 μs 7.99 μs 79.96 μs -24.5% ✅
CeleritySetBenchmark.CeleritySet_Remove(ItemCount: 1000) 96.80 μs 10.95 μs 122.15 μs -20.8% ✅
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Remove(ItemCount: 1000) 102.13 μs 8.03 μs 127.74 μs -20.0% ✅
CuckooFilterBenchmark.HashSet_Remove(ItemCount: 1000) 10.12 μs 44.6 ns 13.00 μs -22.1% ✅
CuckooFilterBenchmark.CuckooFilter_Remove(ItemCount: 1000) 9.26 μs 41.8 ns 12.85 μs -28.0% ✅
CeleritySetBenchmark.HashSet_Remove(ItemCount: 100000) 1.46 ms 53.05 μs 1.70 ms -14.4% ✅
PooledCelerityDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 1.61 ms 31.66 μs 2.05 ms -21.2% ✅
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Remove(ItemCount: 100000) 6.68 ms 95.43 μs 1.60 ms +318.2% ⚠️
CuckooFilterBenchmark.HashSet_Remove(ItemCount: 100000) 2.88 ms 12.66 μs 3.77 ms -23.7% ✅
RankSelectBitVectorBenchmark.Array_Select(ItemCount: 1024) 10.14 μs 102.5 ns 13.00 μs -22.0% ✅
RankSelectBitVectorBenchmark.RankSelectBitVector_Select(ItemCount: 1024) 8.85 μs 84.5 ns 11.41 μs -22.4% ✅
RankSelectBitVectorBenchmark.RankSelectBitVector_Select(ItemCount: 1000000) 66.25 μs 571.9 ns 25.81 μs +156.7% ⚠️
BTreeDictionaryBenchmark.SortedDictionary_Add(ItemCount: 1000) 59.60 μs 1.05 μs 89.81 μs -33.6% ✅
BTreeDictionaryBenchmark.BTreeDictionary_Add(ItemCount: 1000) 53.75 μs 272.1 ns 64.75 μs -17.0% ✅
BTreeDictionaryBenchmark.SortedDictionary_Lookup(ItemCount: 1000) 39.36 μs 2.44 μs 52.48 μs -25.0% ✅
BTreeDictionaryBenchmark.BTreeDictionary_Lookup(ItemCount: 1000) 25.70 μs 73.2 ns 44.70 μs -42.5% ✅
BTreeDictionaryBenchmark.SortedDictionary_Mixed(ItemCount: 1000) 186.53 μs 2.34 μs 213.64 μs -12.7% ✅
BTreeDictionaryBenchmark.BTreeDictionary_Mixed(ItemCount: 1000) 86.21 μs 4.85 μs 131.14 μs -34.3% ✅
BTreeDictionaryBenchmark.SortedDictionary_RangeScan(ItemCount: 1000) 4.50 μs 12.4 ns 3.74 μs +20.4% ⚠️
BTreeDictionaryBenchmark.BTreeDictionary_RangeScan(ItemCount: 1000) 77.9 ns 0.5 ns 62.5 ns +24.6% ⚠️
BTreeDictionaryBenchmark.BTreeDictionary_RangeScan(ItemCount: 100000) 5.95 μs 160.0 ns 4.43 μs +34.2% ⚠️
BTreeDictionaryBenchmark.SortedDictionary_Remove(ItemCount: 1000) 786.37 μs 16.43 μs 570.46 μs +37.8% ⚠️
BTreeDictionaryBenchmark.BTreeDictionary_Remove(ItemCount: 1000) 313.12 μs 12.66 μs 228.16 μs +37.2% ⚠️
LongDictionaryBenchmark.LongDictionary_Remove(ItemCount: 100000) 6.84 ms 83.54 μs 1.64 ms +317.0% ⚠️
BloomFilterBenchmark.BloomFilter_Add(ItemCount: 1000) 14.49 μs 13.0 ns 16.38 μs -11.5% ✅
BloomFilterBenchmark.BloomFilter_Add(ItemCount: 100000) 1.10 ms 2.25 μs 1.24 ms -11.2% ✅
FrozenCeleritySetBenchmark.FrozenCeleritySet_Build(ItemCount: 1000) 2.64 ms 91.80 μs 2.25 ms +17.3% ⚠️
BloomFilterBenchmark.BloomFilter_Contains(ItemCount: 1000) 12.52 μs 5.1 ns 14.18 μs -11.7% ✅
FrozenCeleritySetBenchmark.FrozenCeleritySet_Contains(ItemCount: 1000) 94.17 μs 3.99 μs 79.49 μs +18.5% ⚠️
BloomFilterBenchmark.BloomFilter_Contains(ItemCount: 100000) 869.25 μs 649.8 ns 982.54 μs -11.5% ✅
FrozenCeleritySetBenchmark.FrozenCeleritySet_Contains(ItemCount: 100000) 7.36 ms 15.10 μs 8.17 ms -10.0% ✅
BloomFilterBenchmark.BloomFilter_ContainsMissing(ItemCount: 1000) 3.52 μs 8.6 ns 3.98 μs -11.5% ✅
BloomFilterBenchmark.BloomFilter_ContainsMissing(ItemCount: 100000) 1.49 ms 790.9 ns 1.67 ms -10.6% ✅
CelerityMultiSetBenchmark.CelerityMultiSet_Lookup(ItemCount: 1000) 1.72 μs 1.4 ns 1.95 μs -11.8% ✅
CelerityMultiSetBenchmark.Dictionary_Lookup(ItemCount: 100000) 650.80 μs 780.4 ns 558.84 μs +16.5% ⚠️
CelerityMultiSetBenchmark.CelerityMultiSet_Lookup(ItemCount: 100000) 189.94 μs 288.0 ns 215.19 μs -11.7% ✅
SwissDictionaryBenchmark.SwissDictionary_Lookup(ItemCount: 100000) 802.28 μs 5.50 μs 676.49 μs +18.6% ⚠️
FenwickTreeBenchmark.Array_RangeSum(ItemCount: 1000) 223.39 μs 375.3 ns 248.97 μs -10.3% ✅
FenwickTreeBenchmark.Array_RangeSum(ItemCount: 100000) 209.67 ms 12.59 ms 178.79 ms +17.3% ⚠️
FenwickTreeBenchmark.FenwickTree_RangeSum(ItemCount: 100000) 324.59 μs 1.20 μs 209.29 μs +55.1% ⚠️
SwissDictionaryBenchmark.SwissDictionary_Remove(ItemCount: 1000) 79.62 μs 4.09 μs 69.88 μs +13.9% ⚠️
CelerityMultiSetBenchmark.CelerityMultiSet_Remove(ItemCount: 100000) 1.26 ms 21.18 μs 1.42 ms -10.9% ✅
SwissDictionaryBenchmark.SwissDictionary_Remove(ItemCount: 100000) 1.62 ms 34.38 μs 1.30 ms +25.1% ⚠️
EnumSetBenchmark.HashSet_Add 567.9 ns 7.4 ns 625.0 ns -9.1% ✅
XorFilterBenchmark.HashSet_Build(ItemCount: 1000) 7.96 μs 47.5 ns 6.19 μs +28.7% ⚠️
XorFilterBenchmark.XorFilter_Build(ItemCount: 1000) 39.32 μs 291.1 ns 33.17 μs +18.5% ⚠️
XorFilterBenchmark.HashSet_Build(ItemCount: 100000) 2.12 ms 35.58 μs 1.60 ms +32.2% ⚠️
XorFilterBenchmark.XorFilter_Build(ItemCount: 100000) 12.42 ms 249.43 μs 9.45 ms +31.4% ⚠️
XorFilterBenchmark.HashSet_Contains(ItemCount: 1000) 4.74 μs 34.8 ns 3.05 μs +55.3% ⚠️
XorFilterBenchmark.XorFilter_Contains(ItemCount: 1000) 6.77 μs 3.1 ns 5.31 μs +27.6% ⚠️
XorFilterBenchmark.HashSet_Contains(ItemCount: 100000) 1.60 ms 7.15 μs 1.27 ms +25.7% ⚠️
XorFilterBenchmark.XorFilter_Contains(ItemCount: 100000) 703.71 μs 378.3 ns 570.81 μs +23.3% ⚠️
XorFilterBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 4.54 μs 4.5 ns 3.14 μs +44.7% ⚠️
XorFilterBenchmark.XorFilter_ContainsMissing(ItemCount: 1000) 6.78 μs 11.7 ns 5.36 μs +26.4% ⚠️
XorFilterBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 1.91 ms 17.79 μs 1.62 ms +18.4% ⚠️
XorFilterBenchmark.XorFilter_ContainsMissing(ItemCount: 100000) 705.44 μs 701.1 ns 579.73 μs +21.7% ⚠️
SmallDictionaryBenchmark.Dictionary_Insert(ItemCount: 8) 162.2 ns 1.7 ns 136.6 ns +18.8% ⚠️
SmallDictionaryBenchmark.SmallDictionary_Insert(ItemCount: 8) 85.4 ns 0.5 ns 76.6 ns +11.5% ⚠️
SmallDictionaryBenchmark.Dictionary_Insert(ItemCount: 64) 771.8 ns 8.0 ns 652.4 ns +18.3% ⚠️
HashCachingDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 13.31 μs 330.5 ns 10.71 μs +24.2% ⚠️
HashCachingDictionaryBenchmark.HashCachingDictionary_Insert(ItemCount: 1000) 11.49 μs 119.9 ns 8.82 μs +30.2% ⚠️
HashCachingDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 4.73 ms 78.96 μs 4.05 ms +16.9% ⚠️
SmallDictionaryBenchmark.Dictionary_Lookup(ItemCount: 8) 36.8 ns 0.1 ns 23.1 ns +59.2% ⚠️
SmallDictionaryBenchmark.Dictionary_Lookup(ItemCount: 64) 297.5 ns 2.1 ns 197.9 ns +50.4% ⚠️
SmallDictionaryBenchmark.SmallDictionary_Lookup(ItemCount: 64) 1.10 μs 9.8 ns 883.8 ns +25.0% ⚠️
HashCachingDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.71 μs 9.7 ns 3.02 μs +56.2% ⚠️
HashCachingDictionaryBenchmark.HashCachingDictionary_Lookup(ItemCount: 1000) 2.71 μs 8.3 ns 2.16 μs +25.1% ⚠️
HashCachingDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.62 ms 2.31 μs 1.30 ms +24.6% ⚠️
EnumSetBenchmark.HashSet_Remove 4.01 μs 172.0 ns 3.35 μs +19.8% ⚠️
SmallDictionaryBenchmark.Dictionary_Remove(ItemCount: 64) 6.28 μs 297.4 ns 3.62 μs +73.4% ⚠️
HashCachingDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 86.30 μs 7.12 μs 64.95 μs +32.9% ⚠️
HashCachingDictionaryBenchmark.HashCachingDictionary_Remove(ItemCount: 1000) 114.86 μs 7.25 μs 91.71 μs +25.2% ⚠️
HashCachingDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.03 ms 14.56 μs 1.61 ms +26.5% ⚠️
Collections (536)
Benchmark This PR StdDev main Δ
EnumMapBenchmark.Dictionary_Add 627.4 ns 4.7 ns 636.6 ns -1.5%
EnumMapBenchmark.EnumMap_Add 108.8 ns 0.1 ns 156.1 ns -30.3% ✅
SmallSetBenchmark.HashSet_Add(ItemCount: 8) 183.7 ns 2.1 ns 169.4 ns +8.5%
SmallSetBenchmark.SmallSet_Add(ItemCount: 8) 58.3 ns 1.3 ns 47.9 ns +21.8% ⚠️
SmallSetBenchmark.HashSet_Add(ItemCount: 64) 837.5 ns 78.8 ns 791.6 ns +5.8%
SmallSetBenchmark.SmallSet_Add(ItemCount: 64) 1.93 μs 319.6 ns 1.67 μs +15.7%
SmallSetBenchmark.HashSet_Contains(ItemCount: 8) 37.6 ns 0.3 ns 37.1 ns +1.3%
SmallSetBenchmark.SmallSet_Contains(ItemCount: 8) 19.8 ns 0.2 ns 19.1 ns +3.9%
SmallSetBenchmark.HashSet_Contains(ItemCount: 64) 301.9 ns 0.3 ns 317.9 ns -5.0%
SmallSetBenchmark.SmallSet_Contains(ItemCount: 64) 924.8 ns 11.1 ns 1.09 μs -15.2% ✅
IndexedPriorityQueueBenchmark.PriorityQueue_DecreaseKey(ItemCount: 1000) 76.43 μs 299.9 ns 146.38 μs -47.8% ✅
IndexedPriorityQueueBenchmark.IndexedPriorityQueue_DecreaseKey(ItemCount: 1000) 187.93 μs 971.1 ns 262.47 μs -28.4% ✅
IndexedPriorityQueueBenchmark.PriorityQueue_DecreaseKey(ItemCount: 100000) 35.12 ms 298.31 μs 32.43 ms +8.3%
IndexedPriorityQueueBenchmark.IndexedPriorityQueue_DecreaseKey(ItemCount: 100000) 56.50 ms 175.68 μs 55.99 ms +0.9%
IndexedPriorityQueueBenchmark.PriorityQueue_Enqueue(ItemCount: 1000) 4.56 μs 13.8 ns 4.57 μs -0.3%
IndexedPriorityQueueBenchmark.IndexedPriorityQueue_Enqueue(ItemCount: 1000) 29.37 μs 205.7 ns 29.48 μs -0.4%
IndexedPriorityQueueBenchmark.PriorityQueue_Enqueue(ItemCount: 100000) 1.17 ms 13.76 μs 1.07 ms +8.9%
IndexedPriorityQueueBenchmark.IndexedPriorityQueue_Enqueue(ItemCount: 100000) 6.33 ms 124.40 μs 6.40 ms -1.1%
EnumMapBenchmark.Dictionary_Enumerate 43.0 ns 0.1 ns 50.5 ns -14.8% ✅
EnumMapBenchmark.EnumMap_Enumerate 38.1 ns 0.2 ns 39.8 ns -4.3%
CelerityMultiMapBenchmark.Dictionary_Insert(ItemCount: 1000) 27.08 μs 286.2 ns 30.19 μs -10.3% ✅
RobinHoodDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 13.91 μs 306.1 ns 13.28 μs +4.7%
CelerityMultiMapBenchmark.CelerityMultiMap_Insert(ItemCount: 1000) 38.54 μs 156.8 ns 39.21 μs -1.7%
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Insert(ItemCount: 1000) 18.80 μs 224.1 ns 18.07 μs +4.1%
CelerityMultiMapBenchmark.Dictionary_Insert(ItemCount: 100000) 12.85 ms 1.19 ms 12.62 ms +1.8%
RobinHoodDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 5.05 ms 85.17 μs 4.69 ms +7.6%
CelerityMultiMapBenchmark.CelerityMultiMap_Insert(ItemCount: 100000) 17.73 ms 139.79 μs 17.18 ms +3.2%
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Insert(ItemCount: 100000) 8.05 ms 1.09 ms 8.10 ms -0.6%
EnumMapBenchmark.Dictionary_Lookup 135.8 ns 0.1 ns 117.9 ns +15.1% ⚠️
EnumMapBenchmark.EnumMap_Lookup 69.9 ns 0.2 ns 63.1 ns +10.7% ⚠️
CelerityMultiMapBenchmark.Dictionary_Lookup(ItemCount: 1000) 5.10 μs 6.5 ns 5.03 μs +1.3%
RobinHoodDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.72 μs 5.3 ns 4.71 μs +0.1%
CelerityMultiMapBenchmark.CelerityMultiMap_Lookup(ItemCount: 1000) 2.55 μs 2.2 ns 2.36 μs +8.2%
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Lookup(ItemCount: 1000) 3.01 μs 40.1 ns 2.83 μs +6.2%
CelerityMultiMapBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.76 ms 1.28 μs 1.78 ms -1.1%
RobinHoodDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.61 ms 1.47 μs 1.60 ms +0.8%
CelerityMultiMapBenchmark.CelerityMultiMap_Lookup(ItemCount: 100000) 775.20 μs 2.71 μs 746.04 μs +3.9%
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Lookup(ItemCount: 100000) 930.42 μs 6.96 μs 860.46 μs +8.1%
EnumMapBenchmark.Dictionary_Remove 2.73 μs 383.5 ns 3.40 μs -19.8%
EnumMapBenchmark.EnumMap_Remove 1.73 μs 275.8 ns 1.91 μs -9.1%
SmallSetBenchmark.HashSet_Remove(ItemCount: 8) 427.2 ns 56.8 ns 295.1 ns +44.8%
SmallSetBenchmark.SmallSet_Remove(ItemCount: 8) 1.24 μs 112.6 ns 1.40 μs -11.5%
SmallSetBenchmark.HashSet_Remove(ItemCount: 64) 1.46 μs 182.9 ns 1.42 μs +2.5%
SmallSetBenchmark.SmallSet_Remove(ItemCount: 64) 26.41 μs 1.58 μs 28.65 μs -7.8%
CelerityMultiMapBenchmark.Dictionary_Remove(ItemCount: 1000) 29.64 μs 3.81 μs 28.96 μs +2.4%
RobinHoodDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 76.26 μs 5.88 μs 80.89 μs -5.7%
CelerityMultiMapBenchmark.CelerityMultiMap_Remove(ItemCount: 1000) 122.72 μs 10.12 μs 136.92 μs -10.4%
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Remove(ItemCount: 1000) 119.31 μs 4.71 μs 121.30 μs -1.6%
CelerityMultiMapBenchmark.Dictionary_Remove(ItemCount: 100000) 2.03 ms 154.85 μs 2.77 ms -26.8% ✅
RobinHoodDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.00 ms 15.40 μs 2.09 ms -4.2%
CelerityMultiMapBenchmark.CelerityMultiMap_Remove(ItemCount: 100000) 1.93 ms 63.70 μs 2.49 ms -22.3% ✅
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Remove(ItemCount: 100000) 1.86 ms 67.34 μs 1.75 ms +6.1%
CompressedIntSetBenchmark.HashSet_Add(ItemCount: 1000) 13.21 μs 148.5 ns n/a 🆕 new
LongSetBenchmark.HashSet_Add(ItemCount: 1000) 14.95 μs 660.0 ns 13.51 μs +10.7% ⚠️
CompressedIntSetBenchmark.CompressedIntSet_Add(ItemCount: 1000) 34.08 μs 410.8 ns n/a 🆕 new
LongSetBenchmark.LongSet_Add(ItemCount: 1000) 9.82 μs 176.5 ns 9.37 μs +4.7%
CompressedIntSetBenchmark.HashSet_Add(ItemCount: 100000) 3.59 ms 47.17 μs n/a 🆕 new
LongSetBenchmark.HashSet_Add(ItemCount: 100000) 4.61 ms 209.32 μs 4.55 ms +1.3%
CompressedIntSetBenchmark.CompressedIntSet_Add(ItemCount: 100000) 10.71 ms 47.72 μs n/a 🆕 new
LongSetBenchmark.LongSet_Add(ItemCount: 100000) 6.19 ms 77.99 μs 6.11 ms +1.3%
FrozenCelerityDictionaryBenchmark.FrozenDictionary_Build(ItemCount: 1000) 163.27 μs 466.4 ns 160.36 μs +1.8%
FrozenCelerityDictionaryBenchmark.FrozenCelerityDictionary_Build(ItemCount: 1000) 4.15 ms 554.04 μs 3.81 ms +9.1%
FrozenCelerityDictionaryBenchmark.FrozenDictionary_Build(ItemCount: 100000) 29.55 ms 682.56 μs 29.13 ms +1.4%
FrozenCelerityDictionaryBenchmark.FrozenCelerityDictionary_Build(ItemCount: 100000) 1.53 s 48.70 ms 1.71 s -10.7%
CompressedIntSetBenchmark.HashSet_Contains(ItemCount: 1000) 4.70 μs 6.0 ns n/a 🆕 new
LongSetBenchmark.HashSet_Contains(ItemCount: 1000) 4.85 μs 4.8 ns 5.11 μs -5.1%
CompressedIntSetBenchmark.CompressedIntSet_Contains(ItemCount: 1000) 13.50 μs 39.3 ns n/a 🆕 new
LongSetBenchmark.LongSet_Contains(ItemCount: 1000) 2.01 μs 8.3 ns 2.01 μs +0.1%
StringKeyProbeBenchmark.HashSet_Contains(ItemCount: 1000) 18.05 μs 66.5 ns 18.03 μs +0.1%
StringKeyProbeBenchmark.CeleritySet_Contains(ItemCount: 1000) 24.23 μs 35.6 ns 24.27 μs -0.2%
CompressedIntSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.57 ms 14.29 μs n/a 🆕 new
LongSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.66 ms 6.98 μs 1.64 ms +1.1%
CompressedIntSetBenchmark.CompressedIntSet_Contains(ItemCount: 100000) 8.27 ms 11.68 μs n/a 🆕 new
LongSetBenchmark.LongSet_Contains(ItemCount: 100000) 643.36 μs 1.41 μs 639.20 μs +0.7%
StringKeyProbeBenchmark.HashSet_Contains(ItemCount: 100000) 3.51 ms 29.39 μs 3.42 ms +2.6%
StringKeyProbeBenchmark.CeleritySet_Contains(ItemCount: 100000) 5.00 ms 173.21 μs 4.81 ms +3.9%
StringInternTableBenchmark.Dictionary_Dedupe(ItemCount: 1000) 34.65 μs 400.6 ns 33.97 μs +2.0%
StringInternTableBenchmark.StringInternTable_Dedupe(ItemCount: 1000) 35.70 μs 70.2 ns 35.67 μs +0.1%
StringInternTableBenchmark.Dictionary_Dedupe(ItemCount: 100000) 3.39 ms 26.39 μs 3.26 ms +3.8%
StringInternTableBenchmark.StringInternTable_Dedupe(ItemCount: 100000) 3.19 ms 3.33 μs 3.20 ms -0.2%
CompressedIntSetBenchmark.HashSet_Except(ItemCount: 1000) 58.81 μs 9.17 μs n/a 🆕 new
CompressedIntSetBenchmark.CompressedIntSet_Except(ItemCount: 1000) 67.29 μs 6.59 μs n/a 🆕 new
CompressedIntSetBenchmark.HashSet_Except(ItemCount: 100000) 2.52 ms 28.30 μs n/a 🆕 new
CompressedIntSetBenchmark.CompressedIntSet_Except(ItemCount: 100000) 1.10 ms 17.04 μs n/a 🆕 new
CelerityDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 13.95 μs 162.1 ns 10.58 μs +31.9% ⚠️
CelerityDictionaryBenchmark.CelerityDictionary_Insert(ItemCount: 1000) 12.19 μs 187.4 ns 8.09 μs +50.7% ⚠️
CelerityDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 4.25 ms 76.22 μs 3.62 ms +17.4% ⚠️
CelerityDictionaryBenchmark.CelerityDictionary_Insert(ItemCount: 100000) 4.99 ms 75.60 μs 4.75 ms +5.2%
CompressedIntSetBenchmark.HashSet_IntersectClustered(ItemCount: 1000) 38.56 μs 6.04 μs n/a 🆕 new
CompressedIntSetBenchmark.CompressedIntSet_IntersectClustered(ItemCount: 1000) 1.25 μs 60.9 ns n/a 🆕 new
CompressedIntSetBenchmark.HashSet_IntersectClustered(ItemCount: 100000) 963.37 μs 10.86 μs n/a 🆕 new
CompressedIntSetBenchmark.CompressedIntSet_IntersectClustered(ItemCount: 100000) 1.96 μs 482.2 ns n/a 🆕 new
CompressedIntSetBenchmark.HashSet_IntersectDense(ItemCount: 1000) 51.52 μs 4.52 μs n/a 🆕 new
CompressedIntSetBenchmark.CompressedIntSet_IntersectDense(ItemCount: 1000) 54.21 μs 5.49 μs n/a 🆕 new
CompressedIntSetBenchmark.HashSet_IntersectDense(ItemCount: 100000) 3.21 ms 338.09 μs n/a 🆕 new
CompressedIntSetBenchmark.CompressedIntSet_IntersectDense(ItemCount: 100000) 95.31 μs 18.03 μs n/a 🆕 new
CompressedIntSetBenchmark.HashSet_IntersectSparse(ItemCount: 1000) 48.77 μs 3.15 μs n/a 🆕 new
CompressedIntSetBenchmark.CompressedIntSet_IntersectSparse(ItemCount: 1000) 53.95 μs 7.35 μs n/a 🆕 new
CompressedIntSetBenchmark.HashSet_IntersectSparse(ItemCount: 100000) 3.92 ms 84.26 μs n/a 🆕 new
CompressedIntSetBenchmark.CompressedIntSet_IntersectSparse(ItemCount: 100000) 948.97 μs 12.69 μs n/a 🆕 new
StringKeyProbeBenchmark.Dictionary_Lookup(ItemCount: 1000) 18.78 μs 207.3 ns 18.63 μs +0.9%
StringKeyProbeBenchmark.CelerityDictionary_Lookup(ItemCount: 1000) 26.84 μs 57.5 ns 26.53 μs +1.1%
CelerityDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.72 μs 14.4 ns 3.05 μs +54.8% ⚠️
FrozenCelerityDictionaryBenchmark.FrozenDictionary_Lookup(ItemCount: 1000) 7.33 μs 11.2 ns 7.34 μs -0.2%
StringInternTableBenchmark.HashSet_Lookup(ItemCount: 1000) 33.54 μs 217.4 ns 32.57 μs +3.0%
CelerityDictionaryBenchmark.CelerityDictionary_Lookup(ItemCount: 1000) 2.48 μs 11.0 ns 1.89 μs +31.2% ⚠️
FrozenCelerityDictionaryBenchmark.FrozenCelerityDictionary_Lookup(ItemCount: 1000) 86.24 μs 2.57 μs 86.64 μs -0.5%
StringInternTableBenchmark.StringInternTable_Lookup(ItemCount: 1000) 31.39 μs 20.2 ns 31.40 μs -0.0%
StringKeyProbeBenchmark.Dictionary_Lookup(ItemCount: 100000) 3.63 ms 59.09 μs 3.57 ms +1.6%
StringKeyProbeBenchmark.CelerityDictionary_Lookup(ItemCount: 100000) 5.47 ms 141.62 μs 5.21 ms +4.8%
CelerityDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.60 ms 8.23 μs 1.30 ms +22.8% ⚠️
FrozenCelerityDictionaryBenchmark.FrozenDictionary_Lookup(ItemCount: 100000) 2.03 ms 18.40 μs 1.99 ms +1.9%
StringInternTableBenchmark.HashSet_Lookup(ItemCount: 100000) 3.42 ms 70.63 μs 3.33 ms +2.9%
CelerityDictionaryBenchmark.CelerityDictionary_Lookup(ItemCount: 100000) 736.56 μs 1.03 μs 644.43 μs +14.3% ⚠️
FrozenCelerityDictionaryBenchmark.FrozenCelerityDictionary_Lookup(ItemCount: 100000) 7.78 ms 112.19 μs 7.64 ms +1.9%
StringInternTableBenchmark.StringInternTable_Lookup(ItemCount: 100000) 3.17 ms 4.09 μs 3.17 ms -0.1%
StringKeyProbeBenchmark.Dictionary_LookupMissing(ItemCount: 1000) 15.07 μs 110.3 ns 15.05 μs +0.1%
StringKeyProbeBenchmark.CelerityDictionary_LookupMissing(ItemCount: 1000) 28.47 μs 238.9 ns 28.45 μs +0.1%
StringKeyProbeBenchmark.Dictionary_LookupMissing(ItemCount: 100000) 4.00 ms 73.56 μs 3.81 ms +5.0%
StringKeyProbeBenchmark.CelerityDictionary_LookupMissing(ItemCount: 100000) 6.01 ms 277.38 μs 5.36 ms +12.2% ⚠️
CelerityDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 83.58 μs 6.41 μs 60.85 μs +37.3% ⚠️
LongSetBenchmark.HashSet_Remove(ItemCount: 1000) 77.24 μs 7.84 μs 75.75 μs +2.0%
CelerityDictionaryBenchmark.CelerityDictionary_Remove(ItemCount: 1000) 124.48 μs 7.15 μs 99.56 μs +25.0% ⚠️
LongSetBenchmark.LongSet_Remove(ItemCount: 1000) 86.40 μs 5.00 μs 85.36 μs +1.2%
CelerityDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.05 ms 16.94 μs 1.62 ms +26.6% ⚠️
LongSetBenchmark.HashSet_Remove(ItemCount: 100000) 1.97 ms 14.68 μs 1.97 ms -0.0%
CelerityDictionaryBenchmark.CelerityDictionary_Remove(ItemCount: 100000) 1.61 ms 42.51 μs 2.24 ms -28.1%
LongSetBenchmark.LongSet_Remove(ItemCount: 100000) 1.52 ms 226.34 μs 1.45 ms +5.3%
FrozenCelerityDictionaryBenchmark.FrozenDictionary_SpanLookup(ItemCount: 1000) 32.13 μs 657.1 ns 30.44 μs +5.6%
FrozenCelerityDictionaryBenchmark.FrozenCelerityDictionary_SpanLookup(ItemCount: 1000) 91.28 μs 128.2 ns 91.51 μs -0.3%
FrozenCelerityDictionaryBenchmark.FrozenDictionary_SpanLookup(ItemCount: 100000) 6.30 ms 133.71 μs 5.78 ms +9.0%
FrozenCelerityDictionaryBenchmark.FrozenCelerityDictionary_SpanLookup(ItemCount: 100000) 8.81 ms 136.47 μs 8.52 ms +3.5%
CompressedIntSetBenchmark.HashSet_Union(ItemCount: 1000) 37.04 μs 4.56 μs n/a 🆕 new
CompressedIntSetBenchmark.CompressedIntSet_Union(ItemCount: 1000) 79.52 μs 5.09 μs n/a 🆕 new
CompressedIntSetBenchmark.HashSet_Union(ItemCount: 100000) 4.60 ms 1.08 ms n/a 🆕 new
CompressedIntSetBenchmark.CompressedIntSet_Union(ItemCount: 100000) 1.19 ms 10.58 μs n/a 🆕 new
CeleritySetBenchmark.HashSet_Add(ItemCount: 1000) 9.46 μs 137.9 ns 12.07 μs -21.7% ✅
CuckooFilterBenchmark.HashSet_Add(ItemCount: 1000) 9.87 μs 152.5 ns 12.72 μs -22.5% ✅
HyperLogLogBenchmark.HashSet_Add(ItemCount: 1000) 9.64 μs 79.4 ns 10.70 μs -9.9% ✅
CeleritySetBenchmark.CeleritySet_Add(ItemCount: 1000) 7.58 μs 70.5 ns 8.77 μs -13.6% ✅
CuckooFilterBenchmark.CuckooFilter_Add(ItemCount: 1000) 5.13 μs 34.7 ns 7.14 μs -28.2% ✅
HyperLogLogBenchmark.HyperLogLog_Add(ItemCount: 1000) 84.48 μs 411.0 ns 87.09 μs -3.0%
CeleritySetBenchmark.HashSet_Add(ItemCount: 100000) 3.93 ms 259.29 μs 5.06 ms -22.3% ✅
CuckooFilterBenchmark.HashSet_Add(ItemCount: 100000) 3.63 ms 87.90 μs 4.70 ms -22.8% ✅
HyperLogLogBenchmark.HashSet_Add(ItemCount: 100000) 3.77 ms 263.74 μs 4.03 ms -6.4%
CeleritySetBenchmark.CeleritySet_Add(ItemCount: 100000) 3.12 ms 27.73 μs 3.17 ms -1.8%
CuckooFilterBenchmark.CuckooFilter_Add(ItemCount: 100000) 2.04 ms 48.04 μs 2.08 ms -2.2%
HyperLogLogBenchmark.HyperLogLog_Add(ItemCount: 100000) 588.57 μs 4.40 μs 590.56 μs -0.3%
RankSelectBitVectorBenchmark.Array_Build(ItemCount: 1024) 82.4 ns 1.1 ns 90.9 ns -9.4% ✅
RankSelectBitVectorBenchmark.RankSelectBitVector_Build(ItemCount: 1024) 62.2 ns 2.9 ns 60.0 ns +3.7%
RankSelectBitVectorBenchmark.Array_Build(ItemCount: 1000000) 46.27 μs 522.5 ns 67.96 μs -31.9% ✅
RankSelectBitVectorBenchmark.RankSelectBitVector_Build(ItemCount: 1000000) 65.69 μs 1.86 μs 87.49 μs -24.9% ✅
CeleritySetBenchmark.HashSet_Contains(ItemCount: 1000) 3.01 μs 10.5 ns 4.76 μs -36.8% ✅
CuckooFilterBenchmark.HashSet_Contains(ItemCount: 1000) 3.02 μs 3.9 ns 4.73 μs -36.1% ✅
CeleritySetBenchmark.CeleritySet_Contains(ItemCount: 1000) 1.55 μs 6.9 ns 2.08 μs -25.1% ✅
CuckooFilterBenchmark.CuckooFilter_Contains(ItemCount: 1000) 3.63 μs 3.6 ns 4.91 μs -26.1% ✅
CeleritySetBenchmark.HashSet_Contains(ItemCount: 100000) 1.26 ms 4.28 μs 1.58 ms -20.6% ✅
CuckooFilterBenchmark.HashSet_Contains(ItemCount: 100000) 1.24 ms 8.04 μs 1.60 ms -22.1% ✅
CeleritySetBenchmark.CeleritySet_Contains(ItemCount: 100000) 515.68 μs 4.13 μs 593.11 μs -13.1% ✅
CuckooFilterBenchmark.CuckooFilter_Contains(ItemCount: 100000) 1.76 ms 3.68 μs 1.74 ms +1.4%
CuckooFilterBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 3.06 μs 8.1 ns 4.54 μs -32.5% ✅
CuckooFilterBenchmark.CuckooFilter_ContainsMissing(ItemCount: 1000) 6.10 μs 22.5 ns 8.43 μs -27.7% ✅
CuckooFilterBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 1.64 ms 7.26 μs 1.93 ms -15.2% ✅
CuckooFilterBenchmark.CuckooFilter_ContainsMissing(ItemCount: 100000) 700.07 μs 3.01 μs 879.18 μs -20.4% ✅
HyperLogLogBenchmark.HashSet_Estimate(ItemCount: 1000) 0.0 ns 0.0 ns 0.0 ns -40.7%
HyperLogLogBenchmark.HyperLogLog_Estimate(ItemCount: 1000) 80.86 μs 340.0 ns 80.91 μs -0.1%
HyperLogLogBenchmark.HashSet_Estimate(ItemCount: 100000) 0.0 ns 0.0 ns 0.0 ns +9.1%
HyperLogLogBenchmark.HyperLogLog_Estimate(ItemCount: 100000) 80.94 μs 183.0 ns 80.91 μs +0.0%
LruCacheBenchmark.Dictionary_Get(ItemCount: 1000) 23.44 μs 114.1 ns 24.12 μs -2.8%
LruCacheBenchmark.LruCache_Get(ItemCount: 1000) 5.03 μs 47.8 ns 6.80 μs -26.0% ✅
LruCacheBenchmark.Dictionary_Get(ItemCount: 100000) 24.44 μs 111.7 ns 25.01 μs -2.3%
LruCacheBenchmark.LruCache_Get(ItemCount: 100000) 5.11 μs 104.1 ns 7.01 μs -27.0% ✅
LruCacheBenchmark.Dictionary_GetMissing(ItemCount: 1000) 3.28 μs 21.7 ns 4.83 μs -31.9% ✅
LruCacheBenchmark.LruCache_GetMissing(ItemCount: 1000) 3.98 μs 26.1 ns 3.60 μs +10.6% ⚠️
LruCacheBenchmark.Dictionary_GetMissing(ItemCount: 100000) 392.78 μs 1.75 μs 557.92 μs -29.6% ✅
LruCacheBenchmark.LruCache_GetMissing(ItemCount: 100000) 1.49 ms 3.83 μs 1.34 ms +11.1% ⚠️
PooledCelerityDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 10.57 μs 121.6 ns 13.63 μs -22.5% ✅
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Insert(ItemCount: 1000) 6.56 μs 56.4 ns 8.09 μs -18.9% ✅
PooledCelerityDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 3.80 ms 259.72 μs 4.89 ms -22.2% ✅
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Insert(ItemCount: 100000) 2.87 ms 18.41 μs 2.97 ms -3.5%
PooledCelerityDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 2.98 μs 15.9 ns 4.72 μs -36.8% ✅
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Lookup(ItemCount: 1000) 1.93 μs 15.8 ns 2.59 μs -25.5% ✅
PooledCelerityDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.28 ms 9.11 μs 1.60 ms -19.5% ✅
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Lookup(ItemCount: 100000) 644.52 μs 10.68 μs 714.29 μs -9.8% ✅
LruCacheBenchmark.Dictionary_Put(ItemCount: 1000) 70.73 μs 4.36 μs 121.64 μs -41.9% ✅
LruCacheBenchmark.LruCache_Put(ItemCount: 1000) 290.04 μs 14.46 μs 468.65 μs -38.1% ✅
LruCacheBenchmark.Dictionary_Put(ItemCount: 100000) 5.60 ms 105.69 μs 8.20 ms -31.7% ✅
LruCacheBenchmark.LruCache_Put(ItemCount: 100000) 5.94 ms 61.73 μs 5.80 ms +2.4%
RankSelectBitVectorBenchmark.Array_RankEarly(ItemCount: 1024) 1.20 μs 30.6 ns 1.23 μs -2.8%
RankSelectBitVectorBenchmark.RankSelectBitVector_RankEarly(ItemCount: 1024) 1.52 μs 40.3 ns 1.88 μs -19.3% ✅
RankSelectBitVectorBenchmark.Array_RankEarly(ItemCount: 1000000) 43.33 μs 474.4 ns 32.76 μs +32.3% ⚠️
RankSelectBitVectorBenchmark.RankSelectBitVector_RankEarly(ItemCount: 1000000) 1.48 μs 27.5 ns 1.88 μs -21.0% ✅
RankSelectBitVectorBenchmark.Array_RankLate(ItemCount: 1024) 8.10 μs 82.7 ns 6.44 μs +25.8% ⚠️
RankSelectBitVectorBenchmark.RankSelectBitVector_RankLate(ItemCount: 1024) 1.44 μs 8.0 ns 1.88 μs -23.5% ✅
RankSelectBitVectorBenchmark.Array_RankLate(ItemCount: 1000000) 6.54 ms 67.92 μs 4.87 ms +34.3% ⚠️
RankSelectBitVectorBenchmark.RankSelectBitVector_RankLate(ItemCount: 1000000) 1.44 μs 3.4 ns 1.88 μs -23.3% ✅
RankSelectBitVectorBenchmark.Array_RankMid(ItemCount: 1024) 4.60 μs 31.5 ns 4.87 μs -5.6%
RankSelectBitVectorBenchmark.RankSelectBitVector_RankMid(ItemCount: 1024) 1.47 μs 26.0 ns 1.88 μs -21.5% ✅
RankSelectBitVectorBenchmark.Array_RankMid(ItemCount: 1000000) 3.39 ms 53.81 μs 2.47 ms +37.0% ⚠️
RankSelectBitVectorBenchmark.RankSelectBitVector_RankMid(ItemCount: 1000000) 1.46 μs 20.5 ns 1.88 μs -22.5% ✅
CeleritySetBenchmark.HashSet_Remove(ItemCount: 1000) 22.93 μs 2.65 μs 32.77 μs -30.0% ✅
PooledCelerityDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 60.38 μs 7.99 μs 79.96 μs -24.5% ✅
CeleritySetBenchmark.CeleritySet_Remove(ItemCount: 1000) 96.80 μs 10.95 μs 122.15 μs -20.8% ✅
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Remove(ItemCount: 1000) 102.13 μs 8.03 μs 127.74 μs -20.0% ✅
CuckooFilterBenchmark.HashSet_Remove(ItemCount: 1000) 10.12 μs 44.6 ns 13.00 μs -22.1% ✅
CuckooFilterBenchmark.CuckooFilter_Remove(ItemCount: 1000) 9.26 μs 41.8 ns 12.85 μs -28.0% ✅
CeleritySetBenchmark.HashSet_Remove(ItemCount: 100000) 1.46 ms 53.05 μs 1.70 ms -14.4% ✅
PooledCelerityDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 1.61 ms 31.66 μs 2.05 ms -21.2% ✅
CeleritySetBenchmark.CeleritySet_Remove(ItemCount: 100000) 1.26 ms 54.78 μs 1.39 ms -8.9%
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Remove(ItemCount: 100000) 6.68 ms 95.43 μs 1.60 ms +318.2% ⚠️
CuckooFilterBenchmark.HashSet_Remove(ItemCount: 100000) 2.88 ms 12.66 μs 3.77 ms -23.7% ✅
CuckooFilterBenchmark.CuckooFilter_Remove(ItemCount: 100000) 3.77 ms 12.68 μs 3.96 ms -4.8%
RankSelectBitVectorBenchmark.Array_Select(ItemCount: 1024) 10.14 μs 102.5 ns 13.00 μs -22.0% ✅
RankSelectBitVectorBenchmark.RankSelectBitVector_Select(ItemCount: 1024) 8.85 μs 84.5 ns 11.41 μs -22.4% ✅
RankSelectBitVectorBenchmark.Array_Select(ItemCount: 1000000) 4.77 ms 1.81 ms 4.23 ms +12.7%
RankSelectBitVectorBenchmark.RankSelectBitVector_Select(ItemCount: 1000000) 66.25 μs 571.9 ns 25.81 μs +156.7% ⚠️
BTreeDictionaryBenchmark.SortedDictionary_Add(ItemCount: 1000) 59.60 μs 1.05 μs 89.81 μs -33.6% ✅
CountMinSketchBenchmark.Dictionary_Add(ItemCount: 1000) 10.41 μs 86.5 ns 10.59 μs -1.7%
PooledCeleritySetBenchmark.HashSet_Add(ItemCount: 1000) 12.33 μs 422.6 ns 12.23 μs +0.8%
BTreeDictionaryBenchmark.BTreeDictionary_Add(ItemCount: 1000) 53.75 μs 272.1 ns 64.75 μs -17.0% ✅
CountMinSketchBenchmark.CountMinSketch_Add(ItemCount: 1000) 10.43 μs 162.2 ns 10.40 μs +0.2%
PooledCeleritySetBenchmark.PooledCeleritySet_Add(ItemCount: 1000) 8.59 μs 46.6 ns 8.40 μs +2.3%
BTreeDictionaryBenchmark.SortedDictionary_Add(ItemCount: 100000) 23.80 ms 221.36 μs 22.90 ms +3.9%
CountMinSketchBenchmark.Dictionary_Add(ItemCount: 100000) 1.43 ms 9.20 μs 1.43 ms -0.2%
PooledCeleritySetBenchmark.HashSet_Add(ItemCount: 100000) 4.80 ms 58.87 μs 4.81 ms -0.3%
BTreeDictionaryBenchmark.BTreeDictionary_Add(ItemCount: 100000) 16.29 ms 192.98 μs 15.82 ms +2.9%
CountMinSketchBenchmark.CountMinSketch_Add(ItemCount: 100000) 962.10 μs 877.6 ns 963.09 μs -0.1%
PooledCeleritySetBenchmark.PooledCeleritySet_Add(ItemCount: 100000) 2.87 ms 8.49 μs 2.88 ms -0.4%
BitSetBenchmark.BitArray_And(ItemCount: 1024) 55.7 ns 1.2 ns 57.0 ns -2.4%
BitSetBenchmark.BitSet_And(ItemCount: 1024) 1.24 μs 6.0 ns 1.25 μs -0.4%
BitSetBenchmark.BitArray_And(ItemCount: 1000000) 44.05 μs 583.6 ns 44.93 μs -2.0%
BitSetBenchmark.BitSet_And(ItemCount: 1000000) 4.48 ms 7.22 μs 4.48 ms -0.0%
PooledCeleritySetBenchmark.HashSet_Contains(ItemCount: 1000) 4.81 μs 62.5 ns 4.96 μs -3.1%
PooledCeleritySetBenchmark.PooledCeleritySet_Contains(ItemCount: 1000) 1.94 μs 8.4 ns 1.93 μs +0.1%
PooledCeleritySetBenchmark.HashSet_Contains(ItemCount: 100000) 1.59 ms 3.38 μs 1.59 ms -0.2%
PooledCeleritySetBenchmark.PooledCeleritySet_Contains(ItemCount: 100000) 575.42 μs 907.6 ns 580.05 μs -0.8%
DequeBenchmark.LinkedList_Enumerate(ItemCount: 1000) 1.37 μs 0.5 ns 1.37 μs -0.1%
DequeBenchmark.Deque_Enumerate(ItemCount: 1000) 941.0 ns 0.5 ns 942.5 ns -0.2%
DequeBenchmark.LinkedList_Enumerate(ItemCount: 100000) 134.70 μs 55.9 ns 135.28 μs -0.4%
DequeBenchmark.Deque_Enumerate(ItemCount: 100000) 93.70 μs 71.3 ns 93.84 μs -0.2%
CountMinSketchBenchmark.Dictionary_Estimate(ItemCount: 1000) 4.37 μs 2.4 ns 4.37 μs -0.0%
CountMinSketchBenchmark.CountMinSketch_Estimate(ItemCount: 1000) 10.06 μs 57.8 ns 10.05 μs +0.0%
CountMinSketchBenchmark.Dictionary_Estimate(ItemCount: 100000) 504.55 μs 18.98 μs 516.26 μs -2.3%
CountMinSketchBenchmark.CountMinSketch_Estimate(ItemCount: 100000) 2.01 ms 41.26 μs 1.96 ms +2.1%
IntDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 13.17 μs 230.9 ns 13.20 μs -0.2%
IntDictionaryBenchmark.IntDictionary_Insert(ItemCount: 1000) 11.16 μs 183.3 ns 11.48 μs -2.8%
IntDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 4.21 ms 65.45 μs 4.17 ms +0.9%
IntDictionaryBenchmark.IntDictionary_Insert(ItemCount: 100000) 4.96 ms 69.56 μs 4.83 ms +2.6%
BTreeDictionaryBenchmark.SortedDictionary_Lookup(ItemCount: 1000) 39.36 μs 2.44 μs 52.48 μs -25.0% ✅
IntDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.74 μs 16.7 ns 4.72 μs +0.5%
BTreeDictionaryBenchmark.BTreeDictionary_Lookup(ItemCount: 1000) 25.70 μs 73.2 ns 44.70 μs -42.5% ✅
IntDictionaryBenchmark.IntDictionary_Lookup(ItemCount: 1000) 2.14 μs 3.4 ns 2.14 μs +0.0%
BTreeDictionaryBenchmark.SortedDictionary_Lookup(ItemCount: 100000) 18.19 ms 286.09 μs 18.70 ms -2.7%
IntDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.60 ms 18.71 μs 1.61 ms -0.6%
BTreeDictionaryBenchmark.BTreeDictionary_Lookup(ItemCount: 100000) 13.03 ms 161.18 μs 14.04 ms -7.2%
IntDictionaryBenchmark.IntDictionary_Lookup(ItemCount: 100000) 673.21 μs 2.02 μs 674.16 μs -0.1%
BTreeDictionaryBenchmark.SortedDictionary_Mixed(ItemCount: 1000) 186.53 μs 2.34 μs 213.64 μs -12.7% ✅
BTreeDictionaryBenchmark.BTreeDictionary_Mixed(ItemCount: 1000) 86.21 μs 4.85 μs 131.14 μs -34.3% ✅
BTreeDictionaryBenchmark.SortedDictionary_Mixed(ItemCount: 100000) 48.22 ms 1.18 ms 49.99 ms -3.5%
BTreeDictionaryBenchmark.BTreeDictionary_Mixed(ItemCount: 100000) 26.78 ms 77.16 μs 27.99 ms -4.3%
BitSetBenchmark.BitArray_Or(ItemCount: 1024) 56.7 ns 1.5 ns 52.6 ns +7.9%
BitSetBenchmark.BitSet_Or(ItemCount: 1024) 1.25 μs 4.1 ns 1.21 μs +3.2%
BitSetBenchmark.BitArray_Or(ItemCount: 1000000) 44.15 μs 382.7 ns 44.37 μs -0.5%
BitSetBenchmark.BitSet_Or(ItemCount: 1000000) 4.47 ms 4.86 μs 4.48 ms -0.0%
BitSetBenchmark.BitArray_PopCount(ItemCount: 1024) 1.24 μs 4.4 ns 1.24 μs -0.2%
BitSetBenchmark.BitSet_PopCount(ItemCount: 1024) 7.1 ns 0.0 ns 7.0 ns +0.6%
BitSetBenchmark.BitArray_PopCount(ItemCount: 1000000) 4.82 ms 1.71 μs 4.83 ms -0.1%
BitSetBenchmark.BitSet_PopCount(ItemCount: 1000000) 4.94 μs 7.6 ns 4.94 μs +0.1%
DequeBenchmark.LinkedList_PushFront(ItemCount: 1000) 35.84 μs 1.34 μs 41.08 μs -12.8%
DequeBenchmark.Deque_PushFront(ItemCount: 1000) 23.74 μs 5.06 μs 21.26 μs +11.7%
DequeBenchmark.LinkedList_PushFront(ItemCount: 100000) 1.76 ms 13.12 μs 1.82 ms -2.8%
DequeBenchmark.Deque_PushFront(ItemCount: 100000) 752.43 μs 208.77 μs 628.18 μs +19.8%
DequeBenchmark.LinkedList_Queue(ItemCount: 1000) 57.00 μs 8.08 μs 61.72 μs -7.7%
DequeBenchmark.Deque_Queue(ItemCount: 1000) 36.26 μs 5.80 μs 32.32 μs +12.2%
DequeBenchmark.LinkedList_Queue(ItemCount: 100000) 4.14 ms 59.07 μs 4.22 ms -2.0%
DequeBenchmark.Deque_Queue(ItemCount: 100000) 487.60 μs 122.42 μs 475.11 μs +2.6%
BTreeDictionaryBenchmark.SortedDictionary_RangeScan(ItemCount: 1000) 4.50 μs 12.4 ns 3.74 μs +20.4% ⚠️
BTreeDictionaryBenchmark.BTreeDictionary_RangeScan(ItemCount: 1000) 77.9 ns 0.5 ns 62.5 ns +24.6% ⚠️
BTreeDictionaryBenchmark.SortedDictionary_RangeScan(ItemCount: 100000) 1.24 ms 2.48 μs 1.15 ms +7.9%
BTreeDictionaryBenchmark.BTreeDictionary_RangeScan(ItemCount: 100000) 5.95 μs 160.0 ns 4.43 μs +34.2% ⚠️
BTreeDictionaryBenchmark.SortedDictionary_Remove(ItemCount: 1000) 786.37 μs 16.43 μs 570.46 μs +37.8% ⚠️
IntDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 85.72 μs 7.72 μs 79.89 μs +7.3%
PooledCeleritySetBenchmark.HashSet_Remove(ItemCount: 1000) 29.63 μs 3.69 μs 30.72 μs -3.6%
BTreeDictionaryBenchmark.BTreeDictionary_Remove(ItemCount: 1000) 313.12 μs 12.66 μs 228.16 μs +37.2% ⚠️
IntDictionaryBenchmark.IntDictionary_Remove(ItemCount: 1000) 100.14 μs 14.56 μs 92.30 μs +8.5%
PooledCeleritySetBenchmark.PooledCeleritySet_Remove(ItemCount: 1000) 116.72 μs 12.62 μs 132.97 μs -12.2%
BTreeDictionaryBenchmark.SortedDictionary_Remove(ItemCount: 100000) 26.57 ms 687.47 μs 27.95 ms -4.9%
IntDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.05 ms 14.68 μs 2.05 ms -0.3%
PooledCeleritySetBenchmark.HashSet_Remove(ItemCount: 100000) 1.71 ms 16.91 μs 1.70 ms +0.6%
BTreeDictionaryBenchmark.BTreeDictionary_Remove(ItemCount: 100000) 18.14 ms 62.20 μs 17.67 ms +2.7%
IntDictionaryBenchmark.IntDictionary_Remove(ItemCount: 100000) 1.58 ms 40.01 μs 2.69 ms -41.0%
PooledCeleritySetBenchmark.PooledCeleritySet_Remove(ItemCount: 100000) 1.31 ms 52.08 μs 1.36 ms -3.8%
BitSetBenchmark.BitArray_Xor(ItemCount: 1024) 59.2 ns 1.3 ns 54.9 ns +7.9%
BitSetBenchmark.BitSet_Xor(ItemCount: 1024) 1.25 μs 4.0 ns 1.25 μs +0.4%
BitSetBenchmark.BitArray_Xor(ItemCount: 1000000) 44.59 μs 858.4 ns 44.59 μs +0.0%
BitSetBenchmark.BitSet_Xor(ItemCount: 1000000) 4.48 ms 7.38 μs 4.48 ms -0.0%
TrieBenchmark.Dictionary_Add(ItemCount: 1000) 33.11 μs 839.1 ns 39.69 μs -16.6%
TrieBenchmark.Trie_Add(ItemCount: 1000) 574.73 μs 18.09 μs 589.74 μs -2.5%
BTreeSetBenchmark.SortedSet_Add(ItemCount: 1000) 42.82 μs 1.16 μs 43.84 μs -2.3%
IntSetBenchmark.HashSet_Add(ItemCount: 1000) 12.78 μs 263.6 ns 12.86 μs -0.6%
TopKSketchBenchmark.Dictionary_Add(ItemCount: 1000) 13.53 μs 82.0 ns 13.80 μs -2.0%
BTreeSetBenchmark.BTreeSet_Add(ItemCount: 1000) 41.81 μs 140.0 ns 42.30 μs -1.2%
IntSetBenchmark.IntSet_Add(ItemCount: 1000) 8.70 μs 84.6 ns 8.79 μs -1.0%
TopKSketchBenchmark.TopKSketch_Add(ItemCount: 1000) 85.67 μs 2.83 μs 88.05 μs -2.7%
TrieBenchmark.Dictionary_Add(ItemCount: 100000) 4.95 ms 1.32 ms 5.13 ms -3.6%
TrieBenchmark.Trie_Add(ItemCount: 100000) 27.21 ms 1.01 ms 26.84 ms +1.4%
BTreeSetBenchmark.SortedSet_Add(ItemCount: 100000) 21.17 ms 205.93 μs 21.06 ms +0.5%
IntSetBenchmark.HashSet_Add(ItemCount: 100000) 5.08 ms 114.86 μs 5.09 ms -0.3%
TopKSketchBenchmark.Dictionary_Add(ItemCount: 100000) 3.24 ms 50.47 μs 3.24 ms +0.0%
BTreeSetBenchmark.BTreeSet_Add(ItemCount: 100000) 13.98 ms 82.51 μs 13.99 ms -0.1%
IntSetBenchmark.IntSet_Add(ItemCount: 100000) 3.16 ms 19.11 μs 3.18 ms -0.5%
TopKSketchBenchmark.TopKSketch_Add(ItemCount: 100000) 14.44 ms 179.31 μs 14.50 ms -0.5%
DisjointSetBenchmark.Dictionary_Components(ItemCount: 1000) 19.38 μs 144.2 ns 18.86 μs +2.7%
DisjointSetBenchmark.DisjointSet_Components(ItemCount: 1000) 17.49 μs 321.4 ns 17.21 μs +1.7%
DisjointSetBenchmark.Dictionary_Components(ItemCount: 100000) 4.45 ms 131.60 μs 4.35 ms +2.2%
DisjointSetBenchmark.DisjointSet_Components(ItemCount: 100000) 3.22 ms 66.97 μs 3.18 ms +1.4%
DisjointSetBenchmark.Dictionary_Connected(ItemCount: 1000) 9.22 μs 59.0 ns 9.42 μs -2.1%
DisjointSetBenchmark.DisjointSet_Connected(ItemCount: 1000) 12.16 μs 56.4 ns 12.20 μs -0.4%
DisjointSetBenchmark.Dictionary_Connected(ItemCount: 100000) 261.67 μs 5.84 μs 261.93 μs -0.1%
DisjointSetBenchmark.DisjointSet_Connected(ItemCount: 100000) 342.72 μs 2.12 μs 343.66 μs -0.3%
BTreeSetBenchmark.SortedSet_Contains(ItemCount: 1000) 16.75 μs 63.0 ns 16.69 μs +0.3%
IntSetBenchmark.HashSet_Contains(ItemCount: 1000) 4.74 μs 7.4 ns 4.74 μs -0.0%
BTreeSetBenchmark.BTreeSet_Contains(ItemCount: 1000) 17.30 μs 168.9 ns 17.17 μs +0.8%
IntSetBenchmark.IntSet_Contains(ItemCount: 1000) 1.80 μs 7.1 ns 1.81 μs -0.5%
BTreeSetBenchmark.SortedSet_Contains(ItemCount: 100000) 15.81 ms 159.77 μs 15.52 ms +1.9%
IntSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.56 ms 13.15 μs 1.57 ms -0.7%
BTreeSetBenchmark.BTreeSet_Contains(ItemCount: 100000) 12.86 ms 278.52 μs 12.83 ms +0.2%
IntSetBenchmark.IntSet_Contains(ItemCount: 100000) 575.75 μs 2.20 μs 574.32 μs +0.3%
LongDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 15.20 μs 459.5 ns 14.63 μs +3.9%
LongDictionaryBenchmark.LongDictionary_Insert(ItemCount: 1000) 11.67 μs 130.9 ns 11.22 μs +4.0%
LongDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 5.05 ms 46.00 μs 5.02 ms +0.5%
LongDictionaryBenchmark.LongDictionary_Insert(ItemCount: 100000) 6.83 ms 132.90 μs 6.92 ms -1.3%
LongDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.89 μs 19.8 ns 5.01 μs -2.4%
TrieBenchmark.Dictionary_Lookup(ItemCount: 1000) 13.26 μs 483.6 ns 12.99 μs +2.1%
LongDictionaryBenchmark.LongDictionary_Lookup(ItemCount: 1000) 2.27 μs 7.4 ns 2.28 μs -0.2%
TrieBenchmark.Trie_Lookup(ItemCount: 1000) 41.17 μs 289.3 ns 41.06 μs +0.3%
LongDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.59 ms 1.80 μs 1.59 ms +0.4%
TrieBenchmark.Dictionary_Lookup(ItemCount: 100000) 2.72 ms 20.14 μs 2.68 ms +1.7%
LongDictionaryBenchmark.LongDictionary_Lookup(ItemCount: 100000) 692.87 μs 5.32 μs 702.23 μs -1.3%
TrieBenchmark.Trie_Lookup(ItemCount: 100000) 9.32 ms 67.39 μs 8.76 ms +6.4%
BTreeSetBenchmark.SortedSet_Mixed(ItemCount: 1000) 100.52 μs 1.10 μs 100.38 μs +0.1%
BTreeSetBenchmark.BTreeSet_Mixed(ItemCount: 1000) 62.95 μs 4.25 μs 62.99 μs -0.1%
BTreeSetBenchmark.SortedSet_Mixed(ItemCount: 100000) 32.06 ms 478.35 μs 31.67 ms +1.2%
BTreeSetBenchmark.BTreeSet_Mixed(ItemCount: 100000) 24.45 ms 82.59 μs 23.83 ms +2.6%
TrieBenchmark.Dictionary_PrefixMatch(ItemCount: 1000) 73.38 μs 69.3 ns 73.35 μs +0.1%
TrieBenchmark.Trie_PrefixMatch(ItemCount: 1000) 58.58 μs 184.6 ns 58.37 μs +0.4%
TrieBenchmark.Dictionary_PrefixMatch(ItemCount: 100000) 7.41 ms 5.76 μs 7.39 ms +0.3%
TrieBenchmark.Trie_PrefixMatch(ItemCount: 100000) 8.52 ms 479.92 μs 8.15 ms +4.6%
BTreeSetBenchmark.SortedSet_RangeScan(ItemCount: 1000) 166.2 ns 0.5 ns 167.1 ns -0.6%
BTreeSetBenchmark.BTreeSet_RangeScan(ItemCount: 1000) 73.3 ns 0.2 ns 73.3 ns -0.1%
BTreeSetBenchmark.SortedSet_RangeScan(ItemCount: 100000) 9.85 μs 437.5 ns 9.97 μs -1.2%
BTreeSetBenchmark.BTreeSet_RangeScan(ItemCount: 100000) 5.19 μs 14.3 ns 5.19 μs -0.1%
BTreeSetBenchmark.SortedSet_Remove(ItemCount: 1000) 724.02 μs 14.93 μs 724.67 μs -0.1%
IntSetBenchmark.HashSet_Remove(ItemCount: 1000) 30.05 μs 4.90 μs 29.86 μs +0.6%
LongDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 88.55 μs 9.09 μs 86.57 μs +2.3%
BTreeSetBenchmark.BTreeSet_Remove(ItemCount: 1000) 267.65 μs 11.86 μs 266.20 μs +0.5%
IntSetBenchmark.IntSet_Remove(ItemCount: 1000) 86.15 μs 8.68 μs 86.34 μs -0.2%
LongDictionaryBenchmark.LongDictionary_Remove(ItemCount: 1000) 94.67 μs 4.80 μs 94.37 μs +0.3%
BTreeSetBenchmark.SortedSet_Remove(ItemCount: 100000) 25.27 ms 111.64 μs 24.98 ms +1.2%
IntSetBenchmark.HashSet_Remove(ItemCount: 100000) 1.74 ms 17.03 μs 1.73 ms +0.5%
LongDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.01 ms 19.97 μs 2.02 ms -0.7%
BTreeSetBenchmark.BTreeSet_Remove(ItemCount: 100000) 15.20 ms 142.44 μs 15.18 ms +0.1%
IntSetBenchmark.IntSet_Remove(ItemCount: 100000) 1.31 ms 51.28 μs 1.35 ms -3.1%
LongDictionaryBenchmark.LongDictionary_Remove(ItemCount: 100000) 6.84 ms 83.54 μs 1.64 ms +317.0% ⚠️
TrieBenchmark.Dictionary_SpanLookup(ItemCount: 1000) 40.78 μs 233.8 ns 40.94 μs -0.4%
TrieBenchmark.Trie_SpanLookup(ItemCount: 1000) 43.52 μs 422.0 ns 43.10 μs +1.0%
TrieBenchmark.Dictionary_SpanLookup(ItemCount: 100000) 5.88 ms 50.20 μs 5.85 ms +0.5%
TrieBenchmark.Trie_SpanLookup(ItemCount: 100000) 8.90 ms 218.48 μs 8.69 ms +2.5%
TopKSketchBenchmark.Dictionary_TopK(ItemCount: 1000) 30.7 ns 0.4 ns 31.4 ns -2.3%
TopKSketchBenchmark.TopKSketch_TopK(ItemCount: 1000) 1.25 μs 5.1 ns 1.26 μs -0.5%
TopKSketchBenchmark.Dictionary_TopK(ItemCount: 100000) 30.4 ns 1.1 ns 31.1 ns -2.3%
TopKSketchBenchmark.TopKSketch_TopK(ItemCount: 100000) 1.20 μs 6.4 ns 1.22 μs -1.8%
DisjointSetBenchmark.Dictionary_Union(ItemCount: 1000) 98.47 μs 764.4 ns 99.07 μs -0.6%
DisjointSetBenchmark.DisjointSet_Union(ItemCount: 1000) 27.24 μs 101.4 ns 26.76 μs +1.8%
DisjointSetBenchmark.Dictionary_Union(ItemCount: 100000) 44.77 ms 912.12 μs 42.22 ms +6.1%
DisjointSetBenchmark.DisjointSet_Union(ItemCount: 100000) 8.25 ms 56.47 μs 8.29 ms -0.5%
BloomFilterBenchmark.HashSet_Add(ItemCount: 1000) 12.15 μs 137.5 ns 12.36 μs -1.7%
HashCachingSetBenchmark.HashSet_Add(ItemCount: 1000) 12.21 μs 287.9 ns 12.19 μs +0.2%
SwissSetBenchmark.HashSet_Add(ItemCount: 1000) 12.33 μs 64.5 ns 12.92 μs -4.5%
BloomFilterBenchmark.BloomFilter_Add(ItemCount: 1000) 14.49 μs 13.0 ns 16.38 μs -11.5% ✅
HashCachingSetBenchmark.HashCachingSet_Add(ItemCount: 1000) 11.05 μs 189.4 ns 10.90 μs +1.4%
SwissSetBenchmark.SwissSet_Add(ItemCount: 1000) 26.43 μs 61.2 ns 26.68 μs -0.9%
BloomFilterBenchmark.HashSet_Add(ItemCount: 100000) 4.71 ms 88.73 μs 4.72 ms -0.3%
HashCachingSetBenchmark.HashSet_Add(ItemCount: 100000) 4.31 ms 487.14 μs 4.23 ms +1.8%
SwissSetBenchmark.HashSet_Add(ItemCount: 100000) 4.75 ms 41.88 μs 4.73 ms +0.4%
BloomFilterBenchmark.BloomFilter_Add(ItemCount: 100000) 1.10 ms 2.25 μs 1.24 ms -11.2% ✅
HashCachingSetBenchmark.HashCachingSet_Add(ItemCount: 100000) 5.29 ms 51.97 μs 5.20 ms +1.7%
SwissSetBenchmark.SwissSet_Add(ItemCount: 100000) 4.62 ms 52.75 μs 4.57 ms +1.2%
FrozenCeleritySetBenchmark.FrozenSet_Build(ItemCount: 1000) 164.30 μs 709.7 ns 172.10 μs -4.5%
FrozenCeleritySetBenchmark.FrozenCeleritySet_Build(ItemCount: 1000) 2.64 ms 91.80 μs 2.25 ms +17.3% ⚠️
FrozenCeleritySetBenchmark.FrozenSet_Build(ItemCount: 100000) 29.29 ms 405.65 μs 29.12 ms +0.6%
FrozenCeleritySetBenchmark.FrozenCeleritySet_Build(ItemCount: 100000) 1.44 s 55.13 ms 1.39 s +3.6%
BloomFilterBenchmark.HashSet_Contains(ItemCount: 1000) 4.74 μs 29.7 ns 4.74 μs -0.1%
FrozenCeleritySetBenchmark.FrozenSet_Contains(ItemCount: 1000) 6.87 μs 6.9 ns 7.09 μs -3.2%
HashCachingSetBenchmark.HashSet_Contains(ItemCount: 1000) 4.72 μs 5.4 ns 4.72 μs +0.0%
SwissSetBenchmark.HashSet_Contains(ItemCount: 1000) 4.74 μs 30.3 ns 4.73 μs +0.1%
BloomFilterBenchmark.BloomFilter_Contains(ItemCount: 1000) 12.52 μs 5.1 ns 14.18 μs -11.7% ✅
FrozenCeleritySetBenchmark.FrozenCeleritySet_Contains(ItemCount: 1000) 94.17 μs 3.99 μs 79.49 μs +18.5% ⚠️
HashCachingSetBenchmark.HashCachingSet_Contains(ItemCount: 1000) 2.53 μs 4.4 ns 2.53 μs +0.1%
SwissSetBenchmark.SwissSet_Contains(ItemCount: 1000) 2.86 μs 6.4 ns 2.86 μs -0.1%
BloomFilterBenchmark.HashSet_Contains(ItemCount: 100000) 1.57 ms 19.49 μs 1.52 ms +3.2%
FrozenCeleritySetBenchmark.FrozenSet_Contains(ItemCount: 100000) 1.96 ms 5.93 μs 1.85 ms +5.8%
HashCachingSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.57 ms 4.69 μs 1.57 ms +0.6%
SwissSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.58 ms 6.35 μs 1.58 ms -0.1%
BloomFilterBenchmark.BloomFilter_Contains(ItemCount: 100000) 869.25 μs 649.8 ns 982.54 μs -11.5% ✅
FrozenCeleritySetBenchmark.FrozenCeleritySet_Contains(ItemCount: 100000) 7.36 ms 15.10 μs 8.17 ms -10.0% ✅
HashCachingSetBenchmark.HashCachingSet_Contains(ItemCount: 100000) 730.02 μs 3.27 μs 725.69 μs +0.6%
SwissSetBenchmark.SwissSet_Contains(ItemCount: 100000) 631.50 μs 1.88 μs 645.01 μs -2.1%
BloomFilterBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 4.54 μs 5.9 ns 4.60 μs -1.3%
HashCachingSetBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 4.66 μs 118.2 ns 4.54 μs +2.6%
SwissSetBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 4.54 μs 2.9 ns 4.55 μs -0.3%
BloomFilterBenchmark.BloomFilter_ContainsMissing(ItemCount: 1000) 3.52 μs 8.6 ns 3.98 μs -11.5% ✅
HashCachingSetBenchmark.HashCachingSet_ContainsMissing(ItemCount: 1000) 2.96 μs 7.5 ns 2.96 μs +0.1%
SwissSetBenchmark.SwissSet_ContainsMissing(ItemCount: 1000) 2.37 μs 3.1 ns 2.37 μs -0.2%
BloomFilterBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 1.93 ms 1.68 μs 2.00 ms -3.7%
HashCachingSetBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 1.94 ms 6.58 μs 1.94 ms +0.1%
SwissSetBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 1.95 ms 5.09 μs 2.01 ms -3.1%
BloomFilterBenchmark.BloomFilter_ContainsMissing(ItemCount: 100000) 1.49 ms 790.9 ns 1.67 ms -10.6% ✅
HashCachingSetBenchmark.HashCachingSet_ContainsMissing(ItemCount: 100000) 1.13 ms 2.21 μs 1.13 ms -0.2%
SwissSetBenchmark.SwissSet_ContainsMissing(ItemCount: 100000) 338.82 μs 1.56 μs 342.21 μs -1.0%
CelerityMultiSetBenchmark.Dictionary_Count(ItemCount: 1000) 10.40 μs 82.8 ns 9.78 μs +6.3%
CelerityMultiSetBenchmark.CelerityMultiSet_Count(ItemCount: 1000) 5.37 μs 174.7 ns 5.31 μs +1.1%
CelerityMultiSetBenchmark.Dictionary_Count(ItemCount: 100000) 1.45 ms 17.55 μs 1.33 ms +9.3%
CelerityMultiSetBenchmark.CelerityMultiSet_Count(ItemCount: 100000) 754.23 μs 25.03 μs 706.31 μs +6.8%
SwissDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 13.29 μs 521.7 ns 12.93 μs +2.8%
SwissDictionaryBenchmark.SwissDictionary_Insert(ItemCount: 1000) 28.33 μs 77.2 ns 29.32 μs -3.4%
SwissDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 4.69 ms 89.30 μs 4.94 ms -5.2%
SwissDictionaryBenchmark.SwissDictionary_Insert(ItemCount: 100000) 3.93 ms 21.16 μs 3.83 ms +2.6%
CelerityMultiSetBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.37 μs 2.7 ns 4.64 μs -5.8%
SwissDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.75 μs 27.5 ns 4.84 μs -1.7%
CelerityMultiSetBenchmark.CelerityMultiSet_Lookup(ItemCount: 1000) 1.72 μs 1.4 ns 1.95 μs -11.8% ✅
SwissDictionaryBenchmark.SwissDictionary_Lookup(ItemCount: 1000) 3.01 μs 20.1 ns 2.90 μs +3.7%
CelerityMultiSetBenchmark.Dictionary_Lookup(ItemCount: 100000) 650.80 μs 780.4 ns 558.84 μs +16.5% ⚠️
SwissDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.60 ms 2.66 μs 1.60 ms -0.2%
CelerityMultiSetBenchmark.CelerityMultiSet_Lookup(ItemCount: 100000) 189.94 μs 288.0 ns 215.19 μs -11.7% ✅
SwissDictionaryBenchmark.SwissDictionary_Lookup(ItemCount: 100000) 802.28 μs 5.50 μs 676.49 μs +18.6% ⚠️
FenwickTreeBenchmark.Array_Mixed(ItemCount: 1000) 185.80 μs 377.7 ns 202.87 μs -8.4%
FenwickTreeBenchmark.FenwickTree_Mixed(ItemCount: 1000) 11.00 μs 18.6 ns 11.01 μs -0.1%
FenwickTreeBenchmark.Array_Mixed(ItemCount: 100000) 173.86 ms 1.37 ms 184.12 ms -5.6%
FenwickTreeBenchmark.FenwickTree_Mixed(ItemCount: 100000) 629.54 μs 13.57 μs 632.56 μs -0.5%
FenwickTreeBenchmark.Array_RangeSum(ItemCount: 1000) 223.39 μs 375.3 ns 248.97 μs -10.3% ✅
FenwickTreeBenchmark.FenwickTree_RangeSum(ItemCount: 1000) 7.45 μs 3.8 ns 6.85 μs +8.9%
FenwickTreeBenchmark.Array_RangeSum(ItemCount: 100000) 209.67 ms 12.59 ms 178.79 ms +17.3% ⚠️
FenwickTreeBenchmark.FenwickTree_RangeSum(ItemCount: 100000) 324.59 μs 1.20 μs 209.29 μs +55.1% ⚠️
CelerityMultiSetBenchmark.Dictionary_Remove(ItemCount: 1000) 52.13 μs 6.25 μs 48.14 μs +8.3%
SwissDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 84.24 μs 8.38 μs 77.88 μs +8.2%
CelerityMultiSetBenchmark.CelerityMultiSet_Remove(ItemCount: 1000) 81.15 μs 1.98 μs 82.84 μs -2.0%
SwissDictionaryBenchmark.SwissDictionary_Remove(ItemCount: 1000) 79.62 μs 4.09 μs 69.88 μs +13.9% ⚠️
HashCachingSetBenchmark.HashSet_Remove(ItemCount: 1000) 28.26 μs 4.56 μs 27.35 μs +3.4%
SwissSetBenchmark.HashSet_Remove(ItemCount: 1000) 29.42 μs 4.04 μs 30.42 μs -3.3%
HashCachingSetBenchmark.HashCachingSet_Remove(ItemCount: 1000) 111.96 μs 6.60 μs 115.30 μs -2.9%
SwissSetBenchmark.SwissSet_Remove(ItemCount: 1000) 75.20 μs 11.73 μs 71.39 μs +5.3%
CelerityMultiSetBenchmark.Dictionary_Remove(ItemCount: 100000) 553.75 μs 12.74 μs 557.27 μs -0.6%
SwissDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.05 ms 15.64 μs 2.00 ms +2.2%
CelerityMultiSetBenchmark.CelerityMultiSet_Remove(ItemCount: 100000) 1.26 ms 21.18 μs 1.42 ms -10.9% ✅
SwissDictionaryBenchmark.SwissDictionary_Remove(ItemCount: 100000) 1.62 ms 34.38 μs 1.30 ms +25.1% ⚠️
HashCachingSetBenchmark.HashSet_Remove(ItemCount: 100000) 1.72 ms 14.56 μs 1.71 ms +0.7%
SwissSetBenchmark.HashSet_Remove(ItemCount: 100000) 1.72 ms 15.90 μs 1.72 ms -0.2%
HashCachingSetBenchmark.HashCachingSet_Remove(ItemCount: 100000) 1.49 ms 48.31 μs 1.55 ms -3.6%
SwissSetBenchmark.SwissSet_Remove(ItemCount: 100000) 1.06 ms 15.11 μs 1.08 ms -1.5%
EnumSetBenchmark.HashSet_Add 567.9 ns 7.4 ns 625.0 ns -9.1% ✅
EnumSetBenchmark.EnumSet_Add 85.5 ns 1.8 ns 88.6 ns -3.5%
RobinHoodSetBenchmark.HashSet_Add(ItemCount: 1000) 12.55 μs 468.8 ns 11.80 μs +6.3%
SparseSetBenchmark.HashSet_Add(ItemCount: 1000) 7.28 μs 341.8 ns 7.96 μs -8.5%
RobinHoodSetBenchmark.RobinHoodSet_Add(ItemCount: 1000) 17.70 μs 268.6 ns 17.15 μs +3.2%
SparseSetBenchmark.SparseSet_Add(ItemCount: 1000) 6.00 μs 43.1 ns 6.44 μs -6.8%
RobinHoodSetBenchmark.HashSet_Add(ItemCount: 100000) 4.35 ms 493.30 μs 4.56 ms -4.7%
SparseSetBenchmark.HashSet_Add(ItemCount: 100000) 1.71 ms 36.29 μs 1.73 ms -1.0%
RobinHoodSetBenchmark.RobinHoodSet_Add(ItemCount: 100000) 6.50 ms 223.17 μs 6.24 ms +4.3%
SparseSetBenchmark.SparseSet_Add(ItemCount: 100000) 1.48 ms 70.28 μs 1.49 ms -0.6%
XorFilterBenchmark.HashSet_Build(ItemCount: 1000) 7.96 μs 47.5 ns 6.19 μs +28.7% ⚠️
XorFilterBenchmark.XorFilter_Build(ItemCount: 1000) 39.32 μs 291.1 ns 33.17 μs +18.5% ⚠️
XorFilterBenchmark.HashSet_Build(ItemCount: 100000) 2.12 ms 35.58 μs 1.60 ms +32.2% ⚠️
XorFilterBenchmark.XorFilter_Build(ItemCount: 100000) 12.42 ms 249.43 μs 9.45 ms +31.4% ⚠️
SparseSetBenchmark.HashSet_ClearRefill(ItemCount: 1000) 6.39 μs 358.3 ns 6.03 μs +6.1%
SparseSetBenchmark.SparseSet_ClearRefill(ItemCount: 1000) 4.46 μs 10.2 ns 4.56 μs -2.2%
SparseSetBenchmark.HashSet_ClearRefill(ItemCount: 100000) 1.36 ms 4.18 μs 1.38 ms -1.7%
SparseSetBenchmark.SparseSet_ClearRefill(ItemCount: 100000) 669.05 μs 31.51 μs 643.58 μs +4.0%
EnumSetBenchmark.HashSet_Contains 175.3 ns 0.1 ns 175.7 ns -0.2%
EnumSetBenchmark.EnumSet_Contains 46.0 ns 0.0 ns 46.0 ns -0.1%
RobinHoodSetBenchmark.HashSet_Contains(ItemCount: 1000) 4.72 μs 6.5 ns 4.72 μs +0.0%
SparseSetBenchmark.HashSet_Contains(ItemCount: 1000) 4.65 μs 7.4 ns 4.65 μs +0.1%
XorFilterBenchmark.HashSet_Contains(ItemCount: 1000) 4.74 μs 34.8 ns 3.05 μs +55.3% ⚠️
RobinHoodSetBenchmark.RobinHoodSet_Contains(ItemCount: 1000) 2.51 μs 10.3 ns 2.50 μs +0.2%
SparseSetBenchmark.SparseSet_Contains(ItemCount: 1000) 1.33 μs 40.4 ns 1.28 μs +3.4%
XorFilterBenchmark.XorFilter_Contains(ItemCount: 1000) 6.77 μs 3.1 ns 5.31 μs +27.6% ⚠️
RobinHoodSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.55 ms 51.69 μs 1.58 ms -2.3%
SparseSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.34 ms 5.38 μs 1.30 ms +3.2%
XorFilterBenchmark.HashSet_Contains(ItemCount: 100000) 1.60 ms 7.15 μs 1.27 ms +25.7% ⚠️
RobinHoodSetBenchmark.RobinHoodSet_Contains(ItemCount: 100000) 742.89 μs 4.38 μs 744.04 μs -0.2%
SparseSetBenchmark.SparseSet_Contains(ItemCount: 100000) 256.36 μs 2.09 μs 255.97 μs +0.1%
XorFilterBenchmark.XorFilter_Contains(ItemCount: 100000) 703.71 μs 378.3 ns 570.81 μs +23.3% ⚠️
RobinHoodSetBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 4.54 μs 5.8 ns 4.58 μs -0.7%
XorFilterBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 4.54 μs 4.5 ns 3.14 μs +44.7% ⚠️
RobinHoodSetBenchmark.RobinHoodSet_ContainsMissing(ItemCount: 1000) 2.74 μs 2.2 ns 2.74 μs -0.0%
XorFilterBenchmark.XorFilter_ContainsMissing(ItemCount: 1000) 6.78 μs 11.7 ns 5.36 μs +26.4% ⚠️
RobinHoodSetBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 1.93 ms 7.62 μs 1.94 ms -0.4%
XorFilterBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 1.91 ms 17.79 μs 1.62 ms +18.4% ⚠️
RobinHoodSetBenchmark.RobinHoodSet_ContainsMissing(ItemCount: 100000) 1.19 ms 5.63 μs 1.18 ms +0.2%
XorFilterBenchmark.XorFilter_ContainsMissing(ItemCount: 100000) 705.44 μs 701.1 ns 579.73 μs +21.7% ⚠️
SmallDictionaryBenchmark.Dictionary_Insert(ItemCount: 8) 162.2 ns 1.7 ns 136.6 ns +18.8% ⚠️
SmallDictionaryBenchmark.SmallDictionary_Insert(ItemCount: 8) 85.4 ns 0.5 ns 76.6 ns +11.5% ⚠️
SmallDictionaryBenchmark.Dictionary_Insert(ItemCount: 64) 771.8 ns 8.0 ns 652.4 ns +18.3% ⚠️
SmallDictionaryBenchmark.SmallDictionary_Insert(ItemCount: 64) 1.08 μs 8.0 ns 987.5 ns +9.0%
HashCachingDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 13.31 μs 330.5 ns 10.71 μs +24.2% ⚠️
HashCachingDictionaryBenchmark.HashCachingDictionary_Insert(ItemCount: 1000) 11.49 μs 119.9 ns 8.82 μs +30.2% ⚠️
HashCachingDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 4.73 ms 78.96 μs 4.05 ms +16.9% ⚠️
HashCachingDictionaryBenchmark.HashCachingDictionary_Insert(ItemCount: 100000) 6.53 ms 274.85 μs 6.14 ms +6.4%
SmallDictionaryBenchmark.Dictionary_Lookup(ItemCount: 8) 36.8 ns 0.1 ns 23.1 ns +59.2% ⚠️
SmallDictionaryBenchmark.SmallDictionary_Lookup(ItemCount: 8) 29.1 ns 4.4 ns 26.4 ns +10.1%
SmallDictionaryBenchmark.Dictionary_Lookup(ItemCount: 64) 297.5 ns 2.1 ns 197.9 ns +50.4% ⚠️
SmallDictionaryBenchmark.SmallDictionary_Lookup(ItemCount: 64) 1.10 μs 9.8 ns 883.8 ns +25.0% ⚠️
HashCachingDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.71 μs 9.7 ns 3.02 μs +56.2% ⚠️
HashCachingDictionaryBenchmark.HashCachingDictionary_Lookup(ItemCount: 1000) 2.71 μs 8.3 ns 2.16 μs +25.1% ⚠️
HashCachingDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.62 ms 2.31 μs 1.30 ms +24.6% ⚠️
HashCachingDictionaryBenchmark.HashCachingDictionary_Lookup(ItemCount: 100000) 814.24 μs 3.81 μs 830.82 μs -2.0%
EnumSetBenchmark.HashSet_Remove 4.01 μs 172.0 ns 3.35 μs +19.8% ⚠️
EnumSetBenchmark.EnumSet_Remove 1.05 μs 38.1 ns 1.07 μs -1.0%
SmallDictionaryBenchmark.Dictionary_Remove(ItemCount: 8) 1.42 μs 364.6 ns 2.29 μs -37.9%
SmallDictionaryBenchmark.SmallDictionary_Remove(ItemCount: 8) 1.42 μs 254.9 ns 1.60 μs -11.2%
SmallDictionaryBenchmark.Dictionary_Remove(ItemCount: 64) 6.28 μs 297.4 ns 3.62 μs +73.4% ⚠️
SmallDictionaryBenchmark.SmallDictionary_Remove(ItemCount: 64) 21.70 μs 598.6 ns 23.95 μs -9.4%
HashCachingDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 86.30 μs 7.12 μs 64.95 μs +32.9% ⚠️
HashCachingDictionaryBenchmark.HashCachingDictionary_Remove(ItemCount: 1000) 114.86 μs 7.25 μs 91.71 μs +25.2% ⚠️
RobinHoodSetBenchmark.HashSet_Remove(ItemCount: 1000) 31.81 μs 3.86 μs 28.02 μs +13.5%
SparseSetBenchmark.HashSet_Remove(ItemCount: 1000) 28.51 μs 4.28 μs 27.09 μs +5.2%
RobinHoodSetBenchmark.RobinHoodSet_Remove(ItemCount: 1000) 116.36 μs 10.70 μs 108.50 μs +7.2%
SparseSetBenchmark.SparseSet_Remove(ItemCount: 1000) 25.96 μs 3.90 μs 22.22 μs +16.8%
HashCachingDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.03 ms 14.56 μs 1.61 ms +26.5% ⚠️
HashCachingDictionaryBenchmark.HashCachingDictionary_Remove(ItemCount: 100000) 1.75 ms 31.09 μs 2.62 ms -33.1%
RobinHoodSetBenchmark.HashSet_Remove(ItemCount: 100000) 1.73 ms 25.12 μs 1.71 ms +1.1%
SparseSetBenchmark.HashSet_Remove(ItemCount: 100000) 1.50 ms 15.92 μs 1.49 ms +0.1%
RobinHoodSetBenchmark.RobinHoodSet_Remove(ItemCount: 100000) 1.39 ms 51.22 μs 1.37 ms +1.1%
SparseSetBenchmark.SparseSet_Remove(ItemCount: 100000) 794.81 μs 13.66 μs 794.25 μs +0.1%
EnumSetBenchmark.HashSet_Union 417.5 ns 5.7 ns 447.1 ns -6.6%
EnumSetBenchmark.EnumSet_Union 21.7 ns 0.1 ns 23.3 ns -6.9%
Hashers (111)
Benchmark This PR StdDev main Δ
StringHasherBenchmark.Bcl_GetHashCode(Shape: ShortAscii) 15.39 μs 21.1 ns 15.40 μs -0.1%
StringHasherBenchmark.EqualityComparer_Default(Shape: ShortAscii) 15.36 μs 17.5 ns 15.36 μs -0.0%
StringHasherBenchmark.Djb2(Shape: ShortAscii) 22.74 μs 48.7 ns 22.75 μs -0.0%
StringHasherBenchmark.Djb2A(Shape: ShortAscii) 22.72 μs 41.1 ns 22.73 μs -0.1%
StringHasherBenchmark.Sdbm(Shape: ShortAscii) 33.13 μs 24.9 ns 33.13 μs -0.0%
StringHasherBenchmark.Elf(Shape: ShortAscii) 44.75 μs 197.5 ns 44.72 μs +0.1%
StringHasherBenchmark.Crc32(Shape: ShortAscii) 50.68 μs 335.0 ns 50.56 μs +0.2%
StringHasherBenchmark.Adler32(Shape: ShortAscii) 96.47 μs 44.9 ns 96.50 μs -0.0%
StringHasherBenchmark.FnV1(Shape: ShortAscii) 27.15 μs 29.6 ns 27.14 μs +0.0%
StringHasherBenchmark.FnV1_64(Shape: ShortAscii) 25.81 μs 52.1 ns 25.81 μs -0.0%
StringHasherBenchmark.FnV1A(Shape: ShortAscii) 11.06 μs 25.2 ns 11.06 μs -0.0%
StringHasherBenchmark.FnV1A_Full(Shape: ShortAscii) 25.85 μs 23.0 ns 25.85 μs +0.0%
StringHasherBenchmark.FnV1A_64(Shape: ShortAscii) 27.89 μs 17.5 ns 27.88 μs +0.0%
StringHasherBenchmark.JenkinsOaat(Shape: ShortAscii) 39.54 μs 31.8 ns 39.53 μs +0.0%
StringHasherBenchmark.Murmur2(Shape: ShortAscii) 15.42 μs 50.1 ns 15.42 μs -0.1%
StringHasherBenchmark.Murmur3(Shape: ShortAscii) 17.17 μs 37.3 ns 17.14 μs +0.2%
StringHasherBenchmark.XxHash32(Shape: ShortAscii) 16.92 μs 14.0 ns 16.91 μs +0.1%
StringHasherBenchmark.XxHash64(Shape: ShortAscii) 18.38 μs 15.4 ns 18.39 μs -0.1%
StringHasherBenchmark.XxHash3(Shape: ShortAscii) 15.45 μs 20.1 ns 15.45 μs -0.0%
StringHasherBenchmark.CityHash64(Shape: ShortAscii) 15.61 μs 32.6 ns 15.57 μs +0.3%
StringHasherBenchmark.MetroHash64(Shape: ShortAscii) 15.46 μs 27.4 ns 15.46 μs -0.0%
StringHasherBenchmark.SipHash13(Shape: ShortAscii) 27.66 μs 46.7 ns 27.64 μs +0.1%
StringHasherBenchmark.SipHash24(Shape: ShortAscii) 37.92 μs 42.3 ns 37.91 μs +0.0%
StringHasherBenchmark.HalfSipHash24(Shape: ShortAscii) 49.78 μs 108.3 ns 49.79 μs -0.0%
StringHasherBenchmark.HighwayHash64(Shape: ShortAscii) 445.04 μs 16.77 μs 440.05 μs +1.1%
StringHasherBenchmark.XxHash64_Hash64(Shape: ShortAscii) 17.35 μs 11.2 ns 17.36 μs -0.0%
StringHasherBenchmark.SipHash24_Hash64(Shape: ShortAscii) 37.89 μs 25.6 ns 37.89 μs +0.0%
StringHasherBenchmark.Bcl_GetHashCode(Shape: LongAscii) 97.00 μs 99.0 ns 96.94 μs +0.1%
StringHasherBenchmark.EqualityComparer_Default(Shape: LongAscii) 96.65 μs 66.2 ns 96.57 μs +0.1%
StringHasherBenchmark.Djb2(Shape: LongAscii) 223.88 μs 74.7 ns 223.99 μs -0.1%
StringHasherBenchmark.Djb2A(Shape: LongAscii) 223.85 μs 47.6 ns 223.72 μs +0.1%
StringHasherBenchmark.Sdbm(Shape: LongAscii) 308.27 μs 178.7 ns 308.22 μs +0.0%
StringHasherBenchmark.Elf(Shape: LongAscii) 579.22 μs 293.7 ns 578.95 μs +0.0%
StringHasherBenchmark.Crc32(Shape: LongAscii) 591.42 μs 267.7 ns 590.61 μs +0.1%
StringHasherBenchmark.Adler32(Shape: LongAscii) 786.94 μs 210.5 ns 786.96 μs -0.0%
StringHasherBenchmark.FnV1(Shape: LongAscii) 289.26 μs 135.4 ns 289.26 μs -0.0%
StringHasherBenchmark.FnV1_64(Shape: LongAscii) 282.99 μs 76.5 ns 283.04 μs -0.0%
StringHasherBenchmark.FnV1A(Shape: LongAscii) 123.03 μs 112.7 ns 122.99 μs +0.0%
StringHasherBenchmark.FnV1A_Full(Shape: LongAscii) 282.49 μs 240.2 ns 282.34 μs +0.1%
StringHasherBenchmark.FnV1A_64(Shape: LongAscii) 286.99 μs 147.3 ns 286.91 μs +0.0%
StringHasherBenchmark.JenkinsOaat(Shape: LongAscii) 378.65 μs 122.2 ns 378.65 μs -0.0%
StringHasherBenchmark.Murmur2(Shape: LongAscii) 101.72 μs 73.5 ns 101.16 μs +0.6%
StringHasherBenchmark.Murmur3(Shape: LongAscii) 115.68 μs 86.4 ns 115.74 μs -0.0%
StringHasherBenchmark.XxHash32(Shape: LongAscii) 73.57 μs 149.4 ns 73.58 μs -0.0%
StringHasherBenchmark.XxHash64(Shape: LongAscii) 95.09 μs 749.5 ns 94.58 μs +0.5%
StringHasherBenchmark.XxHash3(Shape: LongAscii) 82.09 μs 315.8 ns 81.68 μs +0.5%
StringHasherBenchmark.CityHash64(Shape: LongAscii) 124.51 μs 1.40 μs 124.29 μs +0.2%
StringHasherBenchmark.MetroHash64(Shape: LongAscii) 74.90 μs 288.3 ns 74.77 μs +0.2%
StringHasherBenchmark.SipHash13(Shape: LongAscii) 117.24 μs 85.9 ns 117.18 μs +0.0%
StringHasherBenchmark.SipHash24(Shape: LongAscii) 162.58 μs 349.9 ns 161.64 μs +0.6%
StringHasherBenchmark.HalfSipHash24(Shape: LongAscii) 251.00 μs 250.3 ns 250.88 μs +0.0%
StringHasherBenchmark.HighwayHash64(Shape: LongAscii) 831.50 μs 12.81 μs 851.78 μs -2.4%
StringHasherBenchmark.XxHash64_Hash64(Shape: LongAscii) 87.46 μs 1.14 μs 87.52 μs -0.1%
StringHasherBenchmark.SipHash24_Hash64(Shape: LongAscii) 162.38 μs 261.0 ns 162.33 μs +0.0%
StringHasherBenchmark.Bcl_GetHashCode(Shape: NonAscii) 22.88 μs 14.1 ns 22.92 μs -0.2%
StringHasherBenchmark.EqualityComparer_Default(Shape: NonAscii) 22.85 μs 18.9 ns 22.83 μs +0.1%
StringHasherBenchmark.Djb2(Shape: NonAscii) 43.07 μs 36.7 ns 43.07 μs +0.0%
StringHasherBenchmark.Djb2A(Shape: NonAscii) 43.07 μs 21.7 ns 43.05 μs +0.1%
StringHasherBenchmark.Sdbm(Shape: NonAscii) 61.66 μs 40.7 ns 61.65 μs +0.0%
StringHasherBenchmark.Elf(Shape: NonAscii) 100.23 μs 140.0 ns 100.15 μs +0.1%
StringHasherBenchmark.Crc32(Shape: NonAscii) 103.69 μs 251.7 ns 103.55 μs +0.1%
StringHasherBenchmark.Adler32(Shape: NonAscii) 174.53 μs 188.3 ns 174.43 μs +0.1%
StringHasherBenchmark.FnV1(Shape: NonAscii) 48.44 μs 42.5 ns 48.42 μs +0.0%
StringHasherBenchmark.FnV1_64(Shape: NonAscii) 50.21 μs 33.1 ns 50.28 μs -0.1%
StringHasherBenchmark.FnV1A(Shape: NonAscii) 22.00 μs 33.8 ns 22.02 μs -0.1%
StringHasherBenchmark.FnV1A_Full(Shape: NonAscii) 46.14 μs 52.5 ns 46.11 μs +0.1%
StringHasherBenchmark.FnV1A_64(Shape: NonAscii) 50.06 μs 53.8 ns 50.03 μs +0.1%
StringHasherBenchmark.JenkinsOaat(Shape: NonAscii) 73.37 μs 55.6 ns 73.33 μs +0.1%
StringHasherBenchmark.Murmur2(Shape: NonAscii) 27.00 μs 160.8 ns 27.03 μs -0.1%
StringHasherBenchmark.Murmur3(Shape: NonAscii) 31.66 μs 103.9 ns 31.64 μs +0.1%
StringHasherBenchmark.XxHash32(Shape: NonAscii) 23.87 μs 21.3 ns 23.89 μs -0.1%
StringHasherBenchmark.XxHash64(Shape: NonAscii) 30.05 μs 33.3 ns 30.11 μs -0.2%
StringHasherBenchmark.XxHash3(Shape: NonAscii) 23.60 μs 117.1 ns 23.55 μs +0.2%
StringHasherBenchmark.CityHash64(Shape: NonAscii) 22.31 μs 41.4 ns 22.26 μs +0.2%
StringHasherBenchmark.MetroHash64(Shape: NonAscii) 25.89 μs 20.0 ns 25.88 μs +0.0%
StringHasherBenchmark.SipHash13(Shape: NonAscii) 37.91 μs 90.4 ns 37.87 μs +0.1%
StringHasherBenchmark.SipHash24(Shape: NonAscii) 50.13 μs 72.7 ns 50.14 μs -0.0%
StringHasherBenchmark.HalfSipHash24(Shape: NonAscii) 73.74 μs 1.15 μs 74.23 μs -0.7%
StringHasherBenchmark.HighwayHash64(Shape: NonAscii) 476.98 μs 3.56 μs 479.79 μs -0.6%
StringHasherBenchmark.XxHash64_Hash64(Shape: NonAscii) 28.95 μs 35.9 ns 28.99 μs -0.1%
StringHasherBenchmark.SipHash24_Hash64(Shape: NonAscii) 51.77 μs 564.9 ns 51.19 μs +1.1%
IntegerHasherBenchmark.Guid_Bcl 1.51 μs 20.0 ns 1.49 μs +1.4%
IntegerHasherBenchmark.Guid_EqualityComparer 3.45 μs 41.9 ns 3.44 μs +0.1%
IntegerHasherBenchmark.Guid_Celerity 9.14 μs 4.5 ns 9.10 μs +0.4%
IntegerHasherBenchmark.Guid_Celerity_Hash64 9.10 μs 6.7 ns 9.14 μs -0.5%
IntegerHasherBenchmark.Int32_Bcl 774.8 ns 0.8 ns 771.1 ns +0.5%
IntegerHasherBenchmark.Int32_EqualityComparer 758.8 ns 4.9 ns 763.9 ns -0.7%
IntegerHasherBenchmark.Int32_Identity 764.2 ns 1.8 ns 764.1 ns +0.0%
IntegerHasherBenchmark.Int32_WangNaive 1.41 μs 0.3 ns 1.41 μs -0.0%
IntegerHasherBenchmark.Int32_Wang 3.42 μs 3.2 ns 3.42 μs +0.0%
IntegerHasherBenchmark.Int32_Murmur3 3.05 μs 1.2 ns 3.05 μs -0.0%
IntegerHasherBenchmark.Int64_Bcl 1.68 μs 0.7 ns 1.68 μs -0.1%
IntegerHasherBenchmark.Int64_EqualityComparer 1.41 μs 0.6 ns 1.41 μs -0.0%
IntegerHasherBenchmark.Int64_Identity 765.2 ns 1.2 ns 764.6 ns +0.1%
IntegerHasherBenchmark.Int64_WangNaive 2.10 μs 0.8 ns 2.11 μs -0.1%
IntegerHasherBenchmark.Int64_Wang 4.70 μs 3.7 ns 4.70 μs -0.0%
IntegerHasherBenchmark.Int64_Murmur3 2.68 μs 1.4 ns 2.68 μs -0.2%
IntegerHasherBenchmark.Int64_Wang_Hash64 4.70 μs 1.8 ns 4.70 μs -0.1%
IntegerHasherBenchmark.Int64_Murmur3_Hash64 2.68 μs 0.9 ns 2.68 μs -0.0%
IntegerHasherBenchmark.UInt32_Bcl 774.0 ns 0.8 ns 774.3 ns -0.0%
IntegerHasherBenchmark.UInt32_EqualityComparer 764.2 ns 1.0 ns 764.8 ns -0.1%
IntegerHasherBenchmark.UInt32_Default 1.41 μs 0.6 ns 1.41 μs +0.0%
IntegerHasherBenchmark.UInt32_Wang 3.41 μs 5.1 ns 3.42 μs -0.0%
IntegerHasherBenchmark.UInt32_Murmur3 3.05 μs 1.5 ns 3.05 μs -0.0%
IntegerHasherBenchmark.UInt64_Bcl 1.68 μs 0.4 ns 1.68 μs -0.0%
IntegerHasherBenchmark.UInt64_EqualityComparer 1.41 μs 0.2 ns 1.41 μs -0.2%
IntegerHasherBenchmark.UInt64_Default 2.68 μs 0.9 ns 2.68 μs -0.1%
IntegerHasherBenchmark.UInt64_Wang 4.70 μs 2.5 ns 4.70 μs -0.1%
IntegerHasherBenchmark.UInt64_WangNaive 2.10 μs 0.9 ns 2.11 μs -0.1%
IntegerHasherBenchmark.UInt64_Default_Hash64 2.68 μs 1.9 ns 2.68 μs +0.0%
IntegerHasherBenchmark.UInt64_Wang_Hash64 4.70 μs 5.3 ns 4.70 μs +0.1%

Same-runner A/B (sharded 8-way): main (e40127e) 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.

@marius-bughiu

Copy link
Copy Markdown
Owner Author

CI status — one benchmark shard hit the #335 timeout; re-running it

Everything is green except one benchmark shard, and it is worth writing down what happened because the obvious reading ("the PR that adds a benchmark class timed out a benchmark shard" — i.e. #300) is not what this is.

17 of 18 checks passed: build-and-test on all three OSes, coverage, release-gates, dashboard-coverage, all three AOT publishes, and 7 of 8 benchmark shards. The aggregate & report job also succeeded, so the dashboard data was still stitched together.

Shard 5 ran 02:57:43 → 04:57:58 — exactly 120 minutes, the workflow's timeout-minutes, which GitHub surfaces as cancelled rather than failure.

It is not this PR's benchmark class. I pulled the per-shard logs. CompressedIntSetBenchmark was packed onto shard 2, which finished in 88 minutes — the second-fastest of the eight. Shard 5 held BTreeSet, Deque, DisjointSet, IntDictionary, IntSet, LongDictionary, PooledCeleritySet, SparseSet, SwissSet, TopKSketch and Trie — all pre-existing classes.

What it is: #335, exactly. Every shard ran long today — 77, 88, 92, 97, 99, 99, 103 minutes and then shard 5's 120 — against a ceiling sized for the heaviest shard to sit "comfortably inside" it. That is the ~2x slowdown #335 describes when benchmark runs overlap. I contributed to the overlap: this PR went through seven pushes across the review rounds, each starting an 8-shard run. I cancelled each superseded run as I went, but cancellation is not instantaneous and the runners were contended regardless.

I have re-run shard 5 alone, with no other run competing for runners. Will report back.

Two things for the maintainer, neither blocking:

@marius-bughiu

Copy link
Copy Markdown
Owner Author

CI is green — 18/18

Shard 5 passed on the isolated re-run. The whole Benchmarks run is completed/success, and the PR now shows 18 of 18 checks passing with no failures.

The re-run took 80 minutes (05:01:57 → 06:22:16) against the same slice that had hit the 120-minute ceiling the first time, with no other run in the repo competing. So both factors were real, and I want to be precise about the split rather than leave my earlier comment's emphasis standing unqualified:

  • Shard 5's slice is genuinely heavy — 80 minutes on a quiet runner, two-thirds of the budget with nothing else going on. That is not contention, that is the slice.
  • Contention supplied the other 40+ minutes. The same slice went from 80 to over 120 when it ran alongside its seven siblings and the residue of the superseded runs my push cadence created.

Neither is caused by this PR: CompressedIntSetBenchmark is on shard 2, which came in at 88 minutes. But the margin on shard 5 is thinner than the workflow comment's "comfortably inside the limit" assumes — worth a re-measure when #319 (no concurrency group) and #300 are picked up, since the suite has grown by several classes since 8 shards were sized.

Nothing outstanding on my side: the last Copilot round came back with no comments and, for the first time in this PR, no suppressed block either.

@marius-bughiu
marius-bughiu merged commit 69cb972 into main Aug 1, 2026
27 of 28 checks passed
@marius-bughiu
marius-bughiu deleted the feat/issue-310-compressed-int-set branch August 1, 2026 12:11
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 CompressedIntSet — a Roaring-style compressed set of 32-bit integers

2 participants