Skip to content

feat(primitives): add SortedSpan — merge-based set algebra over sorted spans - #342

Merged
marius-bughiu merged 6 commits into
mainfrom
feat/issue-313-sorted-span
Aug 5, 2026
Merged

feat(primitives): add SortedSpan — merge-based set algebra over sorted spans#342
marius-bughiu merged 6 commits into
mainfrom
feat/issue-313-sorted-span

Conversation

@marius-bughiu

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

Copy link
Copy Markdown
Owner

Closes #313.

SortedSpan ships in Celerity.Primitives: merge-based set algebra over spans that are already sorted ascending.

int  Intersect<T>(ReadOnlySpan<T> a, ReadOnlySpan<T> b, Span<T> destination);
int  Union<T>(ReadOnlySpan<T> a, ReadOnlySpan<T> b, Span<T> destination);
int  Except<T>(ReadOnlySpan<T> a, ReadOnlySpan<T> b, Span<T> destination);
int  IntersectCount<T>(ReadOnlySpan<T> a, ReadOnlySpan<T> b);   // allocation-free
bool Overlaps<T>(ReadOnlySpan<T> a, ReadOnlySpan<T> b);         // allocation-free

The BCL has no set operation over spans anywhere — MemoryExtensions has none, TensorPrimitives has none, .NET 10 added none — so the two things a developer writes today (HashSet<T>.IntersectWith, LINQ Intersect) allocate a table and hash every element instead of using the order the data already has.

The measured win (the issue's kill criterion)

1,000,000 x 1,000,000 sorted distinct int spans over a 2,000,000 universe, ~50% overlap:

Operation HashSet<int> LINQ SortedSpan Speedup
Intersect 25.7 ms 34.8 ms 6.1 ms 4.2x (5.7x vs LINQ)
Union 26.5 ms 6.6 ms 4.0x
Except 17.6 ms 6.4 ms 2.8x
Count common 15.9 ms 6.1 ms 2.6x

Allocation on that intersect: 17.9 MB (HashSet) / 17.7 MB (LINQ) / 0 bytes (SortedSpan).

Asymmetric 1k against 10M (the galloping shape): 0.37 ms vs 94.3 ms257x, and 422x for IntersectCount. The kill criterion ("if the scalar merge does not beat HashSet<int>.IntersectWith at 1M elements, close the whole issue") clears with room to spare, so the scalar merge ships.

Design calls worth reviewing

  • No Vector256 path, per the issue's own condition. The scalar merge is already memory-bound at 1M x 1M (~6 ms for one sequential pass over both inputs) and merge is branch-heavy enough that vectorizing it is frequently a wash; the >=25% bar was never plausible enough to justify a second implementation.
  • Generic over IComparisonOperators<T, T, bool>, not hand-written int / long / uint / ulong overloads. The JIT specializes the merge per value type and each comparison lowers to one instruction, so the issue's fallback was not needed. Floats compile but are documented as out of the intended use (NaN is not ordered under <).
  • Duplicates are collapsed, not declared undefined: every result is strictly ascending, which is what makes the HashSet<T> differential oracle meaningful, and costs one predictable comparison per emitted element.
  • Union has no galloping path and Except gallops only when the subtrahend is the long side — in both excluded cases the result is proportional to the long input, so skipping comparisons cannot beat the cost of writing the answer out.
  • Destination too short throws ArgumentException (the alternative the issue offered was a negative sentinel). The shortfall is found while writing, so the destination's contents are then documented as undefined; the always-sufficient sizes (min(a,b) / a / a+b) are documented per method.
  • Sortedness is asserted in Debug builds only. AssertSorted is [Conditional("DEBUG")], so Release elides the call and its O(n) argument evaluation — a Release check would cost exactly what the algorithm saves. It carries [ExcludeFromCodeCoverage] because its failing path calls Debug.Assert, which no test can drive without tearing down the test host.

Parity rollout (all in this PR)

Facet What landed
Type src/Celerity.Primitives/SortedSpan.cs
Dedicated tests SortedSpanTests.cs — merge and galloping paths, both gallop directions, duplicate collapsing, empty/disjoint/identical/single-element, exact-fit and undersized destinations, non-int element types, and a HashSet cross-check across five length ratios
Property / differential SortedSpanDifferentialTests.cs (CsCheck: generated domain, independent side lengths so the ratio swings across the 32x threshold, both argument orders) and a SortedSpan target in Celerity.Fuzz's Differential.All
Benchmark SortedSpanBenchmark.cs, registered in CoreBenchmarks in Program.cs; HashSet<int> baselines marked Baseline = true per category, LINQ arms alongside, [MemoryDiagnoser], ItemCount sweep at 1,000 / 100,000, plus an asymmetric galloping row
Dashboard COLLECTIONS entry in web/dev/bench/index.html and web/dev/bench/detail.html (+ Linq added to BCL_TYPES), and a ship card on web/index.html
Docs docs/api/utilities.md section with the measured table and the runnable example; README primitives paragraph, package-table row, and a "choosing a collection" row with the sortedness caveat stated in the row itself; Celerity.Primitives/README.md and the package Description
AOT Exercise block in Celerity.AotSmokeTest/Program.cs covering the merge, the galloping path and the throw
CHANGELOG / ROADMAP Four [Unreleased] / Added bullets; the 2.4.0 roadmap item flipped from planned to done with the measurements and the three design calls recorded

Two checklist items from the issue do not apply and were not done: the shared cross-collection test suites (AddAndTryAddTests, SetConstructorValidationTests, …) all parameterize over collection types, and SortedSpan is a static helper with no instance surface; and the coverage-gate dependency it named is already closed by #314, so Celerity.Primitives is inside the gate and this code is measured.

Test plan

  • dotnet build clean, no new warnings.
  • dotnet test5289 passed, 0 failed on each of net8.0, net9.0 and net10.0 (the CI matrix's three TFMs; net8.0/net9.0 run locally via DOTNET_ROLL_FORWARD=Major).
  • Coverage on the new type measured in isolation: 100% line, 100% branch (coverage.runsettings, cobertura).
  • Celerity.Fuzz --target SortedSpan --iterations 3000 — all cases pass against the HashSet oracle.
  • AOT smoke test runs green (managed run; CI does the Native AOT publish).
  • node scripts/check_dashboard_coverage.js and node scripts/check_doc_anchors.js (+ --self-test) pass.
  • SortedSpanBenchmark dry-run executed: all 30 result names parse with the dashboard's own regex, and all 12 (op, ItemCount) cards resolve to both a BCL and a Celerity series — so the card will not render blank.
  • CI: all 19 checks green — build + test matrix on all three OSes, coverage gate, all eight benchmark shards, release gates, package validation, AOT publish on net8/9/10, dashboard-coverage and doc-anchors.
  • On merge to main, the benchmark workflow republishes data.js to gh-pages and the new SortedSpan card starts charting.

🤖 Generated with Claude Code

…d spans

Intersect / Union / Except write straight into a caller-owned Span<T>;
IntersectCount and Overlaps answer with no buffer at all. The BCL has no set
operation over spans anywhere, so the alternatives (HashSet<T>.IntersectWith,
LINQ Intersect) allocate a table and hash every element rather than using the
order the data already has.

A two-cursor linear merge touches each element once. On two 1M-element sorted
int spans over a 2M universe: intersect 6.1 ms vs 25.7 ms for HashSet<int>
(4.2x; 5.7x vs LINQ), union 4.0x, except 2.8x, and 0 bytes allocated against
17.9 MB. When one side is at least 32x the other the merge switches to
exponential (galloping) search of the long side, which is where the win gets
large: 1k against 10M intersects in 0.37 ms vs 94.3 ms — 257x, and 422x for
IntersectCount. That clears the issue's kill criterion with room to spare.

Union deliberately has no galloping path (its result is at least as long as
the longer input, so writing the answer out dominates) and Except gallops only
when the subtrahend is the long side, for the same reason. The Vector256 path
was not shipped, per the issue's own condition: the scalar merge is already
memory-bound at 1M x 1M and merge is branch-heavy enough that vectorizing it
is frequently a wash.

Inputs must be sorted ascending — unsorted input silently returns a wrong
answer. The precondition leads every doc surface and is asserted in Debug
builds only; a Release check would cost exactly what the algorithm saves.
Duplicates within an input are collapsed, so every result is strictly
ascending and matches what HashSet<T> computes for the same values.

Full rollout in one change: dedicated + CsCheck differential tests (100% line
and branch on the new type), a Celerity.Fuzz target, Native AOT smoke
coverage, SortedSpanBenchmark registered in the CI suite with the matching
dashboard card on both bench pages, a landing-page ship card, utilities API
reference and README sections including a "choosing a collection" row, and the
ROADMAP status flipped to done.

Closes #313.

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

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

Coverage

Metric Value
Line 100% (11650/11650)
Branch 100% (4852/4852)

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 SortedSpan to Celerity.Primitives: allocation-free, merge-based set algebra over already ascending-sorted spans (with galloping for highly asymmetric sizes), plus tests, benchmarks, fuzz/AOT coverage, and documentation/dashboard wiring.

Changes:

  • Introduces SortedSpan APIs (Intersect/Union/Except/IntersectCount/Overlaps) with duplicate-collapsing set semantics and Debug-only sortedness assertions.
  • Adds comprehensive unit + differential tests, fuzz target, benchmarks, and AOT smoke coverage for the new surface.
  • Updates docs/README/changelog/roadmap and benchmark dashboard pages to surface the new utility.

Reviewed changes

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

Show a summary per file
File Description
web/index.html Adds “SortedSpan” ship card to the public landing page.
web/dev/bench/index.html Registers a SortedSpan benchmark card + adds Linq as a baseline type.
web/dev/bench/detail.html Adds SortedSpan to the per-card detail page + adds Linq as a baseline type.
src/Celerity.Tests/Utils/SortedSpanTests.cs Adds dedicated correctness tests for merge/gallop paths and edge cases.
src/Celerity.Tests/Utils/SortedSpanDifferentialTests.cs Adds CsCheck property-based differential tests vs HashSet<int> oracle.
src/Celerity.Tests/Packaging/PackageSplitTests.cs Verifies SortedSpan is in the Celerity.Primitives assembly.
src/Celerity.Primitives/SortedSpan.cs Implements the new sorted-span set algebra APIs and helpers.
src/Celerity.Primitives/README.md Documents SortedSpan in the primitives package readme.
src/Celerity.Primitives/Celerity.Primitives.csproj Updates package description to mention sorted-span set algebra.
src/Celerity.Fuzz/Differential.cs Adds SortedSpan differential fuzz target.
src/Celerity.Benchmarks/SortedSpanBenchmark.cs Adds BenchmarkDotNet coverage vs HashSet and LINQ baselines.
src/Celerity.Benchmarks/Program.cs Registers SortedSpanBenchmark in the benchmark suite.
src/Celerity.AotSmokeTest/Program.cs Exercises SortedSpan APIs under (Native) AOT smoke coverage.
ROADMAP.md Marks the roadmap item as done and records design decisions/measurements.
README.md Adds SortedSpan to package table + “choosing a collection” guidance + example.
docs/api/utilities.md Adds an API reference section and usage examples for SortedSpan.
CHANGELOG.md Adds Unreleased entries describing SortedSpan + its test/bench/docs wiring.

Comment thread src/Celerity.Primitives/SortedSpan.cs Outdated
Comment thread src/Celerity.Tests/Utils/SortedSpanTests.cs
Comment thread src/Celerity.Tests/Utils/SortedSpanDifferentialTests.cs
The ArgumentException carried a hardcoded "destination" string literal, which
would silently drift if the parameter were renamed. The helper now takes the
name and Append passes nameof(destination).

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

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

Suppressed comments (4)

src/Celerity.Primitives/SortedSpan.cs:241

  • In MergeIntersect, the y < x branch increments j by 1, which can repeatedly compare the same unmatched duplicate values. Since duplicates are treated as a single set element, you can skip over all equal y values when y < x (as other merge paths already do) to reduce work for duplicate-heavy inputs.
            else if (y < x)
            {
                if (++j == b.Length)
                    break;
            }

src/Celerity.Primitives/SortedSpan.cs:351

  • In MergeCount, the y < x branch increments j by 1. Since repeated y values are treated as a single set element, you can skip over duplicates when y < x (as in other merge routines) to reduce the number of comparisons for duplicate-heavy inputs.
            else if (y < x)
            {
                if (++j == b.Length)
                    break;
            }

src/Celerity.Primitives/SortedSpan.cs:236

  • In MergeIntersect, the x < y branch advances i by 1 even though duplicates are defined to be collapsed. When x < y, any subsequent duplicates of x are also < y, so re-checking them is unnecessary work in a hot loop (and inconsistent with MergeUnion/MergeExcept which use SkipEqual on mismatches). Skipping duplicates here reduces comparisons for duplicate-heavy inputs without changing semantics.

This issue also appears on line 237 of the same file.

            if (x < y)
            {
                if (++i == a.Length)
                    break;
            }

src/Celerity.Primitives/SortedSpan.cs:346

  • In MergeCount, the x < y branch advances i by 1 rather than skipping duplicates. Because inputs may contain repeated values but semantics treat them as one element, duplicates that are still < y can be skipped safely; this avoids redundant comparisons in the count/overlaps hot path.

This issue also appears on line 347 of the same file.

            if (x < y)
            {
                if (++i == a.Length)
                    break;
            }

… whole run

The mismatch branches of the intersect and count merges look like they should
skip the equal run the way union and except do. They should not: the run-skip
costs an equality test per element that can only pay off on duplicates, and
this branch is the entire loop on distinct inputs. Measured a wash on
duplicate-heavy data and 1.66x slower on interleaved-disjoint 1M x 1M spans.

Comment only — no behaviour change.

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

Copy link
Copy Markdown
Owner Author

Re: the four low-confidence findings on the merge mismatch branches

The second review round raised no inline comments but its body carries four suppressed findings, all making the same claim: MergeIntersect and MergeCount should call SkipEqual in their x < y / y < x branches — as MergeUnion and MergeExcept do — to "reduce the number of comparisons for duplicate-heavy inputs".

It is a performance claim, so I measured it rather than argued it. Both variants, interleaved round by round with the leading variant alternated and medians taken over 41 rounds, so warm-up and cache ordering cancel (a naive back-to-back run reverses its own verdict when you swap the order — which is how this nearly went the other way):

Shape (1M x 1M int) shipped with SkipEqual on mismatch ratio
distinct over a 2M universe 5.725 ms 5.614 ms 0.98x
duplicate-heavy, 10k domain (~100 copies/value) 0.598 ms 0.602 ms 1.01x
duplicate-extreme, 1k domain (~1000 copies/value) 0.417 ms 0.415 ms 1.00x
interleaved-disjoint (evens vs odds) 0.584 ms 0.969 ms 1.66x slower

So: a wash on the two shapes the suggestion targets, and a 66% regression on the one where the mismatch branch matters most.

The reason the premise does not hold is that the two conditions pull apart. On duplicate-heavy input both sides contain nearly every value, so almost every step takes the equality branch — which already skips runs — and the mismatch branch barely executes; there is nothing there to save. The shape that lives entirely in the mismatch branch is the distinct/disjoint one, and there SkipEqual's extra equality test per element can never succeed, so it is pure added cost.

The apparent inconsistency with MergeUnion / MergeExcept is also not one: those two emit in the mismatch branch, so they must skip the run or they would write the same value twice. MergeIntersect / MergeCount emit nothing there, so they carry no such obligation.

Not changing the code. I have added the measurement and the reasoning as a comment on the merge section in 8416ada, so the next reader — human or reviewer — does not have to rediscover it.

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

Suppressed comments (2)

src/Celerity.Primitives/SortedSpan.cs:579

  • If AssertSorted is tightened to catch unordered comparisons (e.g., NaN), the assertion message "is smaller" becomes inaccurate. Consider wording that covers both "smaller" and "unordered" cases.
            $"SortedSpan requires '{paramName}' to be sorted in ascending order; element {unsortedAt} is smaller than element {unsortedAt - 1}.");

src/Celerity.Primitives/SortedSpan.cs:570

  • AssertSorted only checks span[i] < span[i - 1], which does not detect unordered comparisons (e.g., float.NaN makes both < and > false). That means Debug builds can fail to assert the documented sortedness precondition for spans containing NaN/unordered values.

This issue also appears on line 579 of the same file.

            if (span[i] < span[i - 1])

The check tested span[i] < span[i - 1], which is false for a NaN pair in both
directions — so a span containing NaN sailed past an assertion whose whole job
is to catch exactly that, and which the XML docs already name as the way a
floating-point span violates the precondition. Testing !(span[i - 1] <= span[i])
catches a descending pair and an unordered one alike, and the message now says
"is not ordered after" rather than "is smaller".

Debug-only: the whole method is [Conditional("DEBUG")], so Release builds elide
the call and its scan as before.

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

Copy link
Copy Markdown
Owner Author

Both suppressed findings from the third round were right, and they are fixed in 882e20b.

AssertSorted tested span[i] < span[i - 1], which is false in both directions for a NaN pair — so a span containing NaN sailed straight past the assertion whose entire job is to catch precondition violations, and past the one violation the XML docs specifically name as how a floating-point span breaks the contract. It now tests !(span[i - 1] <= span[i]), which catches a descending pair and an unordered one alike, and the message reads "is not ordered after" rather than "is smaller" so it stays accurate for both.

Still Debug-only — the method is [Conditional("DEBUG")], so Release elides the call and its O(n) scan exactly as before, and there is no test driving the failing path because a tripped Debug.Assert tears down the test host (which is also why the method carries [ExcludeFromCodeCoverage]).

Re-verified locally after the change: 5289 tests pass and SortedSpan still measures 100% line and 100% branch coverage.

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

Suppressed comments (2)

CHANGELOG.md:12

  • The new SortedSpan CHANGELOG entries are very long (multiple sentences with detailed benchmark numbers) and repeat supporting-artifact details across several bullets. This diverges from the repo’s changelog guidance (CLAUDE.md:43-49) to keep entries short and user-facing, and it increases the risk that the extracted release notes exceed GitHub’s release-body limit.
- **`SortedSpan`** in `Celerity.Primitives` — set algebra over spans that are **already sorted ascending**: `Intersect` / `Union` / `Except` write straight into a caller-owned `Span<T>`, and `IntersectCount` / `Overlaps` answer without a buffer at all. The BCL has no set operation over spans, so the alternatives (`HashSet<T>.IntersectWith`, LINQ `Intersect`) allocate a table and hash every element instead of using the order the data already has: a two-cursor merge runs **4.2x faster on two 1M-element `int` spans (6.1 ms vs 25.7 ms) allocating 0 bytes against 17.9 MB**, and when one side is 32x the other it gallops — **1k against 10M takes 0.37 ms vs 94.3 ms, 257x**. Inputs **must** be sorted ascending; unsorted input silently returns a wrong answer, asserted in Debug builds and deliberately unchecked in Release. Closes [#313](https://github.com/marius-bughiu/Celerity/issues/313).
- `SortedSpanTests` and `SortedSpanDifferentialTests` — dedicated coverage of the merge, the galloping path, the duplicate-collapsing set semantics and the destination-too-short contract, plus a CsCheck property test and a `Celerity.Fuzz` target reconciling every operation against a `HashSet<T>` oracle across length ratios, and Native AOT smoke coverage. Closes [#313](https://github.com/marius-bughiu/Celerity/issues/313).
- `SortedSpanBenchmark` in the CI-tracked suite and the matching **SortedSpan** dashboard card, with `HashSet<int>` set algebra as the baseline, LINQ arms alongside it, and an asymmetric row for the galloping shape. Closes [#313](https://github.com/marius-bughiu/Celerity/issues/313).
- Utilities-reference and README sections for `SortedSpan`, including a "choosing a collection" row and the sortedness caveat stated in the row itself. Closes [#313](https://github.com/marius-bughiu/Celerity/issues/313).

src/Celerity.Primitives/SortedSpan.cs:583

  • AssertSorted always constructs the interpolated failure message because it’s passed directly to Debug.Assert(...) as an argument, even when the assertion holds. That’s an avoidable string allocation on every call in Debug builds (and the unused message includes element -1 when ordered). Consider only constructing the message on the failing path.
        Debug.Assert(
            unorderedAt == 0,
            $"SortedSpan requires '{paramName}' to be sorted in ascending order; element {unorderedAt} is not ordered after element {unorderedAt - 1} (it is smaller, or the two are unordered — e.g. NaN).");

The four bullets carried the full pitch, the mechanism and every supporting
detail. CLAUDE.md asks for short, user-facing entries, and the release workflow
extracts the whole version section verbatim as the GitHub Release body, which
this repo has overrun before. Same facts, ~300 characters shorter.

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

Copy link
Copy Markdown
Owner Author

Round four: one taken, one measured and declined

CHANGELOG length — fair, fixed in a8c3b43. The four bullets carried the full pitch plus every supporting detail, and release.yml extracts the whole version section verbatim as the release body — a section this repo has overrun before. Same facts, ~300 characters shorter, still one bullet per rollout facet so the change stays reconstructible from the changelog alone.

Debug.Assert allocating its message on the passing path — not correct, no change. The claim is that the interpolated message is built even when the assertion holds. It is not: since .NET 6 Debug.Assert has an interpolated-string-handler overload, and the compiler binds to it, so the holes are never evaluated unless the condition is false.

Verified rather than asserted — a net8.0 Debug build, matching the floor TFM:

interpolation hole evaluated 0 time(s) on a PASSING assert
allocated over 100k passing asserts: 0 bytes
overload: Boolean, String
overload: Boolean, AssertInterpolatedStringHandler&

The probe method inside the interpolation hole is called zero times and 100,000 passing asserts allocate zero bytes, because overload resolution picks Assert(bool, ref AssertInterpolatedStringHandler) over Assert(bool, string). The element -1 detail in the same comment is moot for the same reason — that string is never constructed. And in Release none of it exists at all: AssertSorted is [Conditional("DEBUG")], so the call and its O(n) scan are elided at the call site.

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

Suppressed comments (3)

src/Celerity.Primitives/SortedSpan.cs:114

  • destination overlap/aliasing isn’t documented, but the merge reads from a/b after writing to destination, so overlapping spans can corrupt subsequent reads and produce wrong results. Please document that destination must not overlap the source spans (or, if overlap is intended, the algorithm would need to be made overlap-safe).
    /// <param name="destination">
    /// Receives the result. <c>a.Length + b.Length</c> elements is always enough.
    /// </param>

src/Celerity.Primitives/SortedSpan.cs:144

  • Like Intersect/Union, Except will misbehave if destination overlaps a or b (writes can overwrite elements that haven’t been read yet). The API docs currently don’t call this out, so callers may reasonably assume in-place use is supported. Please document the non-overlap requirement in the destination parameter docs.
    /// <param name="a">The span to subtract from. Must be sorted ascending.</param>
    /// <param name="b">The span of values to remove. Must be sorted ascending.</param>
    /// <param name="destination">Receives the result. <c>a.Length</c> elements is always enough.</param>
    /// <returns>The number of values written — the result is <c>destination[..returned]</c>.</returns>

src/Celerity.Primitives/SortedSpan.cs:81

  • The implementation writes into destination while still reading from a/b, so if destination overlaps either input span the result can become incorrect (reads can observe overwritten values). The public API currently doesn’t document whether aliasing/overlap is allowed; this should be stated explicitly in the XML docs to prevent accidental in-place use.

This issue also appears in the following locations of the same file:

  • line 112
  • line 141
    /// <param name="destination">
    /// Receives the result. <c>min(a.Length, b.Length)</c> elements is always enough.
    /// </param>

… an input

The merge writes its result while it is still reading both sources, so a
destination overlapping either input can overwrite elements that have not been
consumed yet — silently, in the same way unsorted input does. The contract said
nothing about it, so a caller could reasonably have assumed in-place use worked.

The non-overlap requirement is now documented on the type, on every destination
parameter and in the utilities reference, and enforced the same way the ordering
precondition is: a Debug-only assert over MemoryExtensions.Overlaps, elided from
Release along with the rest of the precondition checking.

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

Copy link
Copy Markdown
Owner Author

Round five was right on all three counts — same finding stated three times — and it is fixed in aa6477a.

destination aliasing an input was genuinely undocumented, and the failure mode is the nasty kind: the merge writes its result while it is still reading both sources, so an overlapping buffer can overwrite elements that have not been consumed yet and return a wrong answer with no error — exactly the silent-wrongness the sortedness precondition is written up so carefully to prevent. A caller could reasonably have read the destination-sizing note and assumed in-place use was supported.

The requirement is now stated in three places (the type remarks alongside the ordering precondition, every destination parameter, and the "Contract and special cases" list in docs/api/utilities.md) and, more usefully, enforced the same way ordering is: a Debug-only AssertNoOverlap over the BCL MemoryExtensions.Overlaps, inside a [Conditional("DEBUG")] helper so Release elides the call and the check entirely.

Verified after the change: 5289 tests pass, the fuzz target passes 3,000 cases, and SortedSpan still measures 100% line and 100% branch — no existing test, fuzz case, benchmark or AOT smoke path was relying on an aliasing destination.

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

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

Benchmarks

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

Highlights

Benchmark This PR StdDev main Δ
TrieBenchmark.Dictionary_Add(ItemCount: 1000) 42.21 μs 7.65 μs 33.06 μs +27.7% ⚠️
CountMinSketchBenchmark.CountMinSketch_Add(ItemCount: 1000) 13.36 μs 168.6 ns 10.81 μs +23.6% ⚠️
TrieBenchmark.Trie_Add(ItemCount: 100000) 30.99 ms 658.43 μs 26.43 ms +17.2% ⚠️
CountMinSketchBenchmark.CountMinSketch_Add(ItemCount: 100000) 1.14 ms 10.07 μs 960.78 μs +18.5% ⚠️
CountMinSketchBenchmark.CountMinSketch_Estimate(ItemCount: 1000) 8.49 μs 18.8 ns 10.07 μs -15.7% ✅
CountMinSketchBenchmark.CountMinSketch_Estimate(ItemCount: 100000) 2.34 ms 2.45 μs 1.97 ms +19.2% ⚠️
TrieBenchmark.Trie_Lookup(ItemCount: 1000) 45.33 μs 30.8 ns 40.83 μs +11.0% ⚠️
CelerityMultiMapBenchmark.CelerityMultiMap_Lookup(ItemCount: 100000) 795.88 μs 18.81 μs 959.63 μs -17.1% ✅
TrieBenchmark.Trie_Lookup(ItemCount: 100000) 11.06 ms 101.02 μs 8.58 ms +28.9% ⚠️
TrieBenchmark.Trie_PrefixMatch(ItemCount: 100000) 10.49 ms 683.06 μs 8.82 ms +19.0% ⚠️
SmallSetBenchmark.SmallSet_Remove(ItemCount: 64) 26.42 μs 4.24 μs 20.34 μs +29.9% ⚠️
TrieBenchmark.Dictionary_SpanLookup(ItemCount: 100000) 6.86 ms 91.08 μs 6.06 ms +13.2% ⚠️
TrieBenchmark.Trie_SpanLookup(ItemCount: 100000) 10.99 ms 41.07 μs 8.56 ms +28.4% ⚠️
DequeBenchmark.LinkedList_Enumerate(ItemCount: 1000) 1.66 μs 0.6 ns 1.37 μs +21.2% ⚠️
DequeBenchmark.Deque_Enumerate(ItemCount: 1000) 1.06 μs 1.1 ns 941.7 ns +12.9% ⚠️
DequeBenchmark.LinkedList_Enumerate(ItemCount: 100000) 152.32 μs 47.1 ns 135.25 μs +12.6% ⚠️
DequeBenchmark.Deque_Enumerate(ItemCount: 100000) 105.63 μs 44.1 ns 93.80 μs +12.6% ⚠️
IntDictionaryBenchmark.IntDictionary_Insert(ItemCount: 1000) 9.26 μs 432.3 ns 11.24 μs -17.6% ✅
DequeBenchmark.LinkedList_Queue(ItemCount: 100000) 4.84 ms 54.23 μs 4.31 ms +12.5% ⚠️
IntDictionaryBenchmark.IntDictionary_Remove(ItemCount: 100000) 1.80 ms 167.44 μs 1.55 ms +16.4% ⚠️
PooledCeleritySetBenchmark.PooledCeleritySet_Remove(ItemCount: 100000) 1.44 ms 14.19 μs 1.30 ms +11.0% ⚠️
IntSetBenchmark.IntSet_Add(ItemCount: 100000) 3.49 ms 16.31 μs 3.17 ms +10.1% ⚠️
BitSetBenchmark.BitArray_And(ItemCount: 1024) 96.8 ns 0.5 ns 56.7 ns +70.6% ⚠️
BitSetBenchmark.BitSet_And(ItemCount: 1000000) 5.03 ms 9.93 μs 4.48 ms +12.5% ⚠️
DisjointSetBenchmark.Dictionary_Connected(ItemCount: 100000) 154.78 μs 422.4 ns 252.88 μs -38.8% ✅
DisjointSetBenchmark.DisjointSet_Connected(ItemCount: 100000) 284.93 μs 446.5 ns 337.40 μs -15.6% ✅
IntSetBenchmark.IntSet_Contains(ItemCount: 100000) 491.85 μs 6.35 μs 576.09 μs -14.6% ✅
IndexedPriorityQueueBenchmark.PriorityQueue_DecreaseKey(ItemCount: 100000) 34.96 ms 176.27 μs 39.43 ms -11.3% ✅
IndexedPriorityQueueBenchmark.PriorityQueue_Enqueue(ItemCount: 1000) 4.57 μs 12.6 ns 5.19 μs -12.0% ✅
LongDictionaryBenchmark.LongDictionary_Insert(ItemCount: 1000) 9.15 μs 81.3 ns 11.73 μs -21.9% ✅
LongDictionaryBenchmark.LongDictionary_Insert(ItemCount: 100000) 7.56 ms 44.27 μs 6.69 ms +13.1% ⚠️
BitSetBenchmark.BitArray_Or(ItemCount: 1024) 94.6 ns 1.8 ns 53.5 ns +76.7% ⚠️
BitSetBenchmark.BitSet_Or(ItemCount: 1000000) 5.03 ms 4.57 μs 4.47 ms +12.5% ⚠️
BitSetBenchmark.BitArray_PopCount(ItemCount: 1000000) 5.48 ms 1.71 μs 4.82 ms +13.5% ⚠️
BitSetBenchmark.BitSet_PopCount(ItemCount: 1000000) 5.55 μs 2.8 ns 4.93 μs +12.4% ⚠️
IntSetBenchmark.HashSet_Remove(ItemCount: 1000) 31.07 μs 2.79 μs 25.95 μs +19.7% ⚠️
BitSetBenchmark.BitArray_Xor(ItemCount: 1024) 95.5 ns 0.3 ns 65.6 ns +45.7% ⚠️
BitSetBenchmark.BitSet_Xor(ItemCount: 1000000) 5.04 ms 7.91 μs 4.47 ms +12.6% ⚠️
RankSelectBitVectorBenchmark.Array_Build(ItemCount: 1024) 91.9 ns 0.4 ns 83.2 ns +10.5% ⚠️
RankSelectBitVectorBenchmark.Array_Build(ItemCount: 1000000) 67.98 μs 454.8 ns 78.37 μs -13.3% ✅
RankSelectBitVectorBenchmark.RankSelectBitVector_Build(ItemCount: 1000000) 87.37 μs 666.6 ns 98.76 μs -11.5% ✅
RankSelectBitVectorBenchmark.Array_RankLate(ItemCount: 1024) 6.43 μs 13.9 ns 8.17 μs -21.2% ✅
RankSelectBitVectorBenchmark.Array_RankLate(ItemCount: 1000000) 4.88 ms 23.40 μs 5.51 ms -11.5% ✅
RankSelectBitVectorBenchmark.Array_RankMid(ItemCount: 1000000) 2.47 ms 1.54 μs 2.81 ms -12.0% ✅
SwissDictionaryBenchmark.SwissDictionary_Remove(ItemCount: 1000) 73.10 μs 2.78 μs 84.49 μs -13.5% ✅
HashCachingSetBenchmark.HashSet_Remove(ItemCount: 1000) 32.34 μs 2.73 μs 26.44 μs +22.3% ⚠️
RankSelectBitVectorBenchmark.Array_Select(ItemCount: 1000000) 4.23 ms 3.41 μs 4.78 ms -11.5% ✅
EnumSetBenchmark.HashSet_Add 671.6 ns 96.2 ns 548.9 ns +22.4% ⚠️
SmallDictionaryBenchmark.Dictionary_Insert(ItemCount: 8) 176.6 ns 1.5 ns 158.5 ns +11.4% ⚠️
SmallDictionaryBenchmark.SmallDictionary_Lookup(ItemCount: 8) 22.6 ns 1.0 ns 28.4 ns -20.5% ✅
CuckooFilterBenchmark.HashSet_Add(ItemCount: 1000) 14.10 μs 472.7 ns 12.62 μs +11.7% ⚠️
CeleritySetBenchmark.CeleritySet_Add(ItemCount: 100000) 3.16 ms 24.52 μs 3.54 ms -10.6% ✅
CuckooFilterBenchmark.CuckooFilter_Add(ItemCount: 100000) 2.10 ms 9.15 μs 2.35 ms -10.6% ✅
HyperLogLogBenchmark.HyperLogLog_Add(ItemCount: 100000) 570.06 μs 5.59 μs 475.87 μs +19.8% ⚠️
CeleritySetBenchmark.CeleritySet_Contains(ItemCount: 1000) 1.85 μs 9.4 ns 2.05 μs -9.6% ✅
CuckooFilterBenchmark.CuckooFilter_Contains(ItemCount: 1000) 4.92 μs 5.5 ns 5.55 μs -11.4% ✅
CeleritySetBenchmark.CeleritySet_Contains(ItemCount: 100000) 595.72 μs 3.20 μs 510.59 μs +16.7% ⚠️
CuckooFilterBenchmark.CuckooFilter_Contains(ItemCount: 100000) 1.75 ms 10.10 μs 1.98 ms -11.6% ✅
CuckooFilterBenchmark.CuckooFilter_ContainsMissing(ItemCount: 1000) 8.43 μs 6.9 ns 9.61 μs -12.3% ✅
CuckooFilterBenchmark.CuckooFilter_ContainsMissing(ItemCount: 100000) 876.62 μs 741.2 ns 985.29 μs -11.0% ✅
HyperLogLogBenchmark.HyperLogLog_Estimate(ItemCount: 1000) 23.46 μs 23.7 ns 26.40 μs -11.1% ✅
HyperLogLogBenchmark.HyperLogLog_Estimate(ItemCount: 100000) 22.98 μs 7.3 ns 27.84 μs -17.5% ✅
LruCacheBenchmark.Dictionary_Get(ItemCount: 1000) 30.90 μs 5.55 μs 24.38 μs +26.8% ⚠️
LruCacheBenchmark.LruCache_Get(ItemCount: 1000) 7.00 μs 195.7 ns 7.77 μs -9.9% ✅
LruCacheBenchmark.LruCache_Get(ItemCount: 100000) 6.93 μs 30.2 ns 7.67 μs -9.7% ✅
LruCacheBenchmark.LruCache_GetMissing(ItemCount: 100000) 1.34 ms 490.8 ns 1.51 ms -11.5% ✅
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Insert(ItemCount: 100000) 2.98 ms 6.85 μs 3.33 ms -10.6% ✅
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Lookup(ItemCount: 100000) 770.38 μs 1.68 μs 1.07 ms -28.0% ✅
LruCacheBenchmark.Dictionary_Put(ItemCount: 1000) 101.17 μs 2.27 μs 88.36 μs +14.5% ⚠️
LruCacheBenchmark.LruCache_Put(ItemCount: 1000) 478.73 μs 18.92 μs 402.38 μs +19.0% ⚠️
LruCacheBenchmark.LruCache_Put(ItemCount: 100000) 5.80 ms 49.15 μs 6.54 ms -11.3% ✅
BTreeSetBenchmark.SortedSet_Remove(ItemCount: 1000) 796.84 μs 40.04 μs 722.79 μs +10.2% ⚠️
CuckooFilterBenchmark.CuckooFilter_Remove(ItemCount: 100000) 3.99 ms 10.74 μs 4.51 ms -11.7% ✅
LongSetBenchmark.HashSet_Add(ItemCount: 100000) 4.47 ms 176.31 μs 5.17 ms -13.5% ✅
FrozenCelerityDictionaryBenchmark.FrozenCelerityDictionary_Build(ItemCount: 1000) 4.33 ms 613.92 μs 3.43 ms +26.4% ⚠️
StringKeyProbeBenchmark.HashSet_Contains(ItemCount: 1000) 18.16 μs 97.2 ns 16.46 μs +10.3% ⚠️
StringKeyProbeBenchmark.CeleritySet_Contains(ItemCount: 1000) 24.40 μs 118.3 ns 27.71 μs -11.9% ✅
StringKeyProbeBenchmark.CeleritySet_Contains(ItemCount: 100000) 4.87 ms 47.71 μs 5.44 ms -10.6% ✅
StringKeyProbeBenchmark.Dictionary_Lookup(ItemCount: 1000) 18.62 μs 253.8 ns 16.72 μs +11.3% ⚠️
StringKeyProbeBenchmark.CelerityDictionary_Lookup(ItemCount: 1000) 26.79 μs 479.1 ns 29.63 μs -9.6% ✅
StringKeyProbeBenchmark.CelerityDictionary_LookupMissing(ItemCount: 1000) 28.36 μs 59.3 ns 32.84 μs -13.7% ✅
StringKeyProbeBenchmark.CelerityDictionary_LookupMissing(ItemCount: 100000) 6.14 ms 524.59 μs 11.04 ms -44.3% ✅
RobinHoodDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.05 ms 20.61 μs 2.40 ms -14.8% ✅
LongSetBenchmark.LongSet_Remove(ItemCount: 100000) 1.43 ms 15.27 μs 1.59 ms -10.2% ✅
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Remove(ItemCount: 100000) 1.73 ms 25.92 μs 2.41 ms -27.9% ✅
FrozenCelerityDictionaryBenchmark.FrozenCelerityDictionary_SpanLookup(ItemCount: 100000) 8.65 ms 50.57 μs 9.78 ms -11.6% ✅
Collections (566)
Benchmark This PR StdDev main Δ
EnumMapBenchmark.Dictionary_Add 644.7 ns 1.5 ns 657.4 ns -1.9%
EnumMapBenchmark.EnumMap_Add 114.8 ns 0.5 ns 114.7 ns +0.1%
SmallSetBenchmark.HashSet_Add(ItemCount: 8) 184.0 ns 13.9 ns 188.3 ns -2.3%
SmallSetBenchmark.SmallSet_Add(ItemCount: 8) 60.8 ns 1.5 ns 60.4 ns +0.7%
SmallSetBenchmark.HashSet_Add(ItemCount: 64) 836.6 ns 15.5 ns 840.0 ns -0.4%
SmallSetBenchmark.SmallSet_Add(ItemCount: 64) 1.94 μs 328.2 ns 2.25 μs -13.7%
TrieBenchmark.Dictionary_Add(ItemCount: 1000) 42.21 μs 7.65 μs 33.06 μs +27.7% ⚠️
TrieBenchmark.Trie_Add(ItemCount: 1000) 513.38 μs 15.49 μs 469.09 μs +9.4%
CountMinSketchBenchmark.Dictionary_Add(ItemCount: 1000) 10.47 μs 40.8 ns 10.56 μs -0.9%
CountMinSketchBenchmark.CountMinSketch_Add(ItemCount: 1000) 13.36 μs 168.6 ns 10.81 μs +23.6% ⚠️
TrieBenchmark.Dictionary_Add(ItemCount: 100000) 6.39 ms 1.50 ms 4.87 ms +31.2%
TrieBenchmark.Trie_Add(ItemCount: 100000) 30.99 ms 658.43 μs 26.43 ms +17.2% ⚠️
CountMinSketchBenchmark.Dictionary_Add(ItemCount: 100000) 1.48 ms 5.62 μs 1.45 ms +2.1%
CountMinSketchBenchmark.CountMinSketch_Add(ItemCount: 100000) 1.14 ms 10.07 μs 960.78 μs +18.5% ⚠️
SmallSetBenchmark.HashSet_Contains(ItemCount: 8) 37.4 ns 0.1 ns 37.4 ns -0.0%
SmallSetBenchmark.SmallSet_Contains(ItemCount: 8) 19.7 ns 0.2 ns 19.8 ns -0.6%
SmallSetBenchmark.HashSet_Contains(ItemCount: 64) 301.9 ns 0.3 ns 323.2 ns -6.6%
SmallSetBenchmark.SmallSet_Contains(ItemCount: 64) 925.2 ns 11.1 ns 930.0 ns -0.5%
EnumMapBenchmark.Dictionary_Enumerate 43.1 ns 0.1 ns 43.1 ns +0.0%
EnumMapBenchmark.EnumMap_Enumerate 37.9 ns 0.2 ns 38.0 ns -0.2%
CountMinSketchBenchmark.Dictionary_Estimate(ItemCount: 1000) 4.66 μs 4.7 ns 4.38 μs +6.4%
CountMinSketchBenchmark.CountMinSketch_Estimate(ItemCount: 1000) 8.49 μs 18.8 ns 10.07 μs -15.7% ✅
CountMinSketchBenchmark.Dictionary_Estimate(ItemCount: 100000) 531.20 μs 854.9 ns 502.85 μs +5.6%
CountMinSketchBenchmark.CountMinSketch_Estimate(ItemCount: 100000) 2.34 ms 2.45 μs 1.97 ms +19.2% ⚠️
SortedSpanBenchmark.HashSet_Except(ItemCount: 1000) 13.00 μs 23.3 ns n/a 🆕 new
SortedSpanBenchmark.Linq_ExceptLinq(ItemCount: 1000) 22.10 μs 94.9 ns n/a 🆕 new
SortedSpanBenchmark.SortedSpan_Except(ItemCount: 1000) 2.49 μs 111.8 ns n/a 🆕 new
SortedSpanBenchmark.HashSet_Except(ItemCount: 100000) 2.71 ms 31.21 μs n/a 🆕 new
SortedSpanBenchmark.Linq_ExceptLinq(ItemCount: 100000) 3.84 ms 37.24 μs n/a 🆕 new
SortedSpanBenchmark.SortedSpan_Except(ItemCount: 100000) 994.21 μs 2.49 μs n/a 🆕 new
CelerityMultiMapBenchmark.Dictionary_Insert(ItemCount: 1000) 29.74 μs 128.6 ns 29.67 μs +0.2%
CelerityMultiMapBenchmark.CelerityMultiMap_Insert(ItemCount: 1000) 42.32 μs 197.0 ns 43.32 μs -2.3%
CelerityMultiMapBenchmark.Dictionary_Insert(ItemCount: 100000) 14.15 ms 839.64 μs 14.37 ms -1.6%
CelerityMultiMapBenchmark.CelerityMultiMap_Insert(ItemCount: 100000) 19.80 ms 168.18 μs 19.93 ms -0.7%
SortedSpanBenchmark.HashSet_Intersect(ItemCount: 1000) 21.27 μs 206.3 ns n/a 🆕 new
SortedSpanBenchmark.Linq_IntersectLinq(ItemCount: 1000) 15.51 μs 42.8 ns n/a 🆕 new
SortedSpanBenchmark.SortedSpan_Intersect(ItemCount: 1000) 2.73 μs 135.0 ns n/a 🆕 new
SortedSpanBenchmark.HashSet_Intersect(ItemCount: 100000) 4.23 ms 30.32 μs n/a 🆕 new
SortedSpanBenchmark.Linq_IntersectLinq(ItemCount: 100000) 3.02 ms 25.18 μs n/a 🆕 new
SortedSpanBenchmark.SortedSpan_Intersect(ItemCount: 100000) 968.56 μs 2.73 μs n/a 🆕 new
SortedSpanBenchmark.HashSet_IntersectAsymmetric(ItemCount: 1000) 8.48 μs 235.2 ns n/a 🆕 new
SortedSpanBenchmark.SortedSpan_IntersectAsymmetric(ItemCount: 1000) 108.8 ns 0.4 ns n/a 🆕 new
SortedSpanBenchmark.HashSet_IntersectAsymmetric(ItemCount: 100000) 1.75 ms 9.18 μs n/a 🆕 new
SortedSpanBenchmark.SortedSpan_IntersectAsymmetric(ItemCount: 100000) 14.05 μs 293.1 ns n/a 🆕 new
SortedSpanBenchmark.HashSet_IntersectCount(ItemCount: 1000) 12.83 μs 94.4 ns n/a 🆕 new
SortedSpanBenchmark.SortedSpan_IntersectCount(ItemCount: 1000) 2.63 μs 86.2 ns n/a 🆕 new
SortedSpanBenchmark.HashSet_IntersectCount(ItemCount: 100000) 2.73 ms 23.64 μs n/a 🆕 new
SortedSpanBenchmark.SortedSpan_IntersectCount(ItemCount: 100000) 948.74 μs 598.5 ns n/a 🆕 new
EnumMapBenchmark.Dictionary_Lookup 135.7 ns 0.1 ns 135.7 ns -0.0%
EnumMapBenchmark.EnumMap_Lookup 70.0 ns 0.3 ns 70.4 ns -0.5%
CelerityMultiMapBenchmark.Dictionary_Lookup(ItemCount: 1000) 5.10 μs 7.8 ns 5.12 μs -0.3%
TrieBenchmark.Dictionary_Lookup(ItemCount: 1000) 12.59 μs 44.6 ns 13.33 μs -5.5%
CelerityMultiMapBenchmark.CelerityMultiMap_Lookup(ItemCount: 1000) 2.55 μs 1.6 ns 2.55 μs -0.2%
TrieBenchmark.Trie_Lookup(ItemCount: 1000) 45.33 μs 30.8 ns 40.83 μs +11.0% ⚠️
CelerityMultiMapBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.79 ms 4.30 μs 1.85 ms -3.4%
TrieBenchmark.Dictionary_Lookup(ItemCount: 100000) 2.84 ms 35.46 μs 2.68 ms +6.1%
CelerityMultiMapBenchmark.CelerityMultiMap_Lookup(ItemCount: 100000) 795.88 μs 18.81 μs 959.63 μs -17.1% ✅
TrieBenchmark.Trie_Lookup(ItemCount: 100000) 11.06 ms 101.02 μs 8.58 ms +28.9% ⚠️
SortedSpanBenchmark.HashSet_Overlaps(ItemCount: 1000) 8.55 μs 64.8 ns n/a 🆕 new
SortedSpanBenchmark.SortedSpan_Overlaps(ItemCount: 1000) 8.4 ns 0.2 ns n/a 🆕 new
SortedSpanBenchmark.HashSet_Overlaps(ItemCount: 100000) 1.31 ms 39.50 μs n/a 🆕 new
SortedSpanBenchmark.SortedSpan_Overlaps(ItemCount: 100000) 4.2 ns 0.0 ns n/a 🆕 new
TrieBenchmark.Dictionary_PrefixMatch(ItemCount: 1000) 79.97 μs 40.3 ns 73.29 μs +9.1%
TrieBenchmark.Trie_PrefixMatch(ItemCount: 1000) 59.21 μs 528.1 ns 56.79 μs +4.3%
TrieBenchmark.Dictionary_PrefixMatch(ItemCount: 100000) 8.08 ms 7.26 μs 7.39 ms +9.4%
TrieBenchmark.Trie_PrefixMatch(ItemCount: 100000) 10.49 ms 683.06 μs 8.82 ms +19.0% ⚠️
EnumMapBenchmark.Dictionary_Remove 3.02 μs 560.9 ns 2.93 μs +3.1%
EnumMapBenchmark.EnumMap_Remove 1.39 μs 398.2 ns 1.51 μs -8.2%
SmallSetBenchmark.HashSet_Remove(ItemCount: 8) 475.2 ns 54.5 ns 528.1 ns -10.0%
SmallSetBenchmark.SmallSet_Remove(ItemCount: 8) 1.21 μs 233.1 ns 1.10 μs +10.2%
SmallSetBenchmark.HashSet_Remove(ItemCount: 64) 1.34 μs 174.7 ns 1.61 μs -17.2%
SmallSetBenchmark.SmallSet_Remove(ItemCount: 64) 26.42 μs 4.24 μs 20.34 μs +29.9% ⚠️
CelerityMultiMapBenchmark.Dictionary_Remove(ItemCount: 1000) 27.92 μs 3.70 μs 30.30 μs -7.8%
CelerityMultiMapBenchmark.CelerityMultiMap_Remove(ItemCount: 1000) 123.19 μs 4.67 μs 121.39 μs +1.5%
CelerityMultiMapBenchmark.Dictionary_Remove(ItemCount: 100000) 3.01 ms 221.33 μs 3.48 ms -13.7%
CelerityMultiMapBenchmark.CelerityMultiMap_Remove(ItemCount: 100000) 2.93 ms 108.24 μs 3.10 ms -5.6%
TrieBenchmark.Dictionary_SpanLookup(ItemCount: 1000) 39.75 μs 351.0 ns 41.61 μs -4.5%
TrieBenchmark.Trie_SpanLookup(ItemCount: 1000) 46.53 μs 162.8 ns 43.21 μs +7.7%
TrieBenchmark.Dictionary_SpanLookup(ItemCount: 100000) 6.86 ms 91.08 μs 6.06 ms +13.2% ⚠️
TrieBenchmark.Trie_SpanLookup(ItemCount: 100000) 10.99 ms 41.07 μs 8.56 ms +28.4% ⚠️
SortedSpanBenchmark.HashSet_Union(ItemCount: 1000) 19.95 μs 114.8 ns n/a 🆕 new
SortedSpanBenchmark.Linq_UnionLinq(ItemCount: 1000) 21.54 μs 101.3 ns n/a 🆕 new
SortedSpanBenchmark.SortedSpan_Union(ItemCount: 1000) 2.89 μs 2.8 ns n/a 🆕 new
SortedSpanBenchmark.HashSet_Union(ItemCount: 100000) 3.65 ms 44.73 μs n/a 🆕 new
SortedSpanBenchmark.Linq_UnionLinq(ItemCount: 100000) 5.01 ms 49.07 μs n/a 🆕 new
SortedSpanBenchmark.SortedSpan_Union(ItemCount: 100000) 1.02 ms 5.37 μs n/a 🆕 new
PooledCeleritySetBenchmark.HashSet_Add(ItemCount: 1000) 13.15 μs 150.9 ns 12.30 μs +6.9%
TopKSketchBenchmark.Dictionary_Add(ItemCount: 1000) 13.44 μs 42.6 ns 13.54 μs -0.7%
PooledCeleritySetBenchmark.PooledCeleritySet_Add(ItemCount: 1000) 8.84 μs 60.3 ns 8.49 μs +4.1%
TopKSketchBenchmark.TopKSketch_Add(ItemCount: 1000) 80.05 μs 40.4 ns 87.74 μs -8.8%
PooledCeleritySetBenchmark.HashSet_Add(ItemCount: 100000) 5.10 ms 60.04 μs 4.84 ms +5.3%
TopKSketchBenchmark.Dictionary_Add(ItemCount: 100000) 3.24 ms 50.87 μs 3.24 ms +0.2%
PooledCeleritySetBenchmark.PooledCeleritySet_Add(ItemCount: 100000) 3.15 ms 20.11 μs 2.87 ms +9.8%
TopKSketchBenchmark.TopKSketch_Add(ItemCount: 100000) 15.07 ms 68.12 μs 14.68 ms +2.7%
PooledCeleritySetBenchmark.HashSet_Contains(ItemCount: 1000) 4.71 μs 6.5 ns 4.74 μs -0.5%
PooledCeleritySetBenchmark.PooledCeleritySet_Contains(ItemCount: 1000) 2.05 μs 52.5 ns 1.94 μs +5.9%
PooledCeleritySetBenchmark.HashSet_Contains(ItemCount: 100000) 1.55 ms 33.24 μs 1.60 ms -3.1%
PooledCeleritySetBenchmark.PooledCeleritySet_Contains(ItemCount: 100000) 526.37 μs 20.86 μs 577.03 μs -8.8%
DequeBenchmark.LinkedList_Enumerate(ItemCount: 1000) 1.66 μs 0.6 ns 1.37 μs +21.2% ⚠️
DequeBenchmark.Deque_Enumerate(ItemCount: 1000) 1.06 μs 1.1 ns 941.7 ns +12.9% ⚠️
DequeBenchmark.LinkedList_Enumerate(ItemCount: 100000) 152.32 μs 47.1 ns 135.25 μs +12.6% ⚠️
DequeBenchmark.Deque_Enumerate(ItemCount: 100000) 105.63 μs 44.1 ns 93.80 μs +12.6% ⚠️
CelerityDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 13.90 μs 275.2 ns 13.22 μs +5.1%
IntDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 14.30 μs 229.1 ns 15.36 μs -6.9%
CelerityDictionaryBenchmark.CelerityDictionary_Insert(ItemCount: 1000) 9.54 μs 291.6 ns 8.98 μs +6.3%
IntDictionaryBenchmark.IntDictionary_Insert(ItemCount: 1000) 9.26 μs 432.3 ns 11.24 μs -17.6% ✅
CelerityDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 4.45 ms 67.61 μs 4.33 ms +2.7%
IntDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 4.40 ms 85.32 μs 4.12 ms +6.9%
CelerityDictionaryBenchmark.CelerityDictionary_Insert(ItemCount: 100000) 5.32 ms 92.66 μs 5.30 ms +0.4%
IntDictionaryBenchmark.IntDictionary_Insert(ItemCount: 100000) 5.14 ms 50.03 μs 4.85 ms +5.9%
CelerityDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.97 μs 366.6 ns 4.83 μs +2.8%
IntDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.62 μs 18.4 ns 4.73 μs -2.2%
CelerityDictionaryBenchmark.CelerityDictionary_Lookup(ItemCount: 1000) 2.39 μs 18.3 ns 2.40 μs -0.3%
IntDictionaryBenchmark.IntDictionary_Lookup(ItemCount: 1000) 2.08 μs 5.9 ns 2.14 μs -2.8%
CelerityDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.55 ms 57.61 μs 1.55 ms -0.3%
IntDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.56 ms 2.32 μs 1.59 ms -2.0%
CelerityDictionaryBenchmark.CelerityDictionary_Lookup(ItemCount: 100000) 698.23 μs 13.44 μs 1.03 ms -32.2%
IntDictionaryBenchmark.IntDictionary_Lookup(ItemCount: 100000) 619.06 μs 51.58 μs 677.28 μs -8.6%
DequeBenchmark.LinkedList_PushFront(ItemCount: 1000) 37.56 μs 4.24 μs 35.30 μs +6.4%
DequeBenchmark.Deque_PushFront(ItemCount: 1000) 19.39 μs 1.78 μs 23.62 μs -17.9%
DequeBenchmark.LinkedList_PushFront(ItemCount: 100000) 1.85 ms 26.88 μs 1.84 ms +0.8%
DequeBenchmark.Deque_PushFront(ItemCount: 100000) 639.27 μs 16.72 μs 653.05 μs -2.1%
DequeBenchmark.LinkedList_Queue(ItemCount: 1000) 54.92 μs 3.85 μs 54.25 μs +1.2%
DequeBenchmark.Deque_Queue(ItemCount: 1000) 30.44 μs 4.66 μs 38.05 μs -20.0%
DequeBenchmark.LinkedList_Queue(ItemCount: 100000) 4.84 ms 54.23 μs 4.31 ms +12.5% ⚠️
DequeBenchmark.Deque_Queue(ItemCount: 100000) 457.14 μs 20.60 μs 418.55 μs +9.2%
CelerityDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 80.31 μs 8.41 μs 76.93 μs +4.4%
IntDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 84.12 μs 6.44 μs 81.76 μs +2.9%
PooledCeleritySetBenchmark.HashSet_Remove(ItemCount: 1000) 27.85 μs 2.46 μs 29.02 μs -4.0%
CelerityDictionaryBenchmark.CelerityDictionary_Remove(ItemCount: 1000) 125.72 μs 7.14 μs 126.29 μs -0.4%
IntDictionaryBenchmark.IntDictionary_Remove(ItemCount: 1000) 91.99 μs 6.71 μs 90.77 μs +1.3%
PooledCeleritySetBenchmark.PooledCeleritySet_Remove(ItemCount: 1000) 115.36 μs 6.80 μs 116.53 μs -1.0%
CelerityDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.03 ms 24.60 μs 2.00 ms +1.3%
IntDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.01 ms 18.29 μs 2.04 ms -1.6%
PooledCeleritySetBenchmark.HashSet_Remove(ItemCount: 100000) 1.68 ms 21.26 μs 1.71 ms -1.9%
CelerityDictionaryBenchmark.CelerityDictionary_Remove(ItemCount: 100000) 1.76 ms 54.30 μs 1.76 ms -0.1%
IntDictionaryBenchmark.IntDictionary_Remove(ItemCount: 100000) 1.80 ms 167.44 μs 1.55 ms +16.4% ⚠️
PooledCeleritySetBenchmark.PooledCeleritySet_Remove(ItemCount: 100000) 1.44 ms 14.19 μs 1.30 ms +11.0% ⚠️
TopKSketchBenchmark.Dictionary_TopK(ItemCount: 1000) 32.4 ns 0.4 ns 30.1 ns +7.5%
TopKSketchBenchmark.TopKSketch_TopK(ItemCount: 1000) 1.20 μs 2.5 ns 1.26 μs -4.9%
TopKSketchBenchmark.Dictionary_TopK(ItemCount: 100000) 32.4 ns 0.5 ns 30.0 ns +7.9%
TopKSketchBenchmark.TopKSketch_TopK(ItemCount: 100000) 1.13 μs 4.6 ns 1.20 μs -5.7%
CompressedIntSetBenchmark.HashSet_Add(ItemCount: 1000) 12.45 μs 34.7 ns 12.54 μs -0.7%
IntSetBenchmark.HashSet_Add(ItemCount: 1000) 12.59 μs 176.2 ns 12.68 μs -0.7%
CompressedIntSetBenchmark.CompressedIntSet_Add(ItemCount: 1000) 35.63 μs 544.4 ns 35.93 μs -0.8%
IntSetBenchmark.IntSet_Add(ItemCount: 1000) 9.16 μs 51.4 ns 8.76 μs +4.6%
CompressedIntSetBenchmark.HashSet_Add(ItemCount: 100000) 3.61 ms 59.28 μs 3.63 ms -0.6%
IntSetBenchmark.HashSet_Add(ItemCount: 100000) 5.15 ms 112.23 μs 5.05 ms +2.0%
CompressedIntSetBenchmark.CompressedIntSet_Add(ItemCount: 100000) 11.92 ms 46.61 μs 11.86 ms +0.5%
IntSetBenchmark.IntSet_Add(ItemCount: 100000) 3.49 ms 16.31 μs 3.17 ms +10.1% ⚠️
BitSetBenchmark.BitArray_And(ItemCount: 1024) 96.8 ns 0.5 ns 56.7 ns +70.6% ⚠️
BitSetBenchmark.BitSet_And(ItemCount: 1024) 1.23 μs 2.6 ns 1.20 μs +2.2%
BitSetBenchmark.BitArray_And(ItemCount: 1000000) 45.77 μs 388.9 ns 44.07 μs +3.8%
BitSetBenchmark.BitSet_And(ItemCount: 1000000) 5.03 ms 9.93 μs 4.48 ms +12.5% ⚠️
DisjointSetBenchmark.Dictionary_Components(ItemCount: 1000) 17.16 μs 226.8 ns 18.60 μs -7.7%
DisjointSetBenchmark.DisjointSet_Components(ItemCount: 1000) 15.71 μs 188.1 ns 17.25 μs -8.9%
DisjointSetBenchmark.Dictionary_Components(ItemCount: 100000) 4.44 ms 40.97 μs 4.34 ms +2.2%
DisjointSetBenchmark.DisjointSet_Components(ItemCount: 100000) 3.38 ms 162.02 μs 3.14 ms +7.6%
DisjointSetBenchmark.Dictionary_Connected(ItemCount: 1000) 9.52 μs 8.7 ns 9.68 μs -1.7%
DisjointSetBenchmark.DisjointSet_Connected(ItemCount: 1000) 13.11 μs 58.7 ns 12.55 μs +4.4%
DisjointSetBenchmark.Dictionary_Connected(ItemCount: 100000) 154.78 μs 422.4 ns 252.88 μs -38.8% ✅
DisjointSetBenchmark.DisjointSet_Connected(ItemCount: 100000) 284.93 μs 446.5 ns 337.40 μs -15.6% ✅
CompressedIntSetBenchmark.HashSet_Contains(ItemCount: 1000) 4.73 μs 6.1 ns 4.73 μs -0.1%
IntSetBenchmark.HashSet_Contains(ItemCount: 1000) 4.71 μs 2.9 ns 4.74 μs -0.7%
CompressedIntSetBenchmark.CompressedIntSet_Contains(ItemCount: 1000) 13.17 μs 52.9 ns 13.16 μs +0.0%
IntSetBenchmark.IntSet_Contains(ItemCount: 1000) 1.93 μs 17.4 ns 1.81 μs +6.9%
CompressedIntSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.49 ms 12.74 μs 1.49 ms +0.3%
IntSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.51 ms 7.78 μs 1.57 ms -3.7%
CompressedIntSetBenchmark.CompressedIntSet_Contains(ItemCount: 100000) 9.40 ms 44.90 μs 9.45 ms -0.5%
IntSetBenchmark.IntSet_Contains(ItemCount: 100000) 491.85 μs 6.35 μs 576.09 μs -14.6% ✅
IndexedPriorityQueueBenchmark.PriorityQueue_DecreaseKey(ItemCount: 1000) 76.94 μs 383.3 ns 84.15 μs -8.6%
IndexedPriorityQueueBenchmark.IndexedPriorityQueue_DecreaseKey(ItemCount: 1000) 187.54 μs 876.6 ns 189.24 μs -0.9%
IndexedPriorityQueueBenchmark.PriorityQueue_DecreaseKey(ItemCount: 100000) 34.96 ms 176.27 μs 39.43 ms -11.3% ✅
IndexedPriorityQueueBenchmark.IndexedPriorityQueue_DecreaseKey(ItemCount: 100000) 56.79 ms 503.08 μs 58.49 ms -2.9%
IndexedPriorityQueueBenchmark.PriorityQueue_Enqueue(ItemCount: 1000) 4.57 μs 12.6 ns 5.19 μs -12.0% ✅
IndexedPriorityQueueBenchmark.IndexedPriorityQueue_Enqueue(ItemCount: 1000) 29.56 μs 95.0 ns 30.17 μs -2.0%
IndexedPriorityQueueBenchmark.PriorityQueue_Enqueue(ItemCount: 100000) 1.17 ms 10.50 μs 1.19 ms -1.6%
IndexedPriorityQueueBenchmark.IndexedPriorityQueue_Enqueue(ItemCount: 100000) 6.43 ms 153.10 μs 6.72 ms -4.2%
CompressedIntSetBenchmark.HashSet_Except(ItemCount: 1000) 54.99 μs 2.32 μs 55.16 μs -0.3%
CompressedIntSetBenchmark.CompressedIntSet_Except(ItemCount: 1000) 62.10 μs 7.64 μs 64.43 μs -3.6%
CompressedIntSetBenchmark.HashSet_Except(ItemCount: 100000) 2.62 ms 25.67 μs 2.64 ms -0.9%
CompressedIntSetBenchmark.CompressedIntSet_Except(ItemCount: 100000) 1.18 ms 12.86 μs 1.17 ms +0.7%
LongDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 16.06 μs 200.3 ns 15.45 μs +3.9%
LongDictionaryBenchmark.LongDictionary_Insert(ItemCount: 1000) 9.15 μs 81.3 ns 11.73 μs -21.9% ✅
LongDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 5.24 ms 63.94 μs 5.02 ms +4.4%
LongDictionaryBenchmark.LongDictionary_Insert(ItemCount: 100000) 7.56 ms 44.27 μs 6.69 ms +13.1% ⚠️
CompressedIntSetBenchmark.HashSet_IntersectClustered(ItemCount: 1000) 34.72 μs 3.25 μs 35.43 μs -2.0%
CompressedIntSetBenchmark.CompressedIntSet_IntersectClustered(ItemCount: 1000) 1.16 μs 93.0 ns 1.33 μs -12.7%
CompressedIntSetBenchmark.HashSet_IntersectClustered(ItemCount: 100000) 1.02 ms 9.73 μs 1.03 ms -0.2%
CompressedIntSetBenchmark.CompressedIntSet_IntersectClustered(ItemCount: 100000) 1.85 μs 324.3 ns 1.75 μs +5.8%
CompressedIntSetBenchmark.HashSet_IntersectDense(ItemCount: 1000) 43.28 μs 3.05 μs 47.00 μs -7.9%
CompressedIntSetBenchmark.CompressedIntSet_IntersectDense(ItemCount: 1000) 49.03 μs 4.04 μs 47.51 μs +3.2%
CompressedIntSetBenchmark.HashSet_IntersectDense(ItemCount: 100000) 3.03 ms 102.01 μs 3.13 ms -3.5%
CompressedIntSetBenchmark.CompressedIntSet_IntersectDense(ItemCount: 100000) 90.94 μs 22.31 μs 86.77 μs +4.8%
CompressedIntSetBenchmark.HashSet_IntersectSparse(ItemCount: 1000) 55.16 μs 3.24 μs 55.63 μs -0.8%
CompressedIntSetBenchmark.CompressedIntSet_IntersectSparse(ItemCount: 1000) 55.63 μs 4.96 μs 51.87 μs +7.2%
CompressedIntSetBenchmark.HashSet_IntersectSparse(ItemCount: 100000) 4.26 ms 85.71 μs 4.21 ms +1.3%
CompressedIntSetBenchmark.CompressedIntSet_IntersectSparse(ItemCount: 100000) 1.08 ms 29.67 μs 1.05 ms +2.7%
LongDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 5.04 μs 37.6 ns 4.90 μs +2.8%
LongDictionaryBenchmark.LongDictionary_Lookup(ItemCount: 1000) 2.30 μs 4.6 ns 6.04 μs -62.0%
LongDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.57 ms 2.78 μs 1.59 ms -1.2%
LongDictionaryBenchmark.LongDictionary_Lookup(ItemCount: 100000) 680.68 μs 14.36 μs 700.60 μs -2.8%
BitSetBenchmark.BitArray_Or(ItemCount: 1024) 94.6 ns 1.8 ns 53.5 ns +76.7% ⚠️
BitSetBenchmark.BitSet_Or(ItemCount: 1024) 1.23 μs 2.8 ns 1.24 μs -1.3%
BitSetBenchmark.BitArray_Or(ItemCount: 1000000) 45.68 μs 331.1 ns 43.93 μs +4.0%
BitSetBenchmark.BitSet_Or(ItemCount: 1000000) 5.03 ms 4.57 μs 4.47 ms +12.5% ⚠️
BitSetBenchmark.BitArray_PopCount(ItemCount: 1024) 1.29 μs 68.3 ns 1.24 μs +3.9%
BitSetBenchmark.BitSet_PopCount(ItemCount: 1024) 7.0 ns 0.0 ns 7.0 ns -1.2%
BitSetBenchmark.BitArray_PopCount(ItemCount: 1000000) 5.48 ms 1.71 μs 4.82 ms +13.5% ⚠️
BitSetBenchmark.BitSet_PopCount(ItemCount: 1000000) 5.55 μs 2.8 ns 4.93 μs +12.4% ⚠️
IntSetBenchmark.HashSet_Remove(ItemCount: 1000) 31.07 μs 2.79 μs 25.95 μs +19.7% ⚠️
LongDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 82.32 μs 5.43 μs 84.72 μs -2.8%
IntSetBenchmark.IntSet_Remove(ItemCount: 1000) 83.65 μs 8.55 μs 83.53 μs +0.1%
LongDictionaryBenchmark.LongDictionary_Remove(ItemCount: 1000) 81.85 μs 6.84 μs 90.73 μs -9.8%
IntSetBenchmark.HashSet_Remove(ItemCount: 100000) 1.68 ms 13.42 μs 1.73 ms -2.7%
LongDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 1.98 ms 40.76 μs 2.02 ms -2.2%
IntSetBenchmark.IntSet_Remove(ItemCount: 100000) 1.43 ms 50.88 μs 1.35 ms +6.2%
LongDictionaryBenchmark.LongDictionary_Remove(ItemCount: 100000) 2.95 ms 2.03 ms 1.71 ms +72.7%
CompressedIntSetBenchmark.HashSet_Union(ItemCount: 1000) 27.61 μs 5.71 μs 24.98 μs +10.5%
CompressedIntSetBenchmark.CompressedIntSet_Union(ItemCount: 1000) 67.88 μs 6.32 μs 68.45 μs -0.8%
DisjointSetBenchmark.Dictionary_Union(ItemCount: 1000) 93.03 μs 1.01 μs 98.85 μs -5.9%
DisjointSetBenchmark.DisjointSet_Union(ItemCount: 1000) 27.80 μs 186.8 ns 27.45 μs +1.3%
CompressedIntSetBenchmark.HashSet_Union(ItemCount: 100000) 3.91 ms 43.61 μs 3.89 ms +0.5%
CompressedIntSetBenchmark.CompressedIntSet_Union(ItemCount: 100000) 1.26 ms 9.41 μs 1.26 ms +0.5%
DisjointSetBenchmark.Dictionary_Union(ItemCount: 100000) 46.39 ms 3.20 ms 45.35 ms +2.3%
DisjointSetBenchmark.DisjointSet_Union(ItemCount: 100000) 7.84 ms 29.86 μs 8.19 ms -4.3%
BitSetBenchmark.BitArray_Xor(ItemCount: 1024) 95.5 ns 0.3 ns 65.6 ns +45.7% ⚠️
BitSetBenchmark.BitSet_Xor(ItemCount: 1024) 1.23 μs 3.7 ns 1.25 μs -1.4%
BitSetBenchmark.BitArray_Xor(ItemCount: 1000000) 46.07 μs 352.7 ns 43.92 μs +4.9%
BitSetBenchmark.BitSet_Xor(ItemCount: 1000000) 5.04 ms 7.91 μs 4.47 ms +12.6% ⚠️
BloomFilterBenchmark.HashSet_Add(ItemCount: 1000) 12.42 μs 295.8 ns 12.92 μs -3.9%
HashCachingSetBenchmark.HashSet_Add(ItemCount: 1000) 12.30 μs 135.2 ns 12.54 μs -1.8%
BloomFilterBenchmark.BloomFilter_Add(ItemCount: 1000) 14.47 μs 11.8 ns 14.49 μs -0.1%
HashCachingSetBenchmark.HashCachingSet_Add(ItemCount: 1000) 11.38 μs 268.6 ns 11.36 μs +0.2%
BloomFilterBenchmark.HashSet_Add(ItemCount: 100000) 4.59 ms 141.36 μs 4.72 ms -2.7%
HashCachingSetBenchmark.HashSet_Add(ItemCount: 100000) 4.30 ms 521.31 μs 4.16 ms +3.4%
BloomFilterBenchmark.BloomFilter_Add(ItemCount: 100000) 1.10 ms 4.03 μs 1.11 ms -1.0%
HashCachingSetBenchmark.HashCachingSet_Add(ItemCount: 100000) 5.18 ms 81.26 μs 5.36 ms -3.3%
FrozenCeleritySetBenchmark.FrozenSet_Build(ItemCount: 1000) 166.77 μs 1.01 μs 166.75 μs +0.0%
FrozenCeleritySetBenchmark.FrozenCeleritySet_Build(ItemCount: 1000) 2.49 ms 55.28 μs 2.66 ms -6.2%
RankSelectBitVectorBenchmark.Array_Build(ItemCount: 1024) 91.9 ns 0.4 ns 83.2 ns +10.5% ⚠️
RankSelectBitVectorBenchmark.RankSelectBitVector_Build(ItemCount: 1024) 61.6 ns 1.0 ns 58.3 ns +5.8%
FrozenCeleritySetBenchmark.FrozenSet_Build(ItemCount: 100000) 28.90 ms 395.55 μs 29.38 ms -1.6%
FrozenCeleritySetBenchmark.FrozenCeleritySet_Build(ItemCount: 100000) 1.45 s 53.49 ms 1.45 s +0.2%
RankSelectBitVectorBenchmark.Array_Build(ItemCount: 1000000) 67.98 μs 454.8 ns 78.37 μs -13.3% ✅
RankSelectBitVectorBenchmark.RankSelectBitVector_Build(ItemCount: 1000000) 87.37 μs 666.6 ns 98.76 μs -11.5% ✅
BloomFilterBenchmark.HashSet_Contains(ItemCount: 1000) 4.72 μs 4.6 ns 4.73 μs -0.2%
FrozenCeleritySetBenchmark.FrozenSet_Contains(ItemCount: 1000) 6.87 μs 7.3 ns 6.87 μs -0.0%
HashCachingSetBenchmark.HashSet_Contains(ItemCount: 1000) 4.72 μs 5.6 ns 4.72 μs -0.0%
BloomFilterBenchmark.BloomFilter_Contains(ItemCount: 1000) 12.52 μs 6.8 ns 12.52 μs -0.0%
FrozenCeleritySetBenchmark.FrozenCeleritySet_Contains(ItemCount: 1000) 92.10 μs 2.93 μs 89.24 μs +3.2%
HashCachingSetBenchmark.HashCachingSet_Contains(ItemCount: 1000) 2.53 μs 3.6 ns 2.53 μs +0.1%
BloomFilterBenchmark.HashSet_Contains(ItemCount: 100000) 1.57 ms 14.93 μs 1.56 ms +0.5%
FrozenCeleritySetBenchmark.FrozenSet_Contains(ItemCount: 100000) 1.88 ms 66.52 μs 1.96 ms -4.2%
HashCachingSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.56 ms 19.17 μs 1.57 ms -0.3%
BloomFilterBenchmark.BloomFilter_Contains(ItemCount: 100000) 868.64 μs 764.9 ns 868.72 μs -0.0%
FrozenCeleritySetBenchmark.FrozenCeleritySet_Contains(ItemCount: 100000) 7.34 ms 35.21 μs 7.37 ms -0.3%
HashCachingSetBenchmark.HashCachingSet_Contains(ItemCount: 100000) 728.99 μs 2.20 μs 733.30 μs -0.6%
BloomFilterBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 4.54 μs 6.4 ns 4.54 μs +0.1%
HashCachingSetBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 4.54 μs 3.1 ns 4.54 μs -0.0%
BloomFilterBenchmark.BloomFilter_ContainsMissing(ItemCount: 1000) 3.53 μs 14.1 ns 3.54 μs -0.1%
HashCachingSetBenchmark.HashCachingSet_ContainsMissing(ItemCount: 1000) 2.96 μs 2.8 ns 3.12 μs -5.2%
BloomFilterBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 1.91 ms 20.24 μs 1.93 ms -1.1%
HashCachingSetBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 1.94 ms 3.95 μs 1.94 ms -0.4%
BloomFilterBenchmark.BloomFilter_ContainsMissing(ItemCount: 100000) 1.49 ms 998.5 ns 1.49 ms +0.0%
HashCachingSetBenchmark.HashCachingSet_ContainsMissing(ItemCount: 100000) 1.13 ms 735.3 ns 1.13 ms -0.2%
CelerityMultiSetBenchmark.Dictionary_Count(ItemCount: 1000) 10.31 μs 181.1 ns 10.50 μs -1.8%
CelerityMultiSetBenchmark.CelerityMultiSet_Count(ItemCount: 1000) 5.28 μs 54.1 ns 5.39 μs -2.0%
CelerityMultiSetBenchmark.Dictionary_Count(ItemCount: 100000) 1.45 ms 8.32 μs 1.46 ms -0.4%
CelerityMultiSetBenchmark.CelerityMultiSet_Count(ItemCount: 100000) 724.31 μs 4.13 μs 773.21 μs -6.3%
StringInternTableBenchmark.Dictionary_Dedupe(ItemCount: 1000) 34.49 μs 304.0 ns 35.01 μs -1.5%
StringInternTableBenchmark.StringInternTable_Dedupe(ItemCount: 1000) 35.88 μs 41.7 ns 37.42 μs -4.1%
StringInternTableBenchmark.Dictionary_Dedupe(ItemCount: 100000) 3.33 ms 38.25 μs 3.36 ms -0.7%
StringInternTableBenchmark.StringInternTable_Dedupe(ItemCount: 100000) 3.19 ms 5.88 μs 3.40 ms -6.2%
SwissDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 13.49 μs 337.1 ns 14.47 μs -6.8%
SwissDictionaryBenchmark.SwissDictionary_Insert(ItemCount: 1000) 29.48 μs 289.3 ns 30.29 μs -2.7%
SwissDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 4.38 ms 161.45 μs 4.56 ms -3.9%
SwissDictionaryBenchmark.SwissDictionary_Insert(ItemCount: 100000) 3.95 ms 71.26 μs 4.00 ms -1.2%
CelerityMultiSetBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.39 μs 9.6 ns 4.54 μs -3.2%
StringInternTableBenchmark.HashSet_Lookup(ItemCount: 1000) 33.39 μs 220.5 ns 34.70 μs -3.8%
SwissDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.72 μs 17.9 ns 4.72 μs +0.0%
CelerityMultiSetBenchmark.CelerityMultiSet_Lookup(ItemCount: 1000) 1.72 μs 1.3 ns 1.72 μs -0.0%
StringInternTableBenchmark.StringInternTable_Lookup(ItemCount: 1000) 31.43 μs 56.9 ns 33.13 μs -5.1%
SwissDictionaryBenchmark.SwissDictionary_Lookup(ItemCount: 1000) 2.99 μs 14.4 ns 3.02 μs -1.2%
CelerityMultiSetBenchmark.Dictionary_Lookup(ItemCount: 100000) 637.33 μs 3.40 μs 661.81 μs -3.7%
StringInternTableBenchmark.HashSet_Lookup(ItemCount: 100000) 3.40 ms 76.81 μs 3.25 ms +4.5%
SwissDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.59 ms 2.09 μs 1.60 ms -0.5%
CelerityMultiSetBenchmark.CelerityMultiSet_Lookup(ItemCount: 100000) 190.49 μs 569.4 ns 189.58 μs +0.5%
StringInternTableBenchmark.StringInternTable_Lookup(ItemCount: 100000) 3.17 ms 4.07 μs 3.32 ms -4.7%
SwissDictionaryBenchmark.SwissDictionary_Lookup(ItemCount: 100000) 800.61 μs 2.63 μs 825.46 μs -3.0%
RankSelectBitVectorBenchmark.Array_RankEarly(ItemCount: 1024) 1.23 μs 1.9 ns 1.33 μs -7.3%
RankSelectBitVectorBenchmark.RankSelectBitVector_RankEarly(ItemCount: 1024) 1.88 μs 1.6 ns 2.03 μs -7.4%
RankSelectBitVectorBenchmark.Array_RankEarly(ItemCount: 1000000) 32.79 μs 142.4 ns 30.65 μs +7.0%
RankSelectBitVectorBenchmark.RankSelectBitVector_RankEarly(ItemCount: 1000000) 1.88 μs 1.2 ns 2.02 μs -7.2%
RankSelectBitVectorBenchmark.Array_RankLate(ItemCount: 1024) 6.43 μs 13.9 ns 8.17 μs -21.2% ✅
RankSelectBitVectorBenchmark.RankSelectBitVector_RankLate(ItemCount: 1024) 1.88 μs 1.7 ns 2.02 μs -7.0%
RankSelectBitVectorBenchmark.Array_RankLate(ItemCount: 1000000) 4.88 ms 23.40 μs 5.51 ms -11.5% ✅
RankSelectBitVectorBenchmark.RankSelectBitVector_RankLate(ItemCount: 1000000) 1.97 μs 6.6 ns 2.02 μs -2.8%
RankSelectBitVectorBenchmark.Array_RankMid(ItemCount: 1024) 4.87 μs 7.1 ns 4.61 μs +5.6%
RankSelectBitVectorBenchmark.RankSelectBitVector_RankMid(ItemCount: 1024) 1.88 μs 1.4 ns 2.03 μs -7.4%
RankSelectBitVectorBenchmark.Array_RankMid(ItemCount: 1000000) 2.47 ms 1.54 μs 2.81 ms -12.0% ✅
RankSelectBitVectorBenchmark.RankSelectBitVector_RankMid(ItemCount: 1000000) 1.88 μs 0.8 ns 2.02 μs -7.2%
CelerityMultiSetBenchmark.Dictionary_Remove(ItemCount: 1000) 55.77 μs 4.49 μs 50.48 μs +10.5%
SwissDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 88.50 μs 6.08 μs 81.56 μs +8.5%
CelerityMultiSetBenchmark.CelerityMultiSet_Remove(ItemCount: 1000) 84.59 μs 6.79 μs 78.47 μs +7.8%
SwissDictionaryBenchmark.SwissDictionary_Remove(ItemCount: 1000) 73.10 μs 2.78 μs 84.49 μs -13.5% ✅
HashCachingSetBenchmark.HashSet_Remove(ItemCount: 1000) 32.34 μs 2.73 μs 26.44 μs +22.3% ⚠️
HashCachingSetBenchmark.HashCachingSet_Remove(ItemCount: 1000) 121.87 μs 14.16 μs 117.23 μs +4.0%
CelerityMultiSetBenchmark.Dictionary_Remove(ItemCount: 100000) 540.03 μs 14.62 μs 543.08 μs -0.6%
SwissDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.04 ms 14.20 μs 2.06 ms -1.3%
CelerityMultiSetBenchmark.CelerityMultiSet_Remove(ItemCount: 100000) 1.26 ms 11.63 μs 1.29 ms -2.2%
SwissDictionaryBenchmark.SwissDictionary_Remove(ItemCount: 100000) 1.66 ms 59.06 μs 1.74 ms -4.4%
HashCachingSetBenchmark.HashSet_Remove(ItemCount: 100000) 1.71 ms 16.37 μs 1.70 ms +0.1%
HashCachingSetBenchmark.HashCachingSet_Remove(ItemCount: 100000) 1.53 ms 75.10 μs 1.52 ms +0.6%
RankSelectBitVectorBenchmark.Array_Select(ItemCount: 1024) 13.04 μs 47.7 ns 14.09 μs -7.5%
RankSelectBitVectorBenchmark.RankSelectBitVector_Select(ItemCount: 1024) 11.42 μs 13.4 ns 10.70 μs +6.7%
RankSelectBitVectorBenchmark.Array_Select(ItemCount: 1000000) 4.23 ms 3.41 μs 4.78 ms -11.5% ✅
RankSelectBitVectorBenchmark.RankSelectBitVector_Select(ItemCount: 1000000) 25.51 μs 43.6 ns 26.09 μs -2.2%
EnumSetBenchmark.HashSet_Add 671.6 ns 96.2 ns 548.9 ns +22.4% ⚠️
EnumSetBenchmark.EnumSet_Add 85.5 ns 0.3 ns 88.5 ns -3.4%
BTreeDictionaryBenchmark.SortedDictionary_Add(ItemCount: 1000) 64.48 μs 1.31 μs 66.96 μs -3.7%
SparseSetBenchmark.HashSet_Add(ItemCount: 1000) 7.31 μs 128.5 ns 7.57 μs -3.4%
BTreeDictionaryBenchmark.BTreeDictionary_Add(ItemCount: 1000) 55.56 μs 2.50 μs 53.75 μs +3.4%
SparseSetBenchmark.SparseSet_Add(ItemCount: 1000) 5.95 μs 29.8 ns 6.50 μs -8.4%
BTreeDictionaryBenchmark.SortedDictionary_Add(ItemCount: 100000) 23.56 ms 120.37 μs 23.37 ms +0.8%
SparseSetBenchmark.HashSet_Add(ItemCount: 100000) 1.68 ms 29.23 μs 1.73 ms -2.5%
BTreeDictionaryBenchmark.BTreeDictionary_Add(ItemCount: 100000) 16.33 ms 314.02 μs 16.09 ms +1.4%
SparseSetBenchmark.SparseSet_Add(ItemCount: 100000) 1.40 ms 45.00 μs 1.51 ms -7.7%
XorFilterBenchmark.HashSet_Build(ItemCount: 1000) 8.17 μs 144.6 ns 7.87 μs +3.9%
XorFilterBenchmark.XorFilter_Build(ItemCount: 1000) 40.78 μs 1.17 μs 38.99 μs +4.6%
XorFilterBenchmark.HashSet_Build(ItemCount: 100000) 2.09 ms 36.65 μs 2.06 ms +1.7%
XorFilterBenchmark.XorFilter_Build(ItemCount: 100000) 12.48 ms 232.70 μs 12.43 ms +0.4%
SparseSetBenchmark.HashSet_ClearRefill(ItemCount: 1000) 6.00 μs 68.2 ns 5.96 μs +0.6%
SparseSetBenchmark.SparseSet_ClearRefill(ItemCount: 1000) 4.65 μs 4.9 ns 4.70 μs -1.1%
SparseSetBenchmark.HashSet_ClearRefill(ItemCount: 100000) 1.35 ms 3.31 μs 1.36 ms -0.2%
SparseSetBenchmark.SparseSet_ClearRefill(ItemCount: 100000) 639.48 μs 1.35 μs 649.20 μs -1.5%
EnumSetBenchmark.HashSet_Contains 175.1 ns 0.1 ns 175.3 ns -0.1%
EnumSetBenchmark.EnumSet_Contains 46.0 ns 0.1 ns 45.9 ns +0.3%
SparseSetBenchmark.HashSet_Contains(ItemCount: 1000) 4.67 μs 31.3 ns 4.87 μs -4.1%
XorFilterBenchmark.HashSet_Contains(ItemCount: 1000) 4.73 μs 4.7 ns 4.75 μs -0.6%
SparseSetBenchmark.SparseSet_Contains(ItemCount: 1000) 1.28 μs 1.6 ns 1.28 μs -0.1%
XorFilterBenchmark.XorFilter_Contains(ItemCount: 1000) 6.77 μs 5.2 ns 6.77 μs -0.0%
SparseSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.34 ms 6.34 μs 1.37 ms -1.9%
XorFilterBenchmark.HashSet_Contains(ItemCount: 100000) 1.60 ms 7.72 μs 1.58 ms +1.4%
SparseSetBenchmark.SparseSet_Contains(ItemCount: 100000) 253.71 μs 1.52 μs 256.97 μs -1.3%
XorFilterBenchmark.XorFilter_Contains(ItemCount: 100000) 703.82 μs 901.7 ns 703.37 μs +0.1%
XorFilterBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 4.54 μs 4.6 ns 4.54 μs +0.1%
XorFilterBenchmark.XorFilter_ContainsMissing(ItemCount: 1000) 6.79 μs 13.8 ns 6.77 μs +0.2%
XorFilterBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 1.88 ms 65.40 μs 1.84 ms +2.3%
XorFilterBenchmark.XorFilter_ContainsMissing(ItemCount: 100000) 705.18 μs 317.2 ns 705.01 μs +0.0%
SmallDictionaryBenchmark.Dictionary_Insert(ItemCount: 8) 176.6 ns 1.5 ns 158.5 ns +11.4% ⚠️
SmallDictionaryBenchmark.SmallDictionary_Insert(ItemCount: 8) 91.0 ns 1.3 ns 86.3 ns +5.4%
SmallDictionaryBenchmark.Dictionary_Insert(ItemCount: 64) 814.9 ns 8.9 ns 749.4 ns +8.7%
SmallDictionaryBenchmark.SmallDictionary_Insert(ItemCount: 64) 1.08 μs 8.2 ns 1.06 μs +2.0%
HashCachingDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 15.78 μs 1.37 μs 14.32 μs +10.2%
HashCachingDictionaryBenchmark.HashCachingDictionary_Insert(ItemCount: 1000) 11.18 μs 417.7 ns 11.15 μs +0.3%
HashCachingDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 4.64 ms 68.31 μs 4.65 ms -0.3%
HashCachingDictionaryBenchmark.HashCachingDictionary_Insert(ItemCount: 100000) 6.66 ms 253.22 μs 6.46 ms +3.2%
SmallDictionaryBenchmark.Dictionary_Lookup(ItemCount: 8) 38.0 ns 1.0 ns 37.0 ns +2.6%
SmallDictionaryBenchmark.SmallDictionary_Lookup(ItemCount: 8) 22.6 ns 1.0 ns 28.4 ns -20.5% ✅
SmallDictionaryBenchmark.Dictionary_Lookup(ItemCount: 64) 297.3 ns 0.5 ns 296.8 ns +0.2%
SmallDictionaryBenchmark.SmallDictionary_Lookup(ItemCount: 64) 1.11 μs 10.5 ns 1.11 μs +0.3%
BTreeDictionaryBenchmark.SortedDictionary_Lookup(ItemCount: 1000) 38.30 μs 2.40 μs 35.16 μs +8.9%
HashCachingDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.72 μs 14.1 ns 4.74 μs -0.5%
BTreeDictionaryBenchmark.BTreeDictionary_Lookup(ItemCount: 1000) 25.60 μs 190.6 ns 25.32 μs +1.1%
HashCachingDictionaryBenchmark.HashCachingDictionary_Lookup(ItemCount: 1000) 2.67 μs 22.1 ns 2.64 μs +1.2%
BTreeDictionaryBenchmark.SortedDictionary_Lookup(ItemCount: 100000) 18.47 ms 76.04 μs 17.89 ms +3.2%
HashCachingDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.61 ms 4.15 μs 1.55 ms +4.1%
BTreeDictionaryBenchmark.BTreeDictionary_Lookup(ItemCount: 100000) 12.99 ms 208.76 μs 13.12 ms -1.0%
HashCachingDictionaryBenchmark.HashCachingDictionary_Lookup(ItemCount: 100000) 821.51 μs 3.82 μs 809.06 μs +1.5%
FenwickTreeBenchmark.Array_Mixed(ItemCount: 1000) 183.11 μs 90.2 ns 182.79 μs +0.2%
FenwickTreeBenchmark.FenwickTree_Mixed(ItemCount: 1000) 11.19 μs 30.2 ns 11.22 μs -0.2%
BTreeDictionaryBenchmark.SortedDictionary_Mixed(ItemCount: 1000) 187.43 μs 2.85 μs 186.20 μs +0.7%
BTreeDictionaryBenchmark.BTreeDictionary_Mixed(ItemCount: 1000) 83.53 μs 2.60 μs 90.83 μs -8.0%
FenwickTreeBenchmark.Array_Mixed(ItemCount: 100000) 167.40 ms 731.73 μs 166.59 ms +0.5%
FenwickTreeBenchmark.FenwickTree_Mixed(ItemCount: 100000) 632.31 μs 15.83 μs 638.20 μs -0.9%
BTreeDictionaryBenchmark.SortedDictionary_Mixed(ItemCount: 100000) 48.00 ms 812.85 μs 49.04 ms -2.1%
BTreeDictionaryBenchmark.BTreeDictionary_Mixed(ItemCount: 100000) 26.39 ms 413.81 μs 26.68 ms -1.1%
BTreeDictionaryBenchmark.SortedDictionary_RangeScan(ItemCount: 1000) 4.53 μs 26.9 ns 4.50 μs +0.5%
BTreeDictionaryBenchmark.BTreeDictionary_RangeScan(ItemCount: 1000) 78.9 ns 1.5 ns 77.7 ns +1.5%
BTreeDictionaryBenchmark.SortedDictionary_RangeScan(ItemCount: 100000) 1.24 ms 3.85 μs 1.23 ms +0.7%
BTreeDictionaryBenchmark.BTreeDictionary_RangeScan(ItemCount: 100000) 5.79 μs 19.4 ns 5.78 μs +0.1%
FenwickTreeBenchmark.Array_RangeSum(ItemCount: 1000) 220.89 μs 184.3 ns 221.01 μs -0.1%
FenwickTreeBenchmark.FenwickTree_RangeSum(ItemCount: 1000) 7.45 μs 5.9 ns 7.45 μs +0.0%
FenwickTreeBenchmark.Array_RangeSum(ItemCount: 100000) 158.99 ms 186.25 μs 159.01 ms -0.0%
FenwickTreeBenchmark.FenwickTree_RangeSum(ItemCount: 100000) 326.99 μs 1.56 μs 349.88 μs -6.5%
EnumSetBenchmark.HashSet_Remove 2.91 μs 89.9 ns 3.02 μs -3.8%
EnumSetBenchmark.EnumSet_Remove 1.44 μs 319.7 ns 1.20 μs +20.5%
SmallDictionaryBenchmark.Dictionary_Remove(ItemCount: 8) 1.40 μs 229.9 ns 1.31 μs +6.8%
SmallDictionaryBenchmark.SmallDictionary_Remove(ItemCount: 8) 1.58 μs 228.0 ns 1.44 μs +9.9%
SmallDictionaryBenchmark.Dictionary_Remove(ItemCount: 64) 5.71 μs 828.9 ns 5.41 μs +5.5%
SmallDictionaryBenchmark.SmallDictionary_Remove(ItemCount: 64) 24.43 μs 1.24 μs 25.54 μs -4.3%
BTreeDictionaryBenchmark.SortedDictionary_Remove(ItemCount: 1000) 789.86 μs 11.39 μs 798.79 μs -1.1%
HashCachingDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 82.95 μs 8.55 μs 83.87 μs -1.1%
BTreeDictionaryBenchmark.BTreeDictionary_Remove(ItemCount: 1000) 313.43 μs 14.02 μs 313.12 μs +0.1%
HashCachingDictionaryBenchmark.HashCachingDictionary_Remove(ItemCount: 1000) 123.63 μs 4.11 μs 118.47 μs +4.4%
SparseSetBenchmark.HashSet_Remove(ItemCount: 1000) 24.77 μs 1.32 μs 26.47 μs -6.4%
SparseSetBenchmark.SparseSet_Remove(ItemCount: 1000) 23.83 μs 4.08 μs 22.58 μs +5.5%
BTreeDictionaryBenchmark.SortedDictionary_Remove(ItemCount: 100000) 26.71 ms 622.28 μs 26.44 ms +1.0%
HashCachingDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.05 ms 20.87 μs 2.03 ms +1.1%
BTreeDictionaryBenchmark.BTreeDictionary_Remove(ItemCount: 100000) 18.21 ms 143.36 μs 18.28 ms -0.4%
HashCachingDictionaryBenchmark.HashCachingDictionary_Remove(ItemCount: 100000) 1.79 ms 79.07 μs 1.75 ms +2.4%
SparseSetBenchmark.HashSet_Remove(ItemCount: 100000) 1.48 ms 14.79 μs 1.63 ms -9.0%
SparseSetBenchmark.SparseSet_Remove(ItemCount: 100000) 787.87 μs 7.41 μs 802.06 μs -1.8%
EnumSetBenchmark.HashSet_Union 430.7 ns 11.0 ns 449.1 ns -4.1%
EnumSetBenchmark.EnumSet_Union 22.5 ns 0.6 ns 22.8 ns -1.6%
BTreeSetBenchmark.SortedSet_Add(ItemCount: 1000) 43.11 μs 1.34 μs 44.12 μs -2.3%
CeleritySetBenchmark.HashSet_Add(ItemCount: 1000) 12.85 μs 563.8 ns 12.52 μs +2.7%
CuckooFilterBenchmark.HashSet_Add(ItemCount: 1000) 14.10 μs 472.7 ns 12.62 μs +11.7% ⚠️
HyperLogLogBenchmark.HashSet_Add(ItemCount: 1000) 12.51 μs 371.8 ns 12.65 μs -1.1%
BTreeSetBenchmark.BTreeSet_Add(ItemCount: 1000) 41.81 μs 102.7 ns 41.82 μs -0.0%
CeleritySetBenchmark.CeleritySet_Add(ItemCount: 1000) 8.93 μs 89.9 ns 9.67 μs -7.7%
CuckooFilterBenchmark.CuckooFilter_Add(ItemCount: 1000) 7.29 μs 16.2 ns 7.94 μs -8.2%
HyperLogLogBenchmark.HyperLogLog_Add(ItemCount: 1000) 27.39 μs 202.4 ns 29.87 μs -8.3%
BTreeSetBenchmark.SortedSet_Add(ItemCount: 100000) 21.03 ms 176.14 μs 21.47 ms -2.1%
CeleritySetBenchmark.HashSet_Add(ItemCount: 100000) 5.08 ms 88.13 μs 5.27 ms -3.5%
CuckooFilterBenchmark.HashSet_Add(ItemCount: 100000) 4.74 ms 149.67 μs 4.86 ms -2.4%
HyperLogLogBenchmark.HashSet_Add(ItemCount: 100000) 4.89 ms 60.47 μs 5.06 ms -3.4%
BTreeSetBenchmark.BTreeSet_Add(ItemCount: 100000) 14.01 ms 79.06 μs 14.03 ms -0.2%
CeleritySetBenchmark.CeleritySet_Add(ItemCount: 100000) 3.16 ms 24.52 μs 3.54 ms -10.6% ✅
CuckooFilterBenchmark.CuckooFilter_Add(ItemCount: 100000) 2.10 ms 9.15 μs 2.35 ms -10.6% ✅
HyperLogLogBenchmark.HyperLogLog_Add(ItemCount: 100000) 570.06 μs 5.59 μs 475.87 μs +19.8% ⚠️
BTreeSetBenchmark.SortedSet_Contains(ItemCount: 1000) 16.71 μs 24.4 ns 16.72 μs -0.0%
CeleritySetBenchmark.HashSet_Contains(ItemCount: 1000) 4.74 μs 5.8 ns 4.72 μs +0.4%
CuckooFilterBenchmark.HashSet_Contains(ItemCount: 1000) 4.72 μs 6.8 ns 4.74 μs -0.4%
BTreeSetBenchmark.BTreeSet_Contains(ItemCount: 1000) 17.30 μs 163.3 ns 17.32 μs -0.1%
CeleritySetBenchmark.CeleritySet_Contains(ItemCount: 1000) 1.85 μs 9.4 ns 2.05 μs -9.6% ✅
CuckooFilterBenchmark.CuckooFilter_Contains(ItemCount: 1000) 4.92 μs 5.5 ns 5.55 μs -11.4% ✅
BTreeSetBenchmark.SortedSet_Contains(ItemCount: 100000) 15.90 ms 114.02 μs 15.11 ms +5.2%
CeleritySetBenchmark.HashSet_Contains(ItemCount: 100000) 1.59 ms 5.82 μs 1.51 ms +5.0%
CuckooFilterBenchmark.HashSet_Contains(ItemCount: 100000) 1.60 ms 5.19 μs 1.47 ms +8.9%
BTreeSetBenchmark.BTreeSet_Contains(ItemCount: 100000) 13.02 ms 90.75 μs 12.63 ms +3.1%
CeleritySetBenchmark.CeleritySet_Contains(ItemCount: 100000) 595.72 μs 3.20 μs 510.59 μs +16.7% ⚠️
CuckooFilterBenchmark.CuckooFilter_Contains(ItemCount: 100000) 1.75 ms 10.10 μs 1.98 ms -11.6% ✅
CuckooFilterBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 4.54 μs 4.0 ns 4.57 μs -0.7%
CuckooFilterBenchmark.CuckooFilter_ContainsMissing(ItemCount: 1000) 8.43 μs 6.9 ns 9.61 μs -12.3% ✅
CuckooFilterBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 1.92 ms 19.45 μs 1.97 ms -2.7%
CuckooFilterBenchmark.CuckooFilter_ContainsMissing(ItemCount: 100000) 876.62 μs 741.2 ns 985.29 μs -11.0% ✅
HyperLogLogBenchmark.HashSet_Estimate(ItemCount: 1000) 0.0 ns 0.0 ns 0.0 ns +37.8%
HyperLogLogBenchmark.HyperLogLog_Estimate(ItemCount: 1000) 23.46 μs 23.7 ns 26.40 μs -11.1% ✅
HyperLogLogBenchmark.HashSet_Estimate(ItemCount: 100000) 0.0 ns 0.0 ns 0.0 ns +64.9%
HyperLogLogBenchmark.HyperLogLog_Estimate(ItemCount: 100000) 22.98 μs 7.3 ns 27.84 μs -17.5% ✅
LruCacheBenchmark.Dictionary_Get(ItemCount: 1000) 30.90 μs 5.55 μs 24.38 μs +26.8% ⚠️
LruCacheBenchmark.LruCache_Get(ItemCount: 1000) 7.00 μs 195.7 ns 7.77 μs -9.9% ✅
LruCacheBenchmark.Dictionary_Get(ItemCount: 100000) 25.06 μs 368.1 ns 26.23 μs -4.4%
LruCacheBenchmark.LruCache_Get(ItemCount: 100000) 6.93 μs 30.2 ns 7.67 μs -9.7% ✅
LruCacheBenchmark.Dictionary_GetMissing(ItemCount: 1000) 4.83 μs 169.2 ns 4.59 μs +5.3%
LruCacheBenchmark.LruCache_GetMissing(ItemCount: 1000) 3.60 μs 4.0 ns 3.67 μs -2.0%
LruCacheBenchmark.Dictionary_GetMissing(ItemCount: 100000) 558.52 μs 41.85 μs 535.28 μs +4.3%
LruCacheBenchmark.LruCache_GetMissing(ItemCount: 100000) 1.34 ms 490.8 ns 1.51 ms -11.5% ✅
PooledCelerityDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 13.93 μs 363.4 ns 13.11 μs +6.3%
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Insert(ItemCount: 1000) 8.09 μs 95.4 ns 8.35 μs -3.0%
PooledCelerityDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 5.09 ms 70.63 μs 5.26 ms -3.3%
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Insert(ItemCount: 100000) 2.98 ms 6.85 μs 3.33 ms -10.6% ✅
PooledCelerityDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.71 μs 13.5 ns 4.73 μs -0.5%
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Lookup(ItemCount: 1000) 2.44 μs 105.5 ns 2.50 μs -2.7%
PooledCelerityDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.57 ms 44.88 μs 1.61 ms -2.2%
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Lookup(ItemCount: 100000) 770.38 μs 1.68 μs 1.07 ms -28.0% ✅
BTreeSetBenchmark.SortedSet_Mixed(ItemCount: 1000) 100.46 μs 1.32 μs 100.99 μs -0.5%
BTreeSetBenchmark.BTreeSet_Mixed(ItemCount: 1000) 63.00 μs 454.7 ns 60.71 μs +3.8%
BTreeSetBenchmark.SortedSet_Mixed(ItemCount: 100000) 32.23 ms 272.11 μs 31.87 ms +1.1%
BTreeSetBenchmark.BTreeSet_Mixed(ItemCount: 100000) 23.60 ms 111.69 μs 24.03 ms -1.8%
LruCacheBenchmark.Dictionary_Put(ItemCount: 1000) 101.17 μs 2.27 μs 88.36 μs +14.5% ⚠️
LruCacheBenchmark.LruCache_Put(ItemCount: 1000) 478.73 μs 18.92 μs 402.38 μs +19.0% ⚠️
LruCacheBenchmark.Dictionary_Put(ItemCount: 100000) 8.41 ms 101.68 μs 7.94 ms +6.0%
LruCacheBenchmark.LruCache_Put(ItemCount: 100000) 5.80 ms 49.15 μs 6.54 ms -11.3% ✅
BTreeSetBenchmark.SortedSet_RangeScan(ItemCount: 1000) 176.5 ns 1.8 ns 174.8 ns +1.0%
BTreeSetBenchmark.BTreeSet_RangeScan(ItemCount: 1000) 73.8 ns 0.3 ns 77.5 ns -4.8%
BTreeSetBenchmark.SortedSet_RangeScan(ItemCount: 100000) 10.23 μs 127.4 ns 9.72 μs +5.2%
BTreeSetBenchmark.BTreeSet_RangeScan(ItemCount: 100000) 5.19 μs 14.3 ns 5.25 μs -1.1%
BTreeSetBenchmark.SortedSet_Remove(ItemCount: 1000) 796.84 μs 40.04 μs 722.79 μs +10.2% ⚠️
CeleritySetBenchmark.HashSet_Remove(ItemCount: 1000) 31.70 μs 2.82 μs 28.31 μs +11.9%
PooledCelerityDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 80.88 μs 7.32 μs 78.24 μs +3.4%
BTreeSetBenchmark.BTreeSet_Remove(ItemCount: 1000) 272.00 μs 12.83 μs 273.00 μs -0.4%
CeleritySetBenchmark.CeleritySet_Remove(ItemCount: 1000) 115.81 μs 8.65 μs 115.41 μs +0.3%
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Remove(ItemCount: 1000) 124.58 μs 11.41 μs 124.11 μs +0.4%
CuckooFilterBenchmark.HashSet_Remove(ItemCount: 1000) 13.60 μs 112.8 ns 13.71 μs -0.7%
CuckooFilterBenchmark.CuckooFilter_Remove(ItemCount: 1000) 13.15 μs 13.3 ns 14.35 μs -8.3%
BTreeSetBenchmark.SortedSet_Remove(ItemCount: 100000) 25.56 ms 429.85 μs 25.04 ms +2.1%
CeleritySetBenchmark.HashSet_Remove(ItemCount: 100000) 1.72 ms 18.42 μs 1.68 ms +2.5%
PooledCelerityDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.20 ms 133.67 μs 2.00 ms +9.8%
BTreeSetBenchmark.BTreeSet_Remove(ItemCount: 100000) 15.38 ms 142.58 μs 15.35 ms +0.2%
CeleritySetBenchmark.CeleritySet_Remove(ItemCount: 100000) 1.39 ms 12.70 μs 1.42 ms -2.7%
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Remove(ItemCount: 100000) 1.64 ms 37.19 μs 1.72 ms -4.8%
CuckooFilterBenchmark.HashSet_Remove(ItemCount: 100000) 3.91 ms 37.96 μs 3.75 ms +4.2%
CuckooFilterBenchmark.CuckooFilter_Remove(ItemCount: 100000) 3.99 ms 10.74 μs 4.51 ms -11.7% ✅
LongSetBenchmark.HashSet_Add(ItemCount: 1000) 13.50 μs 296.9 ns 13.94 μs -3.2%
RobinHoodSetBenchmark.HashSet_Add(ItemCount: 1000) 11.96 μs 159.3 ns 12.78 μs -6.4%
SwissSetBenchmark.HashSet_Add(ItemCount: 1000) 13.29 μs 509.8 ns 12.95 μs +2.7%
LongSetBenchmark.LongSet_Add(ItemCount: 1000) 9.56 μs 151.6 ns 9.85 μs -2.9%
RobinHoodSetBenchmark.RobinHoodSet_Add(ItemCount: 1000) 17.27 μs 139.4 ns 18.18 μs -5.0%
SwissSetBenchmark.SwissSet_Add(ItemCount: 1000) 27.15 μs 165.7 ns 27.15 μs -0.0%
LongSetBenchmark.HashSet_Add(ItemCount: 100000) 4.47 ms 176.31 μs 5.17 ms -13.5% ✅
RobinHoodSetBenchmark.HashSet_Add(ItemCount: 100000) 4.35 ms 500.17 μs 4.32 ms +0.7%
SwissSetBenchmark.HashSet_Add(ItemCount: 100000) 4.68 ms 125.72 μs 4.66 ms +0.5%
LongSetBenchmark.LongSet_Add(ItemCount: 100000) 6.18 ms 44.16 μs 6.72 ms -8.1%
RobinHoodSetBenchmark.RobinHoodSet_Add(ItemCount: 100000) 6.18 ms 50.83 μs 6.32 ms -2.2%
SwissSetBenchmark.SwissSet_Add(ItemCount: 100000) 4.65 ms 35.37 μs 4.56 ms +2.0%
FrozenCelerityDictionaryBenchmark.FrozenDictionary_Build(ItemCount: 1000) 163.16 μs 1.44 μs 165.58 μs -1.5%
FrozenCelerityDictionaryBenchmark.FrozenCelerityDictionary_Build(ItemCount: 1000) 4.33 ms 613.92 μs 3.43 ms +26.4% ⚠️
FrozenCelerityDictionaryBenchmark.FrozenDictionary_Build(ItemCount: 100000) 29.04 ms 530.52 μs 29.50 ms -1.6%
FrozenCelerityDictionaryBenchmark.FrozenCelerityDictionary_Build(ItemCount: 100000) 1.54 s 49.04 ms 1.38 s +11.6%
LongSetBenchmark.HashSet_Contains(ItemCount: 1000) 4.80 μs 51.9 ns 5.06 μs -5.1%
RobinHoodSetBenchmark.HashSet_Contains(ItemCount: 1000) 4.72 μs 4.7 ns 4.72 μs -0.0%
SwissSetBenchmark.HashSet_Contains(ItemCount: 1000) 4.74 μs 27.2 ns 4.75 μs -0.1%
LongSetBenchmark.LongSet_Contains(ItemCount: 1000) 2.01 μs 6.9 ns 2.09 μs -3.8%
RobinHoodSetBenchmark.RobinHoodSet_Contains(ItemCount: 1000) 2.50 μs 11.1 ns 2.53 μs -1.2%
SwissSetBenchmark.SwissSet_Contains(ItemCount: 1000) 2.86 μs 5.8 ns 2.86 μs -0.0%
StringKeyProbeBenchmark.HashSet_Contains(ItemCount: 1000) 18.16 μs 97.2 ns 16.46 μs +10.3% ⚠️
StringKeyProbeBenchmark.CeleritySet_Contains(ItemCount: 1000) 24.40 μs 118.3 ns 27.71 μs -11.9% ✅
LongSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.63 ms 9.42 μs 1.58 ms +3.1%
RobinHoodSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.58 ms 4.01 μs 1.54 ms +2.4%
SwissSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.57 ms 15.68 μs 1.57 ms -0.5%
LongSetBenchmark.LongSet_Contains(ItemCount: 100000) 639.58 μs 394.5 ns 584.91 μs +9.3%
RobinHoodSetBenchmark.RobinHoodSet_Contains(ItemCount: 100000) 741.59 μs 836.4 ns 745.60 μs -0.5%
SwissSetBenchmark.SwissSet_Contains(ItemCount: 100000) 608.29 μs 15.91 μs 634.62 μs -4.1%
StringKeyProbeBenchmark.HashSet_Contains(ItemCount: 100000) 3.46 ms 20.50 μs 3.58 ms -3.4%
StringKeyProbeBenchmark.CeleritySet_Contains(ItemCount: 100000) 4.87 ms 47.71 μs 5.44 ms -10.6% ✅
RobinHoodSetBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 4.54 μs 4.7 ns 4.54 μs -0.1%
SwissSetBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 4.54 μs 3.2 ns 4.54 μs -0.0%
RobinHoodSetBenchmark.RobinHoodSet_ContainsMissing(ItemCount: 1000) 2.74 μs 2.6 ns 2.74 μs -0.2%
SwissSetBenchmark.SwissSet_ContainsMissing(ItemCount: 1000) 2.37 μs 2.6 ns 2.37 μs -0.0%
RobinHoodSetBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 1.92 ms 4.11 μs 1.93 ms -0.5%
SwissSetBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 1.93 ms 8.47 μs 1.92 ms +0.7%
RobinHoodSetBenchmark.RobinHoodSet_ContainsMissing(ItemCount: 100000) 1.18 ms 2.41 μs 1.19 ms -0.7%
SwissSetBenchmark.SwissSet_ContainsMissing(ItemCount: 100000) 343.33 μs 5.18 μs 342.25 μs +0.3%
RobinHoodDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 14.97 μs 326.0 ns 15.13 μs -1.1%
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Insert(ItemCount: 1000) 17.99 μs 449.6 ns 19.23 μs -6.5%
RobinHoodDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 4.72 ms 82.39 μs 5.18 ms -8.9%
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Insert(ItemCount: 100000) 8.42 ms 321.20 μs 9.25 ms -8.9%
StringKeyProbeBenchmark.Dictionary_Lookup(ItemCount: 1000) 18.62 μs 253.8 ns 16.72 μs +11.3% ⚠️
StringKeyProbeBenchmark.CelerityDictionary_Lookup(ItemCount: 1000) 26.79 μs 479.1 ns 29.63 μs -9.6% ✅
FrozenCelerityDictionaryBenchmark.FrozenDictionary_Lookup(ItemCount: 1000) 7.33 μs 12.6 ns 7.63 μs -3.9%
RobinHoodDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.75 μs 32.0 ns 4.72 μs +0.6%
FrozenCelerityDictionaryBenchmark.FrozenCelerityDictionary_Lookup(ItemCount: 1000) 86.87 μs 3.09 μs 80.71 μs +7.6%
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Lookup(ItemCount: 1000) 2.87 μs 16.4 ns 3.05 μs -5.8%
StringKeyProbeBenchmark.Dictionary_Lookup(ItemCount: 100000) 3.76 ms 48.04 μs 3.71 ms +1.3%
StringKeyProbeBenchmark.CelerityDictionary_Lookup(ItemCount: 100000) 5.94 ms 470.49 μs 6.56 ms -9.4%
FrozenCelerityDictionaryBenchmark.FrozenDictionary_Lookup(ItemCount: 100000) 2.00 ms 33.20 μs 2.08 ms -4.1%
RobinHoodDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.60 ms 6.40 μs 1.62 ms -1.2%
FrozenCelerityDictionaryBenchmark.FrozenCelerityDictionary_Lookup(ItemCount: 100000) 8.03 ms 307.88 μs 8.32 ms -3.4%
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Lookup(ItemCount: 100000) 863.32 μs 5.21 μs 903.55 μs -4.5%
StringKeyProbeBenchmark.Dictionary_LookupMissing(ItemCount: 1000) 14.99 μs 62.4 ns 15.17 μs -1.2%
StringKeyProbeBenchmark.CelerityDictionary_LookupMissing(ItemCount: 1000) 28.36 μs 59.3 ns 32.84 μs -13.7% ✅
StringKeyProbeBenchmark.Dictionary_LookupMissing(ItemCount: 100000) 4.25 ms 163.10 μs 4.45 ms -4.6%
StringKeyProbeBenchmark.CelerityDictionary_LookupMissing(ItemCount: 100000) 6.14 ms 524.59 μs 11.04 ms -44.3% ✅
LongSetBenchmark.HashSet_Remove(ItemCount: 1000) 77.55 μs 6.82 μs 74.85 μs +3.6%
RobinHoodDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 80.35 μs 7.92 μs 82.93 μs -3.1%
LongSetBenchmark.LongSet_Remove(ItemCount: 1000) 87.24 μs 6.36 μs 75.44 μs +15.6%
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Remove(ItemCount: 1000) 124.75 μs 17.59 μs 115.53 μs +8.0%
RobinHoodSetBenchmark.HashSet_Remove(ItemCount: 1000) 27.65 μs 3.54 μs 32.52 μs -15.0%
SwissSetBenchmark.HashSet_Remove(ItemCount: 1000) 27.37 μs 1.33 μs 32.70 μs -16.3%
RobinHoodSetBenchmark.RobinHoodSet_Remove(ItemCount: 1000) 112.57 μs 4.12 μs 118.41 μs -4.9%
SwissSetBenchmark.SwissSet_Remove(ItemCount: 1000) 68.96 μs 3.00 μs 72.00 μs -4.2%
LongSetBenchmark.HashSet_Remove(ItemCount: 100000) 1.98 ms 38.99 μs 1.95 ms +1.5%
RobinHoodDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.05 ms 20.61 μs 2.40 ms -14.8% ✅
LongSetBenchmark.LongSet_Remove(ItemCount: 100000) 1.43 ms 15.27 μs 1.59 ms -10.2% ✅
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Remove(ItemCount: 100000) 1.73 ms 25.92 μs 2.41 ms -27.9% ✅
RobinHoodSetBenchmark.HashSet_Remove(ItemCount: 100000) 1.70 ms 16.75 μs 1.71 ms -0.6%
SwissSetBenchmark.HashSet_Remove(ItemCount: 100000) 1.70 ms 6.81 μs 1.71 ms -0.5%
RobinHoodSetBenchmark.RobinHoodSet_Remove(ItemCount: 100000) 1.38 ms 53.17 μs 1.57 ms -11.7%
SwissSetBenchmark.SwissSet_Remove(ItemCount: 100000) 1.04 ms 26.30 μs 1.08 ms -4.2%
FrozenCelerityDictionaryBenchmark.FrozenDictionary_SpanLookup(ItemCount: 1000) 31.16 μs 468.8 ns 28.76 μs +8.3%
FrozenCelerityDictionaryBenchmark.FrozenCelerityDictionary_SpanLookup(ItemCount: 1000) 91.18 μs 255.9 ns 84.07 μs +8.5%
FrozenCelerityDictionaryBenchmark.FrozenDictionary_SpanLookup(ItemCount: 100000) 5.82 ms 45.26 μs 5.53 ms +5.2%
FrozenCelerityDictionaryBenchmark.FrozenCelerityDictionary_SpanLookup(ItemCount: 100000) 8.65 ms 50.57 μs 9.78 ms -11.6% ✅
Hashers (111)
Benchmark This PR StdDev main Δ
StringHasherBenchmark.Bcl_GetHashCode(Shape: ShortAscii) 15.39 μs 23.1 ns 15.38 μs +0.1%
StringHasherBenchmark.EqualityComparer_Default(Shape: ShortAscii) 15.37 μs 14.7 ns 15.37 μs -0.0%
StringHasherBenchmark.Djb2(Shape: ShortAscii) 22.71 μs 18.8 ns 22.67 μs +0.2%
StringHasherBenchmark.Djb2A(Shape: ShortAscii) 22.75 μs 65.2 ns 22.70 μs +0.2%
StringHasherBenchmark.Sdbm(Shape: ShortAscii) 33.13 μs 48.5 ns 33.08 μs +0.1%
StringHasherBenchmark.Elf(Shape: ShortAscii) 44.84 μs 235.3 ns 44.70 μs +0.3%
StringHasherBenchmark.Crc32(Shape: ShortAscii) 50.56 μs 54.5 ns 50.53 μs +0.0%
StringHasherBenchmark.Adler32(Shape: ShortAscii) 96.46 μs 45.4 ns 96.46 μs +0.0%
StringHasherBenchmark.FnV1(Shape: ShortAscii) 27.12 μs 15.4 ns 27.14 μs -0.1%
StringHasherBenchmark.FnV1_64(Shape: ShortAscii) 25.80 μs 45.0 ns 25.77 μs +0.1%
StringHasherBenchmark.FnV1A(Shape: ShortAscii) 11.05 μs 17.5 ns 11.07 μs -0.1%
StringHasherBenchmark.FnV1A_Full(Shape: ShortAscii) 25.83 μs 15.1 ns 25.85 μs -0.0%
StringHasherBenchmark.FnV1A_64(Shape: ShortAscii) 27.87 μs 20.3 ns 27.85 μs +0.1%
StringHasherBenchmark.JenkinsOaat(Shape: ShortAscii) 39.50 μs 25.2 ns 39.50 μs +0.0%
StringHasherBenchmark.Murmur2(Shape: ShortAscii) 15.43 μs 51.2 ns 15.42 μs +0.1%
StringHasherBenchmark.Murmur3(Shape: ShortAscii) 17.16 μs 43.9 ns 17.14 μs +0.1%
StringHasherBenchmark.XxHash32(Shape: ShortAscii) 16.90 μs 18.2 ns 16.90 μs +0.0%
StringHasherBenchmark.XxHash64(Shape: ShortAscii) 18.38 μs 22.7 ns 18.38 μs -0.0%
StringHasherBenchmark.XxHash3(Shape: ShortAscii) 15.42 μs 21.3 ns 15.45 μs -0.2%
StringHasherBenchmark.CityHash64(Shape: ShortAscii) 15.56 μs 11.4 ns 15.56 μs +0.0%
StringHasherBenchmark.MetroHash64(Shape: ShortAscii) 15.44 μs 17.8 ns 15.41 μs +0.1%
StringHasherBenchmark.SipHash13(Shape: ShortAscii) 27.57 μs 69.9 ns 27.63 μs -0.2%
StringHasherBenchmark.SipHash24(Shape: ShortAscii) 37.83 μs 113.7 ns 37.92 μs -0.2%
StringHasherBenchmark.HalfSipHash24(Shape: ShortAscii) 49.72 μs 139.7 ns 49.83 μs -0.2%
StringHasherBenchmark.HighwayHash64(Shape: ShortAscii) 415.10 μs 2.96 μs 411.10 μs +1.0%
StringHasherBenchmark.XxHash64_Hash64(Shape: ShortAscii) 17.33 μs 21.6 ns 17.35 μs -0.1%
StringHasherBenchmark.SipHash24_Hash64(Shape: ShortAscii) 37.79 μs 86.6 ns 37.84 μs -0.1%
StringHasherBenchmark.Bcl_GetHashCode(Shape: LongAscii) 96.85 μs 156.2 ns 96.88 μs -0.0%
StringHasherBenchmark.EqualityComparer_Default(Shape: LongAscii) 96.52 μs 130.9 ns 96.52 μs +0.0%
StringHasherBenchmark.Djb2(Shape: LongAscii) 223.62 μs 202.0 ns 223.82 μs -0.1%
StringHasherBenchmark.Djb2A(Shape: LongAscii) 223.57 μs 246.2 ns 223.64 μs -0.0%
StringHasherBenchmark.Sdbm(Shape: LongAscii) 307.96 μs 94.7 ns 308.01 μs -0.0%
StringHasherBenchmark.Elf(Shape: LongAscii) 578.53 μs 194.1 ns 578.57 μs -0.0%
StringHasherBenchmark.Crc32(Shape: LongAscii) 590.90 μs 281.8 ns 590.82 μs +0.0%
StringHasherBenchmark.Adler32(Shape: LongAscii) 785.85 μs 512.0 ns 786.48 μs -0.1%
StringHasherBenchmark.FnV1(Shape: LongAscii) 288.62 μs 459.1 ns 289.07 μs -0.2%
StringHasherBenchmark.FnV1_64(Shape: LongAscii) 281.38 μs 1.31 μs 282.84 μs -0.5%
StringHasherBenchmark.FnV1A(Shape: LongAscii) 122.64 μs 296.8 ns 122.88 μs -0.2%
StringHasherBenchmark.FnV1A_Full(Shape: LongAscii) 282.03 μs 465.0 ns 282.18 μs -0.1%
StringHasherBenchmark.FnV1A_64(Shape: LongAscii) 285.82 μs 1.16 μs 286.76 μs -0.3%
StringHasherBenchmark.JenkinsOaat(Shape: LongAscii) 377.62 μs 1.31 μs 378.46 μs -0.2%
StringHasherBenchmark.Murmur2(Shape: LongAscii) 101.49 μs 543.9 ns 101.71 μs -0.2%
StringHasherBenchmark.Murmur3(Shape: LongAscii) 115.75 μs 62.9 ns 115.67 μs +0.1%
StringHasherBenchmark.XxHash32(Shape: LongAscii) 73.49 μs 41.1 ns 73.65 μs -0.2%
StringHasherBenchmark.XxHash64(Shape: LongAscii) 94.64 μs 819.8 ns 94.50 μs +0.1%
StringHasherBenchmark.XxHash3(Shape: LongAscii) 82.10 μs 163.9 ns 81.84 μs +0.3%
StringHasherBenchmark.CityHash64(Shape: LongAscii) 124.41 μs 1.26 μs 123.73 μs +0.5%
StringHasherBenchmark.MetroHash64(Shape: LongAscii) 74.59 μs 186.5 ns 74.78 μs -0.3%
StringHasherBenchmark.SipHash13(Shape: LongAscii) 117.10 μs 78.6 ns 117.09 μs +0.0%
StringHasherBenchmark.SipHash24(Shape: LongAscii) 162.15 μs 878.7 ns 161.64 μs +0.3%
StringHasherBenchmark.HalfSipHash24(Shape: LongAscii) 250.85 μs 169.8 ns 250.99 μs -0.1%
StringHasherBenchmark.HighwayHash64(Shape: LongAscii) 845.81 μs 7.37 μs 897.32 μs -5.7%
StringHasherBenchmark.XxHash64_Hash64(Shape: LongAscii) 87.63 μs 1.20 μs 87.35 μs +0.3%
StringHasherBenchmark.SipHash24_Hash64(Shape: LongAscii) 162.23 μs 199.0 ns 162.23 μs +0.0%
StringHasherBenchmark.Bcl_GetHashCode(Shape: NonAscii) 22.85 μs 23.3 ns 22.86 μs -0.0%
StringHasherBenchmark.EqualityComparer_Default(Shape: NonAscii) 22.80 μs 41.1 ns 22.82 μs -0.1%
StringHasherBenchmark.Djb2(Shape: NonAscii) 42.92 μs 170.9 ns 43.07 μs -0.4%
StringHasherBenchmark.Djb2A(Shape: NonAscii) 43.00 μs 137.8 ns 43.02 μs -0.1%
StringHasherBenchmark.Sdbm(Shape: NonAscii) 61.55 μs 195.6 ns 61.67 μs -0.2%
StringHasherBenchmark.Elf(Shape: NonAscii) 100.03 μs 309.2 ns 100.08 μs -0.1%
StringHasherBenchmark.Crc32(Shape: NonAscii) 103.42 μs 233.4 ns 103.56 μs -0.1%
StringHasherBenchmark.Adler32(Shape: NonAscii) 174.22 μs 252.3 ns 174.61 μs -0.2%
StringHasherBenchmark.FnV1(Shape: NonAscii) 48.38 μs 33.9 ns 48.62 μs -0.5%
StringHasherBenchmark.FnV1_64(Shape: NonAscii) 50.14 μs 108.1 ns 50.23 μs -0.2%
StringHasherBenchmark.FnV1A(Shape: NonAscii) 21.95 μs 38.4 ns 21.96 μs -0.0%
StringHasherBenchmark.FnV1A_Full(Shape: NonAscii) 46.05 μs 90.3 ns 46.07 μs -0.0%
StringHasherBenchmark.FnV1A_64(Shape: NonAscii) 50.01 μs 86.0 ns 50.03 μs -0.0%
StringHasherBenchmark.JenkinsOaat(Shape: NonAscii) 73.13 μs 279.3 ns 73.30 μs -0.2%
StringHasherBenchmark.Murmur2(Shape: NonAscii) 26.98 μs 140.1 ns 27.01 μs -0.1%
StringHasherBenchmark.Murmur3(Shape: NonAscii) 31.54 μs 118.6 ns 31.60 μs -0.2%
StringHasherBenchmark.XxHash32(Shape: NonAscii) 23.85 μs 33.2 ns 23.87 μs -0.1%
StringHasherBenchmark.XxHash64(Shape: NonAscii) 30.06 μs 22.6 ns 30.06 μs -0.0%
StringHasherBenchmark.XxHash3(Shape: NonAscii) 23.39 μs 65.2 ns 23.57 μs -0.8%
StringHasherBenchmark.CityHash64(Shape: NonAscii) 22.29 μs 40.2 ns 22.27 μs +0.1%
StringHasherBenchmark.MetroHash64(Shape: NonAscii) 25.87 μs 13.8 ns 25.88 μs -0.0%
StringHasherBenchmark.SipHash13(Shape: NonAscii) 37.82 μs 122.7 ns 37.87 μs -0.1%
StringHasherBenchmark.SipHash24(Shape: NonAscii) 49.97 μs 139.5 ns 50.10 μs -0.3%
StringHasherBenchmark.HalfSipHash24(Shape: NonAscii) 73.83 μs 1.02 μs 73.31 μs +0.7%
StringHasherBenchmark.HighwayHash64(Shape: NonAscii) 494.07 μs 7.12 μs 498.05 μs -0.8%
StringHasherBenchmark.XxHash64_Hash64(Shape: NonAscii) 28.96 μs 30.5 ns 28.95 μs +0.0%
StringHasherBenchmark.SipHash24_Hash64(Shape: NonAscii) 51.33 μs 514.2 ns 51.59 μs -0.5%
IntegerHasherBenchmark.Guid_Bcl 1.50 μs 2.8 ns 1.49 μs +0.3%
IntegerHasherBenchmark.Guid_EqualityComparer 3.48 μs 4.3 ns 3.48 μs +0.0%
IntegerHasherBenchmark.Guid_Celerity 9.16 μs 40.9 ns 9.16 μs -0.0%
IntegerHasherBenchmark.Guid_Celerity_Hash64 9.08 μs 8.6 ns 9.10 μs -0.2%
IntegerHasherBenchmark.Int32_Bcl 774.4 ns 0.9 ns 774.9 ns -0.1%
IntegerHasherBenchmark.Int32_EqualityComparer 764.1 ns 0.7 ns 764.4 ns -0.0%
IntegerHasherBenchmark.Int32_Identity 763.6 ns 0.7 ns 764.1 ns -0.1%
IntegerHasherBenchmark.Int32_WangNaive 1.41 μs 0.8 ns 1.41 μs -0.0%
IntegerHasherBenchmark.Int32_Wang 3.41 μs 5.3 ns 3.42 μs -0.1%
IntegerHasherBenchmark.Int32_Murmur3 3.05 μs 0.9 ns 3.05 μs -0.0%
IntegerHasherBenchmark.Int64_Bcl 1.70 μs 22.7 ns 1.68 μs +1.2%
IntegerHasherBenchmark.Int64_EqualityComparer 1.41 μs 0.5 ns 1.41 μs -0.0%
IntegerHasherBenchmark.Int64_Identity 765.1 ns 0.7 ns 765.4 ns -0.0%
IntegerHasherBenchmark.Int64_WangNaive 2.11 μs 10.9 ns 2.11 μs +0.2%
IntegerHasherBenchmark.Int64_Wang 4.70 μs 1.7 ns 4.70 μs -0.0%
IntegerHasherBenchmark.Int64_Murmur3 2.68 μs 1.5 ns 2.68 μs +0.0%
IntegerHasherBenchmark.Int64_Wang_Hash64 4.70 μs 2.3 ns 4.70 μs -0.0%
IntegerHasherBenchmark.Int64_Murmur3_Hash64 2.68 μs 0.8 ns 2.68 μs -0.0%
IntegerHasherBenchmark.UInt32_Bcl 774.0 ns 0.3 ns 774.5 ns -0.1%
IntegerHasherBenchmark.UInt32_EqualityComparer 759.4 ns 5.3 ns 763.9 ns -0.6%
IntegerHasherBenchmark.UInt32_Default 1.41 μs 0.3 ns 1.41 μs -0.0%
IntegerHasherBenchmark.UInt32_Wang 3.43 μs 9.8 ns 3.42 μs +0.2%
IntegerHasherBenchmark.UInt32_Murmur3 3.05 μs 1.2 ns 3.05 μs +0.0%
IntegerHasherBenchmark.UInt64_Bcl 1.68 μs 0.5 ns 1.69 μs -0.8%
IntegerHasherBenchmark.UInt64_EqualityComparer 1.41 μs 0.4 ns 1.41 μs -0.0%
IntegerHasherBenchmark.UInt64_Default 2.68 μs 1.8 ns 2.68 μs +0.1%
IntegerHasherBenchmark.UInt64_Wang 4.70 μs 1.4 ns 4.70 μs -0.0%
IntegerHasherBenchmark.UInt64_WangNaive 2.10 μs 1.3 ns 2.11 μs -0.1%
IntegerHasherBenchmark.UInt64_Default_Hash64 2.68 μs 0.7 ns 2.68 μs -0.1%
IntegerHasherBenchmark.UInt64_Wang_Hash64 4.70 μs 2.5 ns 4.70 μs +0.0%

Same-runner A/B (sharded 8-way): main (28d5cca) 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
marius-bughiu merged commit 6b8d50e into main Aug 5, 2026
20 checks passed
@marius-bughiu
marius-bughiu deleted the feat/issue-313-sorted-span branch August 5, 2026 06:25
marius-bughiu added a commit that referenced this pull request Aug 5, 2026
Picks up SortedSpan (#342), which landed on main while this PR was in review.
Both changes add to the same set of shared surfaces, so all four conflicts were
additive rather than contradictory:

- CHANGELOG.md — both added [Unreleased] entries; kept both, Sorting first.
- README.md — main added SortedSpan to the Celerity.Primitives row of the
  packages table while this branch added a Celerity.Sorting row below it; kept
  main's updated row and this branch's new one.
- Celerity.Fuzz/Differential.cs — competing using directives; both are needed,
  since the file now drives SortedSpan and the three sorters.
- web/index.html — competing ship cards; kept all four, with SortedSpan next to
  the other Celerity.Primitives entry and the three Celerity.Sorting cards after
  it.

The auto-merged files were checked rather than assumed: the benchmark registry,
both dashboard COLLECTIONS arrays, the fuzz target list and the AOT smoke test
all carry both features, and neither side's ROADMAP status was clobbered.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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 sorted-span set algebra to Celerity.Primitives (SortedSpan.Intersect / Union / Except / IntersectCount / Overlaps)

2 participants