Skip to content

feat(collections): add BTreeDictionary and BTreeSet — the library's first sorted map and set - #320

Merged
marius-bughiu merged 9 commits into
mainfrom
feat/issue-305-btree
Jul 26, 2026
Merged

feat(collections): add BTreeDictionary and BTreeSet — the library's first sorted map and set#320
marius-bughiu merged 9 commits into
mainfrom
feat/issue-305-btree

Conversation

@marius-bughiu

Copy link
Copy Markdown
Owner

Closes #305.

Celerity shipped 38 collections and not one sorted map or setTrie was the only ordered type and it is string-keyed. This adds the pair the roadmap's ordered lane opens with: a cache-friendly B-tree map and set with fan-out 32 (up to 31 keys per node in flat arrays), so a lookup visits log₃₂(n) nodes instead of chasing the log₂(n) pointers a red-black tree costs — roughly 4 cache misses instead of ~20 at n = 1M.

Design

  • Struct comparer, per the issue's constraint. where TComparer : struct, IComparer<TKey>, mirroring the struct hashers, so the comparison inlines instead of costing a virtual call for every key inspected inside a node. DefaultComparer<T> wraps Comparer<T>.Default, and the BTreeDictionary<TKey, TValue> / BTreeSet<T> aliases close over it exactly as IntDictionary<TValue> fronts IntDictionary<TValue, THasher>. There are also (TComparer) constructor overloads so a stateful comparer is not assumed to be default-constructed.
  • Fan-out is a named constant with the cache-line justification (MinDegree = 16 → 31 keys, 124–248 bytes for 4- and 8-byte keys = 2–4 cache lines), as the issue asked.
  • Ordered surface: Min, Max, TryGetMin/TryGetMax, TryGetLowerBound, TryGetUpperBound, EnumerateRange(from, toExclusive) in O(log n + k), and in-order enumeration. The bounds use the Try… naming the BCL uses for may-not-exist results rather than the issue's bare LowerBound(key).
  • Interfaces: BTreeDictionary implements IDictionary<TKey, TValue?> and IReadOnlyDictionary<TKey, TValue?>; BTreeSet implements ISet<T> and IReadOnlySet<T> — so the new type does not re-open the Implement IReadOnlySet<T> on the ten mutable sets #306 / Implement IDictionary<TKey,TValue> on the dictionary family — the mirror of the set-interface gap #307 gaps.
  • Allocation-free enumeration. Both enumerators hold the traversal path in an [InlineArray] buffer (the only inline arrays in the library, hence the new AOT-smoke coverage), so a foreach allocates nothing.
  • Insertion splits bottom-up, not preemptively on the way down, so a rejected duplicate TryAdd never restructures the tree or invalidates an active enumerator. An in-place indexer overwrite does not bump the version either, matching BCL Dictionary and the family convention pinned by IndexerOverwriteEnumerationTests (Indexer overwrite of an existing key spuriously invalidates enumerators (BCL parity) #233); the primary indexer returns the non-nullable TValue that IndexerReturnTypeTests pins (CelerityDictionary indexer get returns TValue? while IntDictionary/LongDictionary return TValue #88).
  • A null/default key or element is legal and sorts first, matching how the family treats the out-of-band default key.

Measured — the issue's kill criterion

Local short-run sweep (--filter '*BTree*' --job short), ratios vs the BCL baseline at 100k items:

Add Lookup/Contains Remove RangeScan Mixed Alloc
BTreeDictionary vs SortedDictionary 0.74x 0.84x 1.12x 0.004x¹ 0.59x 0.36x
BTreeSet vs SortedSet 0.72x 0.91x 1.06x 0.43x² 0.79x 0.24x

¹ SortedDictionary has no range view, so the baseline is the best a caller can do: enumerate from the start and break at the upper bound.
² Against SortedSet.GetViewBetween — the BCL's own range view, so this one is a like-for-like comparison.

The mixed insert + lookup + range-scan row — the documented win workload the issue names — is a 1.7x win for the dictionary and 1.27x for the set, so the kill criterion is not met. The two honest losses (a delete-dominated load a few percent behind, and no win at n = 1000) are now documented in the XML remarks and the API reference rather than glossed over.

Parity rollout (all in this PR)

  • (a) Dedicated testsBTreeDictionaryTests, BTreeSetTests, BTreeDictionaryEnumerationTests, BTreeSetEnumerationTests: splits at 1/31/32/512/4000 entries, ascending/descending/shuffled inserts, three whole-tree deletion orders that drive borrow-left, borrow-right and merge, the internal-node predecessor/successor swap, default/null keys, both bounds at every probe of a 600-key tree, a 20k-operation interleaved reconciliation, and enumerator invalidation (including the cases that must not invalidate).
  • (b) Cross-collection suites — rows added to AddAndTryAddTests, ContainsValueTests, RemoveOutValueTests, TryAddDuplicateResizeTests, IEnumerableConstructorTests, SetIEnumerableConstructorTests, ReadOnlyDictionaryInterfaceTests, IndexerReturnTypeTests, IndexerOverwriteEnumerationTests. Genuinely N/A and noted in-file: ConstructorValidationTests / SetConstructorValidationTests / LoadFactorBoundaryTests / IEnumerableConstructorNullPriorityTests / EnsureCapacityAndTrimExcessTests (no capacity or load-factor surface — a B-tree grows a node at a time), TryAddProbeCountTests / BulkConstructorNoResizeTests (no hasher, no probe chain).
  • Differential + fuzzBTreeDictionaryDifferentialTests / BTreeSetDifferentialTests (CsCheck against SortedDictionary / SortedSet, asserting the enumerated sequence and the ordered surface and set algebra, not just membership), plus BTreeDictionary / BTreeSet targets in Differential.All with a key domain wide enough to actually split nodes. Both fuzz targets pass at 3–5k cases locally.
  • (c) BenchmarksBTreeDictionaryBenchmark / BTreeSetBenchmark, ItemCount params, per-Remove [IterationSetup], BCL method Baseline = true, and the mixed row; registered in Program.cs's core suite.
  • (d) DashboardCOLLECTIONS entries in web/dev/bench/index.html and detail.html, SortedDictionary/SortedSet added to BCL_TYPES so the baseline actually parses, and ship cards in web/index.html.
  • (e) Docsdocs/api/collections.md sections following the per-type template; README collection list, decision-table row, quick-start block, and the closing guidance that used to send readers to the BCL for ordered iteration.
  • AOT — a Celerity.AotSmokeTest block exercising both types, a hand-written struct comparer (a second closed generic for ILC), the split/rebalance paths, and both enumerators.
  • (f) CHANGELOG under [Unreleased]; (g) ROADMAP entry flipped to done and the "not one sorted map or set" framing updated.

Test plan

  • dotnet build clean on net8.0 / net9.0 / net10.0 (no new warnings; CS1591 gate green).
  • dotnet test — 4,595 tests pass on all three TFMs.
  • Coverage locally 98.8% line / 97.3% branch overall (gate 95/90); the new types are 96–100% line, 98–100% branch.
  • Celerity.Fuzz--target BTreeDictionary 3,000 cases and --target BTreeSet 5,000 cases pass; full --target all sweep still passes.
  • AOT smoke test runs clean.
  • Benchmarks build and run (numbers above).
  • CI matrix (ubuntu / windows / macos × net8/9/10), coverage gate, AOT publish job, and the 8-shard benchmark run.
  • gh-pages dashboard refresh on merge to main — the new BTreeDictionary / BTreeSet cards should populate from the first post-merge benchmark run.

🤖 Generated with Claude Code

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

github-actions Bot commented Jul 26, 2026

Copy link
Copy Markdown

Coverage

Metric Value
Line 98.64% (7844/7952)
Branch 97.17% (3263/3358)
Files below 100% line coverage
File Line Branch
src/Celerity/Collections/TopKEntry.cs 80% n/a
src/Celerity/Collections/XorFilter.cs 94.29% 90%
src/Celerity/Collections/EnumMap.cs 95.09% 92.19%
src/Celerity/Collections/FenwickTree.cs 96.12% 94.74%
src/Celerity/Collections/IndexedPriorityQueue.cs 96.23% 90.91%

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 Celerity’s first sorted map/set by introducing B-tree–backed ordered collections (fan-out 32 via MinDegree = 16) with allocation-free enumeration and an ordered API surface (min/max, bounds, and O(log n + k) range scans). The PR also wires the new collections through parity tests, differential fuzzing, benchmarks, docs, and the web benchmark dashboard, aligning with the roadmap item for ordered containers (Closes #305).

Changes:

  • Add BTreeDictionary<TKey, TValue, TComparer> and BTreeSet<T, TComparer> plus DefaultComparer<T> (struct comparer) to enable devirtualized comparisons.
  • Add extensive unit + differential tests, fuzz targets, AOT smoke coverage, and BenchmarkDotNet benchmarks; wire benchmarks into the web dashboard.
  • Update documentation (README + API docs), ROADMAP, and CHANGELOG for the new ordered containers.

Reviewed changes

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

Show a summary per file
File Description
src/Celerity/Collections/BTreeDictionary.cs New B-tree sorted dictionary implementation + ordered APIs + IDictionary/IReadOnlyDictionary support.
src/Celerity/Collections/BTreeSet.cs New B-tree sorted set implementation + ordered APIs + ISet/IReadOnlySet support.
src/Celerity/Collections/DefaultComparer.cs Adds default struct comparer wrapper over Comparer<T>.Default for zero-cost ordering.
src/Celerity.Tests/Collections/BTreeDictionaryTests.cs Dedicated behavioral tests for BTreeDictionary.
src/Celerity.Tests/Collections/BTreeDictionaryEnumerationTests.cs Enumeration/versioning/range-enumeration tests for BTreeDictionary.
src/Celerity.Tests/Collections/BTreeDictionaryDifferentialTests.cs CsCheck differential tests vs SortedDictionary (order-sensitive).
src/Celerity.Tests/Collections/BTreeSetTests.cs Dedicated behavioral tests for BTreeSet.
src/Celerity.Tests/Collections/BTreeSetEnumerationTests.cs Enumeration/versioning/range-enumeration tests for BTreeSet.
src/Celerity.Tests/Collections/BTreeSetDifferentialTests.cs CsCheck differential tests vs SortedSet (order-sensitive).
src/Celerity.Tests/Collections/AddAndTryAddTests.cs Adds shared-suite coverage rows for BTreeDictionary add/try-add semantics.
src/Celerity.Tests/Collections/ContainsValueTests.cs Adds shared-suite coverage for BTreeDictionary ContainsValue.
src/Celerity.Tests/Collections/IEnumerableConstructorTests.cs Adds shared-suite coverage for BTreeDictionary enumerable constructor.
src/Celerity.Tests/Collections/IndexerOverwriteEnumerationTests.cs Adds parity coverage that indexer overwrite doesn’t invalidate enumeration (BTreeDictionary).
src/Celerity.Tests/Collections/IndexerReturnTypeTests.cs Pins BTreeDictionary primary indexer return type to non-nullable TValue.
src/Celerity.Tests/Collections/ReadOnlyDictionaryInterfaceTests.cs Validates IReadOnlyDictionary behavior and ordered Keys/Values for BTreeDictionary.
src/Celerity.Tests/Collections/RemoveOutValueTests.cs Adds shared-suite coverage for Remove(key, out value) on BTreeDictionary.
src/Celerity.Tests/Collections/SetIEnumerableConstructorTests.cs Adds shared-suite coverage for BTreeSet enumerable constructor invariants.
src/Celerity.Tests/Collections/TryAddDuplicateResizeTests.cs Adds enumerator-validity tests for duplicate vs split-triggering inserts at node capacity.
src/Celerity.Fuzz/Differential.cs Registers B-tree fuzz targets and adds order-sensitive oracle comparisons.
src/Celerity.Benchmarks/BTreeDictionaryBenchmark.cs Adds BTreeDictionary benchmarks incl. mixed workload + range scan.
src/Celerity.Benchmarks/BTreeSetBenchmark.cs Adds BTreeSet benchmarks incl. mixed workload + range scan.
src/Celerity.Benchmarks/Program.cs Registers new B-tree benchmarks in the core suite.
src/Celerity.AotSmokeTest/Program.cs Adds Native AOT smoke coverage for both B-tree types + inline-array enumerators + custom struct comparer instantiation.
web/index.html Adds “What ships in the box” cards for BTreeDictionary/BTreeSet.
web/dev/bench/index.html Adds benchmark dashboard wiring for B-tree collections + baseline type parsing.
web/dev/bench/detail.html Adds benchmark detail page wiring for B-tree collections + baseline type parsing.
docs/api/collections.md Adds full API documentation sections for BTreeDictionary and BTreeSet.
README.md Documents new ordered collections and updates “Choosing a collection” guidance.
ROADMAP.md Marks ordered-container roadmap item as done and links issue #305.
CHANGELOG.md Adds [Unreleased] entries for the new ordered collections and comparer helper.

Comment thread README.md Outdated
Comment thread CHANGELOG.md Outdated
marius-bughiu added a commit that referenced this pull request Jul 26, 2026
- README: the mutable hash-based sets implement ISet<T>, not IReadOnlySet<T>
  (that gap is what #306 tracks), so the "not the right answer when" paragraph
  no longer claims otherwise.
- CHANGELOG: fold the three [Unreleased] bullets into one tight entry ending in
  Closes #305, per the terse-entry convention in CLAUDE.md / CONTRIBUTING.md.

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

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

Comments suppressed due to low confidence (1)

docs/api/collections.md:3862

  • This sentence says a default element “sorts first”, but ordering is defined by TComparer. For value-type T, default(T) does not necessarily sort first (e.g., -1 precedes 0 for int). Consider documenting null ordering (when applicable) separately and treating default(T) as just another legal element.
Membership is defined by `TComparer` — two elements are the same element when the comparer orders them equal. The set-algebra members materialize the right-hand side into a `HashSet<T>`, so they compare *that* side with `EqualityComparer<T>.Default` (matching the rest of the family). A custom comparer that treats two values as equal when `EqualityComparer<T>.Default` does not — a case-insensitive order, say — can therefore disagree with `SortedSet<T>` on those members alone. A `null` (or `default`) element is legal and sorts first. Not thread-safe.

Comment thread src/Celerity/Collections/BTreeDictionary.cs Outdated
Comment thread src/Celerity/Collections/BTreeSet.cs Outdated
Comment thread src/Celerity/Collections/DefaultComparer.cs
Comment thread docs/api/collections.md Outdated
Copilot AI review requested due to automatic review settings July 26, 2026 02:05

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

Comment thread web/index.html
Comment thread docs/api/collections.md Outdated
Comment thread src/Celerity/Collections/BTreeSet.cs

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comments suppressed due to low confidence (3)

src/Celerity/Collections/BTreeDictionary.cs:47

  • In the TComparer type-parameter docs, the cref DefaultComparer{T} refers to an out-of-scope T. This comparer is for keys, so the cref should be DefaultComparer{TKey}.
/// The comparer that defines the key order. Must be a value type implementing <see cref="IComparer{TKey}"/>
/// so the JIT can devirtualize and inline it — an interface-typed comparer would cost a virtual call for
/// every key inspected inside a node. Use <see cref="DefaultComparer{T}"/> (or the two-parameter
/// <see cref="BTreeDictionary{TKey, TValue}"/> alias) for the natural order.

src/Celerity/Collections/BTreeDictionary.cs:80

  • The remarks still use Comparer{T}.Default (where T is not in scope for this type). This should reference the key type (Comparer{TKey}.Default) to avoid invalid/broken cref links.
/// Unlike <see cref="SortedDictionary{TKey, TValue}"/>, a <c>null</c> key is legal:
/// <see cref="Comparer{T}.Default"/> orders <c>null</c> before every non-<c>null</c> key (a custom
/// <typeparamref name="TComparer"/> that rejects <c>null</c> overrides that). There is no out-of-band

src/Celerity/Collections/BTreeDictionary.cs:304

  • ContainsValue XML docs reference EqualityComparer{T}.Default, but T is not a type parameter here; the comparison is against the value type. Using EqualityComparer{TValue}.Default keeps the cref valid and matches the implementation intent.
    /// <summary>
    /// Determines whether any entry holds <paramref name="value"/>, comparing with
    /// <see cref="EqualityComparer{T}.Default"/>. This is an <c>O(n)</c> scan — the tree is indexed by key,
    /// not by value.

Comment thread src/Celerity/Collections/BTreeDictionary.cs
marius-bughiu and others added 6 commits July 26, 2026 06:09
…irst sorted map and set

Celerity shipped 38 collections and not one sorted map or set: `Trie` was the
only ordered type and it is string-keyed. This adds a cache-friendly B-tree map
and set with fan-out 32 (up to 31 keys per node in flat arrays), so a lookup
visits log32(n) nodes instead of chasing the log2(n) pointers a red-black tree
costs — roughly 4 cache misses instead of ~20 at n = 1M.

Ordering is a `struct, IComparer<T>` type parameter, mirroring the struct
hashers, so the comparison inlines instead of costing a virtual call for every
key inspected inside a node; `DefaultComparer<T>` and the one/two-parameter
aliases close over `Comparer<T>.Default` for the common case.

Beyond the map/set core the types add the ordered surface a hash table cannot
answer: Min, Max, TryGetLowerBound, TryGetUpperBound, EnumerateRange in
O(log n + k), and in-order enumeration. Both enumerators hold their traversal
path in an `[InlineArray]` buffer, so a foreach allocates nothing.

Insertion splits bottom-up rather than preemptively on the way down, so a
rejected duplicate `TryAdd` never restructures the tree or invalidates an active
enumerator; an in-place indexer overwrite does not bump the version either,
matching BCL Dictionary and the rest of the family (#233).

Parity rollout in the same change:

- Dedicated tests: BTreeDictionaryTests, BTreeSetTests, and the two
  *EnumerationTests, covering splits at 1/31/32/512/4000 entries, the three
  whole-tree deletion orders that drive borrow-left, borrow-right and merge,
  the internal-node predecessor/successor swap, null/default keys, the bounds
  at every probe of a 600-key tree, and enumerator invalidation.
- Differential tests: BTreeDictionaryDifferentialTests / BTreeSetDifferentialTests
  — CsCheck against SortedDictionary/SortedSet, asserting the enumerated
  *sequence*, not just membership, plus the ordered surface and set algebra.
- Cross-collection suites: rows added to AddAndTryAddTests, ContainsValueTests,
  RemoveOutValueTests, TryAddDuplicateResizeTests, IEnumerableConstructorTests,
  SetIEnumerableConstructorTests, ReadOnlyDictionaryInterfaceTests,
  IndexerReturnTypeTests and IndexerOverwriteEnumerationTests.
- Fuzz: BTreeDictionary / BTreeSet targets in Differential.All, order-sensitive
  against the sorted BCL oracles, with a key domain wide enough to split nodes.
- Benchmarks: BTreeDictionaryBenchmark / BTreeSetBenchmark registered in the CI
  core suite, with the mixed insert + lookup + range-scan row.
- Dashboard: COLLECTIONS entries in web/dev/bench/{index,detail}.html (plus
  SortedDictionary/SortedSet in BCL_TYPES so the baseline parses) and ship cards
  in web/index.html.
- Docs: docs/api/collections.md sections, README collection list, decision-table
  row, quick-start block, and the closing guidance that used to send readers to
  the BCL for ordered iteration.
- CHANGELOG under [Unreleased]; ROADMAP entry flipped to done.

Closes #305.

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

The local short-run sweep at 100k entries puts BTreeDictionary at 0.59x
SortedDictionary on the mixed insert + lookup + range-scan workload and 0.36x
its allocation, but 1.12x on a delete-dominated load and no better at n = 1000.
Say so in the XML remarks and the API reference rather than only claiming the
win, per Guiding Principle #5.

Also covers the non-generic IEnumerator.Current on the key/value/range
enumerators, which were the only lines the suite missed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- README: the mutable hash-based sets implement ISet<T>, not IReadOnlySet<T>
  (that gap is what #306 tracks), so the "not the right answer when" paragraph
  no longer claims otherwise.
- CHANGELOG: fold the three [Unreleased] bullets into one tight entry ending in
  Closes #305, per the terse-entry convention in CLAUDE.md / CONTRIBUTING.md.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Comparer<T>.Default orders null before every non-null value, which is what
makes a null key or element legal here — but that says nothing about
default(TKey) for a value type: default(int) is 0, and sorts after every
negative key like any other. The B-trees have no out-of-band default slot at
all, unlike the hash-based family, so default(TKey) is simply an ordinary key.

Reworded in the BTreeDictionary / BTreeSet / DefaultComparer XML remarks and
in both places in docs/api/collections.md, and renamed the two tests whose
names claimed default(TKey) sorts first (the assertions were already correct:
0 lands between -5 and 5).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A leaf holds a key and a value array; only an internal node adds a child array,
so "three arrays per 31 entries" overstated a fixed count. The XML remark was
already corrected; this brings docs/api/collections.md in line.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…v2.4.0 cut

v2.4.0 was tagged on main while this branch was open, which inserted a
"## [2.4.0]" heading directly under "## [Unreleased]". The rebase carried this
PR's entry into the released section; it belongs above it, under a fresh
[Unreleased] -> Added.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@marius-bughiu
marius-bughiu force-pushed the feat/issue-305-btree branch from 7cfa6ac to f80e5d6 Compare July 26, 2026 03:11
Copilot AI review requested due to automatic review settings July 26, 2026 03:11
@marius-bughiu

Copy link
Copy Markdown
Owner Author

Rebased onto main after v2.4.0 was tagged (1a71083), and force-pushed — the PR is MERGEABLE again.

One thing worth flagging, because the rebase did not conflict and so would have gone unnoticed: the release commit inserted a ## [2.4.0] - 2026-07-26 heading directly beneath ## [Unreleased], so this PR's changelog entry rebased cleanly into the already-released 2.4.0 section. I moved it back up under a fresh [Unreleased]### Added in f80e5d6; the 2.4.0 section is otherwise untouched.

Re-verified after the rebase: dotnet build clean on all three TFMs and the full suite green (4,597 tests on net8.0).

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 30 out of 30 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

CHANGELOG.md:9

  • The new [Unreleased] changelog entry is still longer/more implementation-detailed than the repo’s changelog guidance (“a few sentences at most”, user-facing). Consider tightening it to 1–2 short sentences focusing on the shipped surface and why it matters, and leave the deeper perf/implementation discussion to the PR body/docs.
- **`BTreeDictionary<TKey, TValue, TComparer>` and `BTreeSet<T, TComparer>`** (with `BTreeDictionary<TKey, TValue>` / `BTreeSet<T>` aliases and the `DefaultComparer<T>` struct comparer) in `Celerity.Collections` — the library's first sorted map and set, and the B-tree the BCL lacks. Up to 31 keys per node keep a lookup `log₃₂(n)` node visits deep instead of chasing the `log₂(n)` pointers a red-black tree costs, and both add the ordered surface a hash table cannot answer: `Min` / `Max`, lower / upper bound, `EnumerateRange` in `O(log n + k)`, and in-order enumeration. They win on the interleaved insert + lookup + range-scan workload and on memory, and lose slightly on a delete-dominated one. Not thread-safe. Closes [#305](https://github.com/marius-bughiu/Celerity/issues/305).

Comment thread src/Celerity/Collections/BTreeDictionary.cs
… index is past the end

CopyTo on the dictionary and on the key/value views validated a negative index
but let an index beyond the destination's length fall through to the
insufficient-space ArgumentException. SetOperations.CopyTo — which BTreeSet and
the rest of the set family route through — and BCL Dictionary.CopyTo both report
that as ArgumentOutOfRangeException, so the three overloads now do too.

Covered by the existing CopyTo validation tests, extended with the past-the-end
index for each of the three.

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

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

Comments suppressed due to low confidence (2)

src/Celerity.Benchmarks/BTreeDictionaryBenchmark.cs:250

  • BTreeDictionary_Mixed is intended to include an in-order range scan, but this block currently enumerates a fixed prefix from the start of the map (and ignores rangeFrom/rangeTo). Using EnumerateRange here would better match the documented workload and keep the mixed row aligned with the RangeScan benchmark.
            if ((i & 1023) == 0)
            {
                int scanned = 0;
                foreach (KeyValuePair<int, int> entry in map)
                {

src/Celerity.Benchmarks/BTreeSetBenchmark.cs:230

  • BTreeSet_Mixed is intended to include an in-order range scan, but this block currently enumerates a fixed prefix from the start of the set and ignores rangeFrom/rangeTo. Using EnumerateRange here would better match the documented workload and keep the mixed row aligned with RangeScan.
            if ((i & 1023) == 0)
            {
                int scanned = 0;
                foreach (int item in set)
                {

Comment thread src/Celerity.Benchmarks/BTreeDictionaryBenchmark.cs
Comment thread src/Celerity.Benchmarks/BTreeSetBenchmark.cs
The Mixed groups interleave inserts and lookups with an in-order scan of the
leading window, not a windowed EnumerateRange — the comments claimed the latter.
The scan is deliberately the same walk on both sides so the row measures
insert + lookup + enumeration on symmetric work; the range-API asymmetry is
isolated in the RangeScan group, which would otherwise dominate it.

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

github-actions Bot commented Jul 26, 2026

Copy link
Copy Markdown

Benchmarks

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

Highlights

Benchmark This PR StdDev main Δ
HyperLogLogBenchmark.HashSet_Add(ItemCount: 1000) 12.99 μs 97.9 ns 9.79 μs +32.8% ⚠️
PooledCeleritySetBenchmark.HashSet_Add(ItemCount: 1000) 12.52 μs 246.5 ns 9.83 μs +27.3% ⚠️
HyperLogLogBenchmark.HyperLogLog_Add(ItemCount: 1000) 27.40 μs 69.8 ns 79.09 μs -65.4% ✅
PooledCeleritySetBenchmark.PooledCeleritySet_Add(ItemCount: 1000) 8.95 μs 161.8 ns 7.46 μs +20.0% ⚠️
HyperLogLogBenchmark.HashSet_Add(ItemCount: 100000) 4.88 ms 43.97 μs 4.09 ms +19.3% ⚠️
PooledCeleritySetBenchmark.HashSet_Add(ItemCount: 100000) 4.89 ms 199.26 μs 4.08 ms +19.9% ⚠️
HyperLogLogBenchmark.HyperLogLog_Add(ItemCount: 100000) 575.93 μs 1.07 μs 475.82 μs +21.0% ⚠️
PooledCeleritySetBenchmark.PooledCeleritySet_Add(ItemCount: 100000) 2.85 ms 5.42 μs 2.46 ms +15.5% ⚠️
PooledCeleritySetBenchmark.HashSet_Contains(ItemCount: 1000) 4.75 μs 14.9 ns 3.65 μs +30.1% ⚠️
PooledCeleritySetBenchmark.PooledCeleritySet_Contains(ItemCount: 1000) 1.93 μs 20.3 ns 1.51 μs +27.6% ⚠️
PooledCeleritySetBenchmark.HashSet_Contains(ItemCount: 100000) 1.53 ms 50.00 μs 1.18 ms +30.5% ⚠️
PooledCeleritySetBenchmark.PooledCeleritySet_Contains(ItemCount: 100000) 572.96 μs 3.07 μs 390.12 μs +46.9% ⚠️
DequeBenchmark.Deque_Enumerate(ItemCount: 1000) 941.4 ns 0.7 ns 824.5 ns +14.2% ⚠️
DequeBenchmark.LinkedList_Enumerate(ItemCount: 100000) 135.15 μs 202.5 ns 118.03 μs +14.5% ⚠️
DequeBenchmark.Deque_Enumerate(ItemCount: 100000) 93.84 μs 78.7 ns 81.95 μs +14.5% ⚠️
HyperLogLogBenchmark.HyperLogLog_Estimate(ItemCount: 1000) 23.44 μs 8.5 ns 75.86 μs -69.1% ✅
HyperLogLogBenchmark.HyperLogLog_Estimate(ItemCount: 100000) 22.98 μs 10.6 ns 75.87 μs -69.7% ✅
PooledCelerityDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 15.02 μs 901.0 ns 10.23 μs +46.8% ⚠️
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Insert(ItemCount: 1000) 8.64 μs 91.9 ns 6.47 μs +33.6% ⚠️
PooledCelerityDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 4.90 ms 70.65 μs 4.26 ms +15.0% ⚠️
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Insert(ItemCount: 100000) 2.99 ms 12.40 μs 2.54 ms +17.5% ⚠️
PooledCelerityDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.72 μs 13.6 ns 3.61 μs +30.6% ⚠️
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Lookup(ItemCount: 1000) 2.31 μs 11.7 ns 1.86 μs +24.3% ⚠️
PooledCelerityDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.60 ms 6.22 μs 1.24 ms +29.0% ⚠️
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Lookup(ItemCount: 100000) 694.42 μs 7.28 μs 608.22 μs +14.2% ⚠️
DequeBenchmark.Deque_PushFront(ItemCount: 1000) 19.47 μs 1.79 μs 14.91 μs +30.7% ⚠️
DequeBenchmark.LinkedList_PushFront(ItemCount: 100000) 1.83 ms 41.39 μs 1.39 ms +31.9% ⚠️
DequeBenchmark.Deque_PushFront(ItemCount: 100000) 654.10 μs 34.72 μs 540.60 μs +21.0% ⚠️
DequeBenchmark.LinkedList_Queue(ItemCount: 1000) 55.50 μs 1.91 μs 39.62 μs +40.1% ⚠️
DequeBenchmark.Deque_Queue(ItemCount: 1000) 38.98 μs 2.00 μs 23.88 μs +63.2% ⚠️
DequeBenchmark.LinkedList_Queue(ItemCount: 100000) 4.21 ms 192.55 μs 3.73 ms +12.9% ⚠️
DequeBenchmark.Deque_Queue(ItemCount: 100000) 422.81 μs 19.40 μs 350.94 μs +20.5% ⚠️
PooledCelerityDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 85.79 μs 9.48 μs 59.20 μs +44.9% ⚠️
PooledCeleritySetBenchmark.HashSet_Remove(ItemCount: 1000) 31.95 μs 4.32 μs 22.49 μs +42.1% ⚠️
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Remove(ItemCount: 1000) 148.74 μs 10.91 μs 117.22 μs +26.9% ⚠️
PooledCeleritySetBenchmark.PooledCeleritySet_Remove(ItemCount: 1000) 151.41 μs 5.94 μs 110.33 μs +37.2% ⚠️
PooledCelerityDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.10 ms 48.07 μs 1.54 ms +36.0% ⚠️
PooledCeleritySetBenchmark.HashSet_Remove(ItemCount: 100000) 1.71 ms 16.84 μs 1.30 ms +31.2% ⚠️
PooledCeleritySetBenchmark.PooledCeleritySet_Remove(ItemCount: 100000) 1.29 ms 69.21 μs 1.06 ms +21.9% ⚠️
CountMinSketchBenchmark.CountMinSketch_Add(ItemCount: 1000) 12.82 μs 323.9 ns 10.24 μs +25.3% ⚠️
CountMinSketchBenchmark.CountMinSketch_Add(ItemCount: 100000) 1.15 ms 16.45 μs 927.96 μs +23.4% ⚠️
CountMinSketchBenchmark.CountMinSketch_Estimate(ItemCount: 1000) 8.45 μs 23.7 ns 10.07 μs -16.0% ✅
CountMinSketchBenchmark.CountMinSketch_Estimate(ItemCount: 100000) 2.34 ms 1.92 μs 2.01 ms +16.3% ⚠️
SwissDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 15.47 μs 223.5 ns 12.69 μs +21.9% ⚠️
FrozenCelerityDictionaryBenchmark.FrozenDictionary_Lookup(ItemCount: 100000) 1.85 ms 40.82 μs 2.57 ms -27.8% ✅
FrozenCelerityDictionaryBenchmark.FrozenCelerityDictionary_Lookup(ItemCount: 100000) 8.37 ms 54.09 μs 15.03 ms -44.3% ✅
SwissDictionaryBenchmark.SwissDictionary_Lookup(ItemCount: 100000) 681.08 μs 16.94 μs 810.39 μs -16.0% ✅
TopKSketchBenchmark.Dictionary_Add(ItemCount: 1000) 13.14 μs 62.5 ns 14.63 μs -10.2% ✅
HashCachingDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 13.20 μs 46.7 ns 16.04 μs -17.7% ✅
HashCachingDictionaryBenchmark.HashCachingDictionary_Insert(ItemCount: 1000) 10.12 μs 78.5 ns 12.67 μs -20.2% ✅
EnumMapBenchmark.Dictionary_Lookup 135.7 ns 0.1 ns 150.7 ns -10.0% ✅
CuckooFilterBenchmark.HashSet_Add(ItemCount: 1000) 12.03 μs 232.8 ns 9.91 μs +21.4% ⚠️
SwissSetBenchmark.HashSet_Add(ItemCount: 1000) 12.15 μs 65.9 ns 13.48 μs -9.9% ✅
CuckooFilterBenchmark.CuckooFilter_Add(ItemCount: 1000) 7.08 μs 13.4 ns 6.18 μs +14.7% ⚠️
CuckooFilterBenchmark.HashSet_Add(ItemCount: 100000) 4.68 ms 84.03 μs 3.83 ms +22.4% ⚠️
CuckooFilterBenchmark.CuckooFilter_Add(ItemCount: 100000) 2.07 ms 23.85 μs 1.81 ms +14.6% ⚠️
CuckooFilterBenchmark.HashSet_Contains(ItemCount: 1000) 4.72 μs 7.4 ns 3.67 μs +28.7% ⚠️
CuckooFilterBenchmark.CuckooFilter_Contains(ItemCount: 1000) 4.91 μs 3.8 ns 4.31 μs +14.0% ⚠️
CuckooFilterBenchmark.HashSet_Contains(ItemCount: 100000) 1.57 ms 22.77 μs 1.18 ms +33.8% ⚠️
CuckooFilterBenchmark.CuckooFilter_Contains(ItemCount: 100000) 1.75 ms 7.22 μs 1.53 ms +14.0% ⚠️
SwissSetBenchmark.SwissSet_Contains(ItemCount: 100000) 643.03 μs 3.52 μs 489.05 μs +31.5% ⚠️
CuckooFilterBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 4.54 μs 19.9 ns 3.54 μs +28.3% ⚠️
CuckooFilterBenchmark.CuckooFilter_ContainsMissing(ItemCount: 1000) 8.37 μs 8.4 ns 7.45 μs +12.3% ⚠️
CuckooFilterBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 1.91 ms 27.35 μs 1.54 ms +24.0% ⚠️
CuckooFilterBenchmark.CuckooFilter_ContainsMissing(ItemCount: 100000) 925.98 μs 303.6 ns 763.81 μs +21.2% ⚠️
SwissSetBenchmark.SwissSet_ContainsMissing(ItemCount: 100000) 351.43 μs 5.77 μs 314.91 μs +11.6% ⚠️
IndexedPriorityQueueBenchmark.PriorityQueue_DecreaseKey(ItemCount: 1000) 144.82 μs 1.54 μs 76.33 μs +89.7% ⚠️
IndexedPriorityQueueBenchmark.IndexedPriorityQueue_DecreaseKey(ItemCount: 1000) 251.77 μs 1.29 μs 178.38 μs +41.1% ⚠️
IndexedPriorityQueueBenchmark.PriorityQueue_Enqueue(ItemCount: 100000) 1.06 ms 10.82 μs 1.18 ms -10.3% ✅
SmallDictionaryBenchmark.SmallDictionary_Insert(ItemCount: 8) 84.1 ns 0.3 ns 92.9 ns -9.5% ✅
CuckooFilterBenchmark.HashSet_Remove(ItemCount: 1000) 12.75 μs 30.0 ns 10.51 μs +21.3% ⚠️
CuckooFilterBenchmark.CuckooFilter_Remove(ItemCount: 1000) 12.78 μs 37.5 ns 11.06 μs +15.6% ⚠️
SwissSetBenchmark.SwissSet_Remove(ItemCount: 100000) 1.06 ms 11.62 μs 851.61 μs +24.8% ⚠️
CuckooFilterBenchmark.HashSet_Remove(ItemCount: 100000) 3.77 ms 56.43 μs 2.94 ms +28.0% ⚠️
CuckooFilterBenchmark.CuckooFilter_Remove(ItemCount: 100000) 3.94 ms 6.45 μs 3.46 ms +13.9% ⚠️
RobinHoodSetBenchmark.RobinHoodSet_Add(ItemCount: 1000) 18.10 μs 112.4 ns 13.27 μs +36.4% ⚠️
FenwickTreeBenchmark.Array_RangeSum(ItemCount: 100000) 201.75 ms 20.75 ms 158.83 ms +27.0% ⚠️
HashCachingSetBenchmark.HashSet_Add(ItemCount: 1000) 9.83 μs 60.5 ns 11.81 μs -16.8% ✅
IntSetBenchmark.HashSet_Add(ItemCount: 1000) 9.81 μs 53.9 ns 13.55 μs -27.7% ✅
HashCachingSetBenchmark.HashCachingSet_Add(ItemCount: 1000) 8.50 μs 46.3 ns 10.59 μs -19.7% ✅
IntSetBenchmark.IntSet_Add(ItemCount: 1000) 7.14 μs 131.9 ns 8.95 μs -20.2% ✅
HashCachingSetBenchmark.HashSet_Add(ItemCount: 100000) 4.10 ms 37.32 μs 4.63 ms -11.5% ✅
IntSetBenchmark.HashSet_Add(ItemCount: 100000) 4.29 ms 110.57 μs 5.12 ms -16.2% ✅
HashCachingSetBenchmark.HashCachingSet_Add(ItemCount: 100000) 4.39 ms 97.23 μs 5.18 ms -15.3% ✅
IntSetBenchmark.IntSet_Add(ItemCount: 100000) 2.70 ms 10.86 μs 3.19 ms -15.2% ✅
DisjointSetBenchmark.Dictionary_Components(ItemCount: 1000) 13.87 μs 337.7 ns 18.33 μs -24.4% ✅
DisjointSetBenchmark.DisjointSet_Components(ItemCount: 1000) 12.25 μs 110.6 ns 16.35 μs -25.1% ✅
DisjointSetBenchmark.Dictionary_Components(ItemCount: 100000) 3.59 ms 80.17 μs 4.27 ms -15.9% ✅
DisjointSetBenchmark.DisjointSet_Components(ItemCount: 100000) 2.60 ms 42.62 μs 3.34 ms -22.1% ✅
DisjointSetBenchmark.Dictionary_Connected(ItemCount: 1000) 7.81 μs 409.3 ns 9.46 μs -17.5% ✅
DisjointSetBenchmark.DisjointSet_Connected(ItemCount: 1000) 10.07 μs 5.5 ns 12.10 μs -16.8% ✅
DisjointSetBenchmark.Dictionary_Connected(ItemCount: 100000) 121.01 μs 193.9 ns 252.13 μs -52.0% ✅
DisjointSetBenchmark.DisjointSet_Connected(ItemCount: 100000) 219.96 μs 627.6 ns 344.42 μs -36.1% ✅
HashCachingSetBenchmark.HashSet_Contains(ItemCount: 1000) 3.67 μs 3.0 ns 4.72 μs -22.3% ✅
IntSetBenchmark.HashSet_Contains(ItemCount: 1000) 3.65 μs 3.6 ns 4.74 μs -23.0% ✅
HashCachingSetBenchmark.HashCachingSet_Contains(ItemCount: 1000) 2.06 μs 8.2 ns 2.42 μs -14.8% ✅
IntSetBenchmark.IntSet_Contains(ItemCount: 1000) 1.49 μs 16.5 ns 1.81 μs -17.8% ✅
HashCachingSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.18 ms 1.68 μs 1.56 ms -24.7% ✅
IntSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.23 ms 7.51 μs 1.55 ms -20.5% ✅
HashCachingSetBenchmark.HashCachingSet_Contains(ItemCount: 100000) 581.53 μs 5.74 μs 740.91 μs -21.5% ✅
IntSetBenchmark.IntSet_Contains(ItemCount: 100000) 374.54 μs 5.78 μs 574.62 μs -34.8% ✅
HashCachingSetBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 3.54 μs 8.1 ns 4.56 μs -22.3% ✅
HashCachingSetBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 1.54 ms 3.59 μs 1.93 ms -20.0% ✅
HashCachingSetBenchmark.HashCachingSet_ContainsMissing(ItemCount: 100000) 977.32 μs 1.46 μs 1.16 ms -15.6% ✅
CelerityDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 10.30 μs 96.3 ns 13.76 μs -25.1% ✅
IntDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 10.27 μs 59.8 ns 16.47 μs -37.6% ✅
CelerityDictionaryBenchmark.CelerityDictionary_Insert(ItemCount: 1000) 6.73 μs 58.0 ns 9.19 μs -26.8% ✅
IntDictionaryBenchmark.IntDictionary_Insert(ItemCount: 1000) 6.60 μs 88.6 ns 12.48 μs -47.1% ✅
CelerityDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 3.43 ms 44.88 μs 4.40 ms -22.1% ✅
IntDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 3.36 ms 40.54 μs 4.34 ms -22.7% ✅
CelerityDictionaryBenchmark.CelerityDictionary_Insert(ItemCount: 100000) 4.12 ms 44.70 μs 5.22 ms -21.1% ✅
IntDictionaryBenchmark.IntDictionary_Insert(ItemCount: 100000) 4.17 ms 34.93 μs 5.06 ms -17.5% ✅
CelerityDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 3.81 μs 59.7 ns 4.72 μs -19.2% ✅
IntDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 3.62 μs 48.1 ns 4.77 μs -24.2% ✅
CelerityDictionaryBenchmark.CelerityDictionary_Lookup(ItemCount: 1000) 1.68 μs 12.4 ns 2.34 μs -28.0% ✅
IntDictionaryBenchmark.IntDictionary_Lookup(ItemCount: 1000) 1.62 μs 7.5 ns 2.14 μs -24.5% ✅
CelerityDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.20 ms 37.78 μs 1.54 ms -22.3% ✅
IntDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.20 ms 8.51 μs 1.61 ms -25.5% ✅
CelerityDictionaryBenchmark.CelerityDictionary_Lookup(ItemCount: 100000) 546.41 μs 15.45 μs 695.04 μs -21.4% ✅
IntDictionaryBenchmark.IntDictionary_Lookup(ItemCount: 100000) 597.52 μs 4.75 μs 678.58 μs -11.9% ✅
CelerityDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 62.54 μs 6.09 μs 76.12 μs -17.8% ✅
IntDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 58.73 μs 4.90 μs 82.17 μs -28.5% ✅
IntSetBenchmark.HashSet_Remove(ItemCount: 1000) 22.04 μs 2.11 μs 26.45 μs -16.7% ✅
CelerityDictionaryBenchmark.CelerityDictionary_Remove(ItemCount: 1000) 115.24 μs 5.83 μs 146.89 μs -21.6% ✅
IntDictionaryBenchmark.IntDictionary_Remove(ItemCount: 1000) 70.26 μs 6.25 μs 92.98 μs -24.4% ✅
IntSetBenchmark.IntSet_Remove(ItemCount: 1000) 65.45 μs 6.54 μs 83.80 μs -21.9% ✅
HashCachingSetBenchmark.HashSet_Remove(ItemCount: 1000) 21.55 μs 784.2 ns 30.12 μs -28.5% ✅
HashCachingSetBenchmark.HashCachingSet_Remove(ItemCount: 1000) 85.57 μs 4.42 μs 113.10 μs -24.3% ✅
CelerityDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 1.55 ms 15.30 μs 2.05 ms -24.3% ✅
IntDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 1.54 ms 13.46 μs 2.07 ms -25.7% ✅
IntSetBenchmark.HashSet_Remove(ItemCount: 100000) 1.31 ms 16.58 μs 1.71 ms -23.7% ✅
CelerityDictionaryBenchmark.CelerityDictionary_Remove(ItemCount: 100000) 1.31 ms 17.46 μs 1.89 ms -30.7% ✅
IntSetBenchmark.IntSet_Remove(ItemCount: 100000) 1.14 ms 21.33 μs 1.33 ms -14.2% ✅
HashCachingSetBenchmark.HashSet_Remove(ItemCount: 100000) 1.32 ms 13.09 μs 1.70 ms -22.5% ✅
HashCachingSetBenchmark.HashCachingSet_Remove(ItemCount: 100000) 1.31 ms 8.39 μs 1.54 ms -14.8% ✅
DisjointSetBenchmark.Dictionary_Union(ItemCount: 1000) 72.81 μs 1.00 μs 95.67 μs -23.9% ✅
DisjointSetBenchmark.DisjointSet_Union(ItemCount: 1000) 21.51 μs 116.7 ns 26.99 μs -20.3% ✅
DisjointSetBenchmark.Dictionary_Union(ItemCount: 100000) 36.17 ms 1.28 ms 43.38 ms -16.6% ✅
DisjointSetBenchmark.DisjointSet_Union(ItemCount: 100000) 6.03 ms 45.63 μs 8.15 ms -26.0% ✅
SparseSetBenchmark.HashSet_Add(ItemCount: 1000) 8.01 μs 179.6 ns 7.09 μs +13.0% ⚠️
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Insert(ItemCount: 100000) 7.75 ms 557.87 μs 9.28 ms -16.5% ✅
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Lookup(ItemCount: 1000) 2.63 μs 11.3 ns 2.89 μs -9.2% ✅
TrieBenchmark.Trie_PrefixMatch(ItemCount: 100000) 9.76 ms 457.82 μs 6.99 ms +39.7% ⚠️
LongDictionaryBenchmark.LongDictionary_Remove(ItemCount: 100000) 2.06 ms 415.62 μs 7.06 ms -70.8% ✅
SparseSetBenchmark.HashSet_Remove(ItemCount: 100000) 1.50 ms 21.07 μs 1.76 ms -14.9% ✅
Collections (460)
Benchmark This PR StdDev main Δ
HyperLogLogBenchmark.HashSet_Add(ItemCount: 1000) 12.99 μs 97.9 ns 9.79 μs +32.8% ⚠️
PooledCeleritySetBenchmark.HashSet_Add(ItemCount: 1000) 12.52 μs 246.5 ns 9.83 μs +27.3% ⚠️
HyperLogLogBenchmark.HyperLogLog_Add(ItemCount: 1000) 27.40 μs 69.8 ns 79.09 μs -65.4% ✅
PooledCeleritySetBenchmark.PooledCeleritySet_Add(ItemCount: 1000) 8.95 μs 161.8 ns 7.46 μs +20.0% ⚠️
HyperLogLogBenchmark.HashSet_Add(ItemCount: 100000) 4.88 ms 43.97 μs 4.09 ms +19.3% ⚠️
PooledCeleritySetBenchmark.HashSet_Add(ItemCount: 100000) 4.89 ms 199.26 μs 4.08 ms +19.9% ⚠️
HyperLogLogBenchmark.HyperLogLog_Add(ItemCount: 100000) 575.93 μs 1.07 μs 475.82 μs +21.0% ⚠️
PooledCeleritySetBenchmark.PooledCeleritySet_Add(ItemCount: 100000) 2.85 ms 5.42 μs 2.46 ms +15.5% ⚠️
PooledCeleritySetBenchmark.HashSet_Contains(ItemCount: 1000) 4.75 μs 14.9 ns 3.65 μs +30.1% ⚠️
PooledCeleritySetBenchmark.PooledCeleritySet_Contains(ItemCount: 1000) 1.93 μs 20.3 ns 1.51 μs +27.6% ⚠️
PooledCeleritySetBenchmark.HashSet_Contains(ItemCount: 100000) 1.53 ms 50.00 μs 1.18 ms +30.5% ⚠️
PooledCeleritySetBenchmark.PooledCeleritySet_Contains(ItemCount: 100000) 572.96 μs 3.07 μs 390.12 μs +46.9% ⚠️
DequeBenchmark.LinkedList_Enumerate(ItemCount: 1000) 1.37 μs 0.5 ns 1.28 μs +6.8%
DequeBenchmark.Deque_Enumerate(ItemCount: 1000) 941.4 ns 0.7 ns 824.5 ns +14.2% ⚠️
DequeBenchmark.LinkedList_Enumerate(ItemCount: 100000) 135.15 μs 202.5 ns 118.03 μs +14.5% ⚠️
DequeBenchmark.Deque_Enumerate(ItemCount: 100000) 93.84 μs 78.7 ns 81.95 μs +14.5% ⚠️
HyperLogLogBenchmark.HashSet_Estimate(ItemCount: 1000) 0.0 ns 0.0 ns 0.0 ns -61.0%
HyperLogLogBenchmark.HyperLogLog_Estimate(ItemCount: 1000) 23.44 μs 8.5 ns 75.86 μs -69.1% ✅
HyperLogLogBenchmark.HashSet_Estimate(ItemCount: 100000) 0.0 ns 0.0 ns 0.0 ns +1034.1%
HyperLogLogBenchmark.HyperLogLog_Estimate(ItemCount: 100000) 22.98 μs 10.6 ns 75.87 μs -69.7% ✅
PooledCelerityDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 15.02 μs 901.0 ns 10.23 μs +46.8% ⚠️
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Insert(ItemCount: 1000) 8.64 μs 91.9 ns 6.47 μs +33.6% ⚠️
PooledCelerityDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 4.90 ms 70.65 μs 4.26 ms +15.0% ⚠️
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Insert(ItemCount: 100000) 2.99 ms 12.40 μs 2.54 ms +17.5% ⚠️
PooledCelerityDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.72 μs 13.6 ns 3.61 μs +30.6% ⚠️
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Lookup(ItemCount: 1000) 2.31 μs 11.7 ns 1.86 μs +24.3% ⚠️
PooledCelerityDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.60 ms 6.22 μs 1.24 ms +29.0% ⚠️
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Lookup(ItemCount: 100000) 694.42 μs 7.28 μs 608.22 μs +14.2% ⚠️
DequeBenchmark.LinkedList_PushFront(ItemCount: 1000) 39.00 μs 5.57 μs 30.95 μs +26.0%
DequeBenchmark.Deque_PushFront(ItemCount: 1000) 19.47 μs 1.79 μs 14.91 μs +30.7% ⚠️
DequeBenchmark.LinkedList_PushFront(ItemCount: 100000) 1.83 ms 41.39 μs 1.39 ms +31.9% ⚠️
DequeBenchmark.Deque_PushFront(ItemCount: 100000) 654.10 μs 34.72 μs 540.60 μs +21.0% ⚠️
DequeBenchmark.LinkedList_Queue(ItemCount: 1000) 55.50 μs 1.91 μs 39.62 μs +40.1% ⚠️
DequeBenchmark.Deque_Queue(ItemCount: 1000) 38.98 μs 2.00 μs 23.88 μs +63.2% ⚠️
DequeBenchmark.LinkedList_Queue(ItemCount: 100000) 4.21 ms 192.55 μs 3.73 ms +12.9% ⚠️
DequeBenchmark.Deque_Queue(ItemCount: 100000) 422.81 μs 19.40 μs 350.94 μs +20.5% ⚠️
PooledCelerityDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 85.79 μs 9.48 μs 59.20 μs +44.9% ⚠️
PooledCeleritySetBenchmark.HashSet_Remove(ItemCount: 1000) 31.95 μs 4.32 μs 22.49 μs +42.1% ⚠️
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Remove(ItemCount: 1000) 148.74 μs 10.91 μs 117.22 μs +26.9% ⚠️
PooledCeleritySetBenchmark.PooledCeleritySet_Remove(ItemCount: 1000) 151.41 μs 5.94 μs 110.33 μs +37.2% ⚠️
PooledCelerityDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.10 ms 48.07 μs 1.54 ms +36.0% ⚠️
PooledCeleritySetBenchmark.HashSet_Remove(ItemCount: 100000) 1.71 ms 16.84 μs 1.30 ms +31.2% ⚠️
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Remove(ItemCount: 100000) 1.63 ms 65.42 μs 2.66 ms -38.6%
PooledCeleritySetBenchmark.PooledCeleritySet_Remove(ItemCount: 100000) 1.29 ms 69.21 μs 1.06 ms +21.9% ⚠️
SmallSetBenchmark.HashSet_Add(ItemCount: 8) 182.5 ns 11.6 ns 177.9 ns +2.5%
SmallSetBenchmark.SmallSet_Add(ItemCount: 8) 58.2 ns 0.3 ns 58.5 ns -0.7%
SmallSetBenchmark.HashSet_Add(ItemCount: 64) 789.1 ns 20.8 ns 802.9 ns -1.7%
SmallSetBenchmark.SmallSet_Add(ItemCount: 64) 1.62 μs 10.9 ns 1.93 μs -16.3%
BTreeDictionaryBenchmark.SortedDictionary_Add(ItemCount: 1000) 56.87 μs 636.8 ns n/a 🆕 new
CountMinSketchBenchmark.Dictionary_Add(ItemCount: 1000) 10.38 μs 25.3 ns 10.56 μs -1.8%
BTreeDictionaryBenchmark.BTreeDictionary_Add(ItemCount: 1000) 54.38 μs 444.9 ns n/a 🆕 new
CountMinSketchBenchmark.CountMinSketch_Add(ItemCount: 1000) 12.82 μs 323.9 ns 10.24 μs +25.3% ⚠️
BTreeDictionaryBenchmark.SortedDictionary_Add(ItemCount: 100000) 26.12 ms 548.67 μs n/a 🆕 new
CountMinSketchBenchmark.Dictionary_Add(ItemCount: 100000) 1.47 ms 16.27 μs 1.42 ms +3.4%
BTreeDictionaryBenchmark.BTreeDictionary_Add(ItemCount: 100000) 17.34 ms 102.24 μs n/a 🆕 new
CountMinSketchBenchmark.CountMinSketch_Add(ItemCount: 100000) 1.15 ms 16.45 μs 927.96 μs +23.4% ⚠️
FrozenCelerityDictionaryBenchmark.FrozenDictionary_Build(ItemCount: 1000) 167.78 μs 670.9 ns 167.51 μs +0.2%
FrozenCelerityDictionaryBenchmark.FrozenCelerityDictionary_Build(ItemCount: 1000) 4.09 ms 199.42 μs 3.76 ms +8.8%
FrozenCelerityDictionaryBenchmark.FrozenDictionary_Build(ItemCount: 100000) 30.14 ms 493.31 μs 30.31 ms -0.6%
FrozenCelerityDictionaryBenchmark.FrozenCelerityDictionary_Build(ItemCount: 100000) 1.71 s 103.45 ms 1.93 s -11.1%
SmallSetBenchmark.HashSet_Contains(ItemCount: 8) 40.4 ns 3.4 ns 37.4 ns +8.2%
SmallSetBenchmark.SmallSet_Contains(ItemCount: 8) 19.7 ns 0.2 ns 19.8 ns -0.4%
SmallSetBenchmark.HashSet_Contains(ItemCount: 64) 302.2 ns 0.3 ns 302.8 ns -0.2%
SmallSetBenchmark.SmallSet_Contains(ItemCount: 64) 921.5 ns 11.9 ns 927.9 ns -0.7%
CountMinSketchBenchmark.Dictionary_Estimate(ItemCount: 1000) 4.65 μs 4.3 ns 4.37 μs +6.4%
CountMinSketchBenchmark.CountMinSketch_Estimate(ItemCount: 1000) 8.45 μs 23.7 ns 10.07 μs -16.0% ✅
CountMinSketchBenchmark.Dictionary_Estimate(ItemCount: 100000) 530.90 μs 486.6 ns 492.19 μs +7.9%
CountMinSketchBenchmark.CountMinSketch_Estimate(ItemCount: 100000) 2.34 ms 1.92 μs 2.01 ms +16.3% ⚠️
CelerityMultiMapBenchmark.Dictionary_Insert(ItemCount: 1000) 28.80 μs 580.9 ns 29.53 μs -2.5%
SwissDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 15.47 μs 223.5 ns 12.69 μs +21.9% ⚠️
CelerityMultiMapBenchmark.CelerityMultiMap_Insert(ItemCount: 1000) 40.61 μs 989.7 ns 41.49 μs -2.1%
SwissDictionaryBenchmark.SwissDictionary_Insert(ItemCount: 1000) 30.68 μs 68.9 ns 28.47 μs +7.8%
CelerityMultiMapBenchmark.Dictionary_Insert(ItemCount: 100000) 14.38 ms 836.46 μs 14.41 ms -0.2%
SwissDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 5.04 ms 162.61 μs 4.68 ms +7.8%
CelerityMultiMapBenchmark.CelerityMultiMap_Insert(ItemCount: 100000) 19.59 ms 349.67 μs 18.77 ms +4.4%
SwissDictionaryBenchmark.SwissDictionary_Insert(ItemCount: 100000) 3.88 ms 33.08 μs 3.92 ms -1.0%
BTreeDictionaryBenchmark.SortedDictionary_Lookup(ItemCount: 1000) 24.74 μs 135.2 ns n/a 🆕 new
CelerityMultiMapBenchmark.Dictionary_Lookup(ItemCount: 1000) 5.40 μs 329.5 ns 5.12 μs +5.6%
FrozenCelerityDictionaryBenchmark.FrozenDictionary_Lookup(ItemCount: 1000) 8.01 μs 345.4 ns 7.61 μs +5.2%
SwissDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.74 μs 138.4 ns 4.77 μs -0.6%
BTreeDictionaryBenchmark.BTreeDictionary_Lookup(ItemCount: 1000) 20.38 μs 238.9 ns n/a 🆕 new
CelerityMultiMapBenchmark.CelerityMultiMap_Lookup(ItemCount: 1000) 2.45 μs 2.7 ns 2.45 μs +0.2%
FrozenCelerityDictionaryBenchmark.FrozenCelerityDictionary_Lookup(ItemCount: 1000) 80.76 μs 140.3 ns 80.73 μs +0.0%
SwissDictionaryBenchmark.SwissDictionary_Lookup(ItemCount: 1000) 2.91 μs 3.3 ns 2.99 μs -2.5%
BTreeDictionaryBenchmark.SortedDictionary_Lookup(ItemCount: 100000) 19.09 ms 1.66 ms n/a 🆕 new
CelerityMultiMapBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.79 ms 11.34 μs 1.80 ms -0.7%
FrozenCelerityDictionaryBenchmark.FrozenDictionary_Lookup(ItemCount: 100000) 1.85 ms 40.82 μs 2.57 ms -27.8% ✅
SwissDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.60 ms 12.50 μs 1.59 ms +0.3%
BTreeDictionaryBenchmark.BTreeDictionary_Lookup(ItemCount: 100000) 14.21 ms 25.01 μs n/a 🆕 new
CelerityMultiMapBenchmark.CelerityMultiMap_Lookup(ItemCount: 100000) 746.77 μs 19.08 μs 736.91 μs +1.3%
FrozenCelerityDictionaryBenchmark.FrozenCelerityDictionary_Lookup(ItemCount: 100000) 8.37 ms 54.09 μs 15.03 ms -44.3% ✅
SwissDictionaryBenchmark.SwissDictionary_Lookup(ItemCount: 100000) 681.08 μs 16.94 μs 810.39 μs -16.0% ✅
BTreeDictionaryBenchmark.SortedDictionary_Mixed(ItemCount: 1000) 96.29 μs 3.62 μs n/a 🆕 new
BTreeDictionaryBenchmark.BTreeDictionary_Mixed(ItemCount: 1000) 70.83 μs 639.6 ns n/a 🆕 new
BTreeDictionaryBenchmark.SortedDictionary_Mixed(ItemCount: 100000) 51.03 ms 342.13 μs n/a 🆕 new
BTreeDictionaryBenchmark.BTreeDictionary_Mixed(ItemCount: 100000) 27.91 ms 120.34 μs n/a 🆕 new
BTreeDictionaryBenchmark.SortedDictionary_RangeScan(ItemCount: 1000) 4.59 μs 26.5 ns n/a 🆕 new
BTreeDictionaryBenchmark.BTreeDictionary_RangeScan(ItemCount: 1000) 81.8 ns 1.0 ns n/a 🆕 new
BTreeDictionaryBenchmark.SortedDictionary_RangeScan(ItemCount: 100000) 1.16 ms 54.79 μs n/a 🆕 new
BTreeDictionaryBenchmark.BTreeDictionary_RangeScan(ItemCount: 100000) 5.80 μs 8.4 ns n/a 🆕 new
SmallSetBenchmark.HashSet_Remove(ItemCount: 8) 441.2 ns 52.9 ns 398.6 ns +10.7%
SmallSetBenchmark.SmallSet_Remove(ItemCount: 8) 1.31 μs 124.1 ns 1.08 μs +21.8%
SmallSetBenchmark.HashSet_Remove(ItemCount: 64) 1.37 μs 185.1 ns 1.36 μs +0.9%
SmallSetBenchmark.SmallSet_Remove(ItemCount: 64) 22.88 μs 3.62 μs 25.00 μs -8.5%
BTreeDictionaryBenchmark.SortedDictionary_Remove(ItemCount: 1000) 682.45 μs 12.27 μs n/a 🆕 new
CelerityMultiMapBenchmark.Dictionary_Remove(ItemCount: 1000) 29.45 μs 2.21 μs 26.95 μs +9.3%
SwissDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 79.98 μs 5.36 μs 81.57 μs -1.9%
BTreeDictionaryBenchmark.BTreeDictionary_Remove(ItemCount: 1000) 284.28 μs 10.84 μs n/a 🆕 new
CelerityMultiMapBenchmark.CelerityMultiMap_Remove(ItemCount: 1000) 153.80 μs 5.27 μs 149.17 μs +3.1%
SwissDictionaryBenchmark.SwissDictionary_Remove(ItemCount: 1000) 76.20 μs 5.51 μs 80.61 μs -5.5%
BTreeDictionaryBenchmark.SortedDictionary_Remove(ItemCount: 100000) 29.57 ms 1.25 ms n/a 🆕 new
CelerityMultiMapBenchmark.Dictionary_Remove(ItemCount: 100000) 3.55 ms 305.78 μs 3.17 ms +12.0%
SwissDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.00 ms 22.34 μs 2.02 ms -1.2%
BTreeDictionaryBenchmark.BTreeDictionary_Remove(ItemCount: 100000) 19.50 ms 117.56 μs n/a 🆕 new
CelerityMultiMapBenchmark.CelerityMultiMap_Remove(ItemCount: 100000) 2.90 ms 221.77 μs 2.88 ms +0.6%
SwissDictionaryBenchmark.SwissDictionary_Remove(ItemCount: 100000) 1.53 ms 355.44 μs 1.64 ms -6.8%
EnumMapBenchmark.Dictionary_Add 610.8 ns 1.3 ns 616.1 ns -0.9%
EnumMapBenchmark.EnumMap_Add 109.7 ns 0.5 ns 112.8 ns -2.7%
BTreeSetBenchmark.SortedSet_Add(ItemCount: 1000) 45.29 μs 692.2 ns n/a 🆕 new
BloomFilterBenchmark.HashSet_Add(ItemCount: 1000) 13.19 μs 149.8 ns 12.51 μs +5.4%
TopKSketchBenchmark.Dictionary_Add(ItemCount: 1000) 13.14 μs 62.5 ns 14.63 μs -10.2% ✅
BTreeSetBenchmark.BTreeSet_Add(ItemCount: 1000) 41.52 μs 705.8 ns n/a 🆕 new
BloomFilterBenchmark.BloomFilter_Add(ItemCount: 1000) 16.38 μs 11.2 ns 16.38 μs -0.0%
TopKSketchBenchmark.TopKSketch_Add(ItemCount: 1000) 74.55 μs 54.6 ns 74.81 μs -0.3%
BTreeSetBenchmark.SortedSet_Add(ItemCount: 100000) 22.47 ms 122.82 μs n/a 🆕 new
BloomFilterBenchmark.HashSet_Add(ItemCount: 100000) 4.86 ms 148.54 μs 4.75 ms +2.1%
TopKSketchBenchmark.Dictionary_Add(ItemCount: 100000) 3.26 ms 48.92 μs 3.54 ms -7.9%
BTreeSetBenchmark.BTreeSet_Add(ItemCount: 100000) 15.63 ms 127.98 μs n/a 🆕 new
BloomFilterBenchmark.BloomFilter_Add(ItemCount: 100000) 1.27 ms 2.09 μs 1.26 ms +0.1%
TopKSketchBenchmark.TopKSketch_Add(ItemCount: 100000) 14.54 ms 81.06 μs 14.43 ms +0.7%
BTreeSetBenchmark.SortedSet_Contains(ItemCount: 1000) 19.09 μs 250.2 ns n/a 🆕 new
BloomFilterBenchmark.HashSet_Contains(ItemCount: 1000) 4.74 μs 5.5 ns 4.74 μs -0.0%
BTreeSetBenchmark.BTreeSet_Contains(ItemCount: 1000) 16.55 μs 20.3 ns n/a 🆕 new
BloomFilterBenchmark.BloomFilter_Contains(ItemCount: 1000) 14.17 μs 3.7 ns 14.18 μs -0.0%
BTreeSetBenchmark.SortedSet_Contains(ItemCount: 100000) 17.23 ms 18.32 μs n/a 🆕 new
BloomFilterBenchmark.HashSet_Contains(ItemCount: 100000) 1.51 ms 1.66 μs 1.54 ms -1.8%
BTreeSetBenchmark.BTreeSet_Contains(ItemCount: 100000) 14.12 ms 11.31 μs n/a 🆕 new
BloomFilterBenchmark.BloomFilter_Contains(ItemCount: 100000) 982.38 μs 905.1 ns 982.46 μs -0.0%
BloomFilterBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 4.57 μs 3.4 ns 4.57 μs -0.1%
BloomFilterBenchmark.BloomFilter_ContainsMissing(ItemCount: 1000) 3.98 μs 1.9 ns 3.98 μs +0.0%
BloomFilterBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 1.99 ms 6.12 μs 1.99 ms -0.3%
BloomFilterBenchmark.BloomFilter_ContainsMissing(ItemCount: 100000) 1.67 ms 1.33 μs 1.67 ms +0.0%
CelerityMultiSetBenchmark.Dictionary_Count(ItemCount: 1000) 9.88 μs 28.4 ns 9.78 μs +1.1%
CelerityMultiSetBenchmark.CelerityMultiSet_Count(ItemCount: 1000) 5.40 μs 62.9 ns 5.29 μs +2.2%
CelerityMultiSetBenchmark.Dictionary_Count(ItemCount: 100000) 1.39 ms 34.09 μs 1.34 ms +3.3%
CelerityMultiSetBenchmark.CelerityMultiSet_Count(ItemCount: 100000) 627.11 μs 50.64 μs 645.73 μs -2.9%
EnumMapBenchmark.Dictionary_Enumerate 43.1 ns 0.1 ns 43.1 ns -0.1%
EnumMapBenchmark.EnumMap_Enumerate 38.0 ns 0.2 ns 38.0 ns -0.0%
HashCachingDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 13.20 μs 46.7 ns 16.04 μs -17.7% ✅
HashCachingDictionaryBenchmark.HashCachingDictionary_Insert(ItemCount: 1000) 10.12 μs 78.5 ns 12.67 μs -20.2% ✅
HashCachingDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 5.06 ms 78.79 μs 4.88 ms +3.8%
HashCachingDictionaryBenchmark.HashCachingDictionary_Insert(ItemCount: 100000) 7.13 ms 363.36 μs 6.83 ms +4.5%
EnumMapBenchmark.Dictionary_Lookup 135.7 ns 0.1 ns 150.7 ns -10.0% ✅
EnumMapBenchmark.EnumMap_Lookup 69.8 ns 0.1 ns 69.7 ns +0.1%
CelerityMultiSetBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.68 μs 15.8 ns 4.62 μs +1.1%
HashCachingDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.74 μs 126.6 ns 4.68 μs +1.1%
CelerityMultiSetBenchmark.CelerityMultiSet_Lookup(ItemCount: 1000) 1.90 μs 4.5 ns 1.90 μs -0.1%
HashCachingDictionaryBenchmark.HashCachingDictionary_Lookup(ItemCount: 1000) 2.87 μs 28.1 ns 2.73 μs +5.3%
CelerityMultiSetBenchmark.Dictionary_Lookup(ItemCount: 100000) 652.46 μs 106.15 μs 561.69 μs +16.2%
HashCachingDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.61 ms 3.76 μs 1.58 ms +1.8%
CelerityMultiSetBenchmark.CelerityMultiSet_Lookup(ItemCount: 100000) 211.62 μs 195.0 ns 211.77 μs -0.1%
HashCachingDictionaryBenchmark.HashCachingDictionary_Lookup(ItemCount: 100000) 848.20 μs 12.32 μs 823.92 μs +2.9%
BTreeSetBenchmark.SortedSet_Mixed(ItemCount: 1000) 59.48 μs 2.02 μs n/a 🆕 new
BTreeSetBenchmark.BTreeSet_Mixed(ItemCount: 1000) 56.14 μs 1.92 μs n/a 🆕 new
BTreeSetBenchmark.SortedSet_Mixed(ItemCount: 100000) 33.78 ms 135.90 μs n/a 🆕 new
BTreeSetBenchmark.BTreeSet_Mixed(ItemCount: 100000) 26.42 ms 373.53 μs n/a 🆕 new
BTreeSetBenchmark.SortedSet_RangeScan(ItemCount: 1000) 177.1 ns 3.1 ns n/a 🆕 new
BTreeSetBenchmark.BTreeSet_RangeScan(ItemCount: 1000) 80.2 ns 1.4 ns n/a 🆕 new
BTreeSetBenchmark.SortedSet_RangeScan(ItemCount: 100000) 9.37 μs 333.7 ns n/a 🆕 new
BTreeSetBenchmark.BTreeSet_RangeScan(ItemCount: 100000) 4.95 μs 16.6 ns n/a 🆕 new
EnumMapBenchmark.Dictionary_Remove 3.24 μs 309.9 ns 3.35 μs -3.4%
EnumMapBenchmark.EnumMap_Remove 1.47 μs 358.4 ns 1.19 μs +23.5%
BTreeSetBenchmark.SortedSet_Remove(ItemCount: 1000) 602.59 μs 11.47 μs n/a 🆕 new
CelerityMultiSetBenchmark.Dictionary_Remove(ItemCount: 1000) 47.44 μs 3.70 μs 51.26 μs -7.4%
HashCachingDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 82.37 μs 7.16 μs 92.30 μs -10.8%
BTreeSetBenchmark.BTreeSet_Remove(ItemCount: 1000) 250.87 μs 12.03 μs n/a 🆕 new
CelerityMultiSetBenchmark.CelerityMultiSet_Remove(ItemCount: 1000) 102.24 μs 4.90 μs 100.18 μs +2.1%
HashCachingDictionaryBenchmark.HashCachingDictionary_Remove(ItemCount: 1000) 110.10 μs 7.99 μs 121.62 μs -9.5%
BTreeSetBenchmark.SortedSet_Remove(ItemCount: 100000) 26.61 ms 185.68 μs n/a 🆕 new
CelerityMultiSetBenchmark.Dictionary_Remove(ItemCount: 100000) 566.73 μs 13.20 μs 565.06 μs +0.3%
HashCachingDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.04 ms 52.32 μs 2.12 ms -4.1%
BTreeSetBenchmark.BTreeSet_Remove(ItemCount: 100000) 16.62 ms 167.95 μs n/a 🆕 new
CelerityMultiSetBenchmark.CelerityMultiSet_Remove(ItemCount: 100000) 1.60 ms 13.54 μs 1.61 ms -0.5%
HashCachingDictionaryBenchmark.HashCachingDictionary_Remove(ItemCount: 100000) 2.49 ms 448.08 μs 2.02 ms +23.1%
TopKSketchBenchmark.Dictionary_TopK(ItemCount: 1000) 32.4 ns 0.1 ns 34.5 ns -6.0%
TopKSketchBenchmark.TopKSketch_TopK(ItemCount: 1000) 1.21 μs 5.4 ns 1.31 μs -7.6%
TopKSketchBenchmark.Dictionary_TopK(ItemCount: 100000) 33.3 ns 0.6 ns 34.4 ns -3.2%
TopKSketchBenchmark.TopKSketch_TopK(ItemCount: 100000) 1.13 μs 21.2 ns 1.19 μs -4.8%
CuckooFilterBenchmark.HashSet_Add(ItemCount: 1000) 12.03 μs 232.8 ns 9.91 μs +21.4% ⚠️
SwissSetBenchmark.HashSet_Add(ItemCount: 1000) 12.15 μs 65.9 ns 13.48 μs -9.9% ✅
CuckooFilterBenchmark.CuckooFilter_Add(ItemCount: 1000) 7.08 μs 13.4 ns 6.18 μs +14.7% ⚠️
SwissSetBenchmark.SwissSet_Add(ItemCount: 1000) 26.17 μs 97.6 ns 26.06 μs +0.4%
CuckooFilterBenchmark.HashSet_Add(ItemCount: 100000) 4.68 ms 84.03 μs 3.83 ms +22.4% ⚠️
SwissSetBenchmark.HashSet_Add(ItemCount: 100000) 4.70 ms 34.07 μs 5.04 ms -6.6%
CuckooFilterBenchmark.CuckooFilter_Add(ItemCount: 100000) 2.07 ms 23.85 μs 1.81 ms +14.6% ⚠️
SwissSetBenchmark.SwissSet_Add(ItemCount: 100000) 4.53 ms 30.52 μs 4.51 ms +0.4%
FrozenCeleritySetBenchmark.FrozenSet_Build(ItemCount: 1000) 164.55 μs 812.9 ns 162.92 μs +1.0%
XorFilterBenchmark.HashSet_Build(ItemCount: 1000) 7.96 μs 124.7 ns 7.75 μs +2.6%
FrozenCeleritySetBenchmark.FrozenCeleritySet_Build(ItemCount: 1000) 2.49 ms 82.22 μs 2.32 ms +7.4%
XorFilterBenchmark.XorFilter_Build(ItemCount: 1000) 37.62 μs 313.2 ns 38.21 μs -1.5%
FrozenCeleritySetBenchmark.FrozenSet_Build(ItemCount: 100000) 29.30 ms 619.35 μs 28.83 ms +1.6%
XorFilterBenchmark.HashSet_Build(ItemCount: 100000) 2.05 ms 21.82 μs 2.05 ms +0.0%
FrozenCeleritySetBenchmark.FrozenCeleritySet_Build(ItemCount: 100000) 1.40 s 52.24 ms 1.40 s -0.4%
XorFilterBenchmark.XorFilter_Build(ItemCount: 100000) 12.81 ms 162.35 μs 12.79 ms +0.2%
CuckooFilterBenchmark.HashSet_Contains(ItemCount: 1000) 4.72 μs 7.4 ns 3.67 μs +28.7% ⚠️
FrozenCeleritySetBenchmark.FrozenSet_Contains(ItemCount: 1000) 6.88 μs 8.5 ns 6.87 μs +0.1%
SwissSetBenchmark.HashSet_Contains(ItemCount: 1000) 4.72 μs 9.1 ns 4.74 μs -0.4%
XorFilterBenchmark.HashSet_Contains(ItemCount: 1000) 4.72 μs 7.5 ns 4.73 μs -0.1%
CuckooFilterBenchmark.CuckooFilter_Contains(ItemCount: 1000) 4.91 μs 3.8 ns 4.31 μs +14.0% ⚠️
FrozenCeleritySetBenchmark.FrozenCeleritySet_Contains(ItemCount: 1000) 89.75 μs 990.5 ns 89.32 μs +0.5%
SwissSetBenchmark.SwissSet_Contains(ItemCount: 1000) 2.77 μs 1.8 ns 2.74 μs +1.3%
XorFilterBenchmark.XorFilter_Contains(ItemCount: 1000) 6.77 μs 3.8 ns 6.77 μs +0.0%
CuckooFilterBenchmark.HashSet_Contains(ItemCount: 100000) 1.57 ms 22.77 μs 1.18 ms +33.8% ⚠️
FrozenCeleritySetBenchmark.FrozenSet_Contains(ItemCount: 100000) 1.88 ms 72.52 μs 1.94 ms -3.1%
SwissSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.56 ms 5.12 μs 1.51 ms +2.8%
XorFilterBenchmark.HashSet_Contains(ItemCount: 100000) 1.58 ms 18.10 μs 1.53 ms +3.1%
CuckooFilterBenchmark.CuckooFilter_Contains(ItemCount: 100000) 1.75 ms 7.22 μs 1.53 ms +14.0% ⚠️
FrozenCeleritySetBenchmark.FrozenCeleritySet_Contains(ItemCount: 100000) 7.35 ms 13.91 μs 7.32 ms +0.3%
SwissSetBenchmark.SwissSet_Contains(ItemCount: 100000) 643.03 μs 3.52 μs 489.05 μs +31.5% ⚠️
XorFilterBenchmark.XorFilter_Contains(ItemCount: 100000) 703.93 μs 1.42 μs 703.48 μs +0.1%
CuckooFilterBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 4.54 μs 19.9 ns 3.54 μs +28.3% ⚠️
SwissSetBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 4.55 μs 10.9 ns 4.57 μs -0.5%
XorFilterBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 4.54 μs 4.1 ns 4.54 μs -0.0%
CuckooFilterBenchmark.CuckooFilter_ContainsMissing(ItemCount: 1000) 8.37 μs 8.4 ns 7.45 μs +12.3% ⚠️
SwissSetBenchmark.SwissSet_ContainsMissing(ItemCount: 1000) 2.37 μs 3.4 ns 2.51 μs -5.6%
XorFilterBenchmark.XorFilter_ContainsMissing(ItemCount: 1000) 6.78 μs 11.2 ns 6.78 μs -0.1%
CuckooFilterBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 1.91 ms 27.35 μs 1.54 ms +24.0% ⚠️
SwissSetBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 1.86 ms 54.77 μs 1.98 ms -6.3%
XorFilterBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 1.92 ms 20.54 μs 1.93 ms -0.8%
CuckooFilterBenchmark.CuckooFilter_ContainsMissing(ItemCount: 100000) 925.98 μs 303.6 ns 763.81 μs +21.2% ⚠️
SwissSetBenchmark.SwissSet_ContainsMissing(ItemCount: 100000) 351.43 μs 5.77 μs 314.91 μs +11.6% ⚠️
XorFilterBenchmark.XorFilter_ContainsMissing(ItemCount: 100000) 705.52 μs 602.3 ns 704.89 μs +0.1%
IndexedPriorityQueueBenchmark.PriorityQueue_DecreaseKey(ItemCount: 1000) 144.82 μs 1.54 μs 76.33 μs +89.7% ⚠️
IndexedPriorityQueueBenchmark.IndexedPriorityQueue_DecreaseKey(ItemCount: 1000) 251.77 μs 1.29 μs 178.38 μs +41.1% ⚠️
IndexedPriorityQueueBenchmark.PriorityQueue_DecreaseKey(ItemCount: 100000) 32.55 ms 184.67 μs 35.04 ms -7.1%
IndexedPriorityQueueBenchmark.IndexedPriorityQueue_DecreaseKey(ItemCount: 100000) 53.56 ms 188.99 μs 53.99 ms -0.8%
IndexedPriorityQueueBenchmark.PriorityQueue_Enqueue(ItemCount: 1000) 4.51 μs 29.1 ns 4.58 μs -1.5%
IndexedPriorityQueueBenchmark.IndexedPriorityQueue_Enqueue(ItemCount: 1000) 28.97 μs 248.7 ns 28.09 μs +3.1%
IndexedPriorityQueueBenchmark.PriorityQueue_Enqueue(ItemCount: 100000) 1.06 ms 10.82 μs 1.18 ms -10.3% ✅
IndexedPriorityQueueBenchmark.IndexedPriorityQueue_Enqueue(ItemCount: 100000) 5.92 ms 132.23 μs 6.13 ms -3.4%
SmallDictionaryBenchmark.Dictionary_Insert(ItemCount: 8) 160.1 ns 1.9 ns 157.0 ns +1.9%
SmallDictionaryBenchmark.SmallDictionary_Insert(ItemCount: 8) 84.1 ns 0.3 ns 92.9 ns -9.5% ✅
SmallDictionaryBenchmark.Dictionary_Insert(ItemCount: 64) 752.2 ns 2.3 ns 755.1 ns -0.4%
SmallDictionaryBenchmark.SmallDictionary_Insert(ItemCount: 64) 1.05 μs 14.0 ns 1.06 μs -0.8%
SmallDictionaryBenchmark.Dictionary_Lookup(ItemCount: 8) 37.0 ns 0.1 ns 36.9 ns +0.2%
SmallDictionaryBenchmark.SmallDictionary_Lookup(ItemCount: 8) 29.2 ns 3.3 ns 25.8 ns +13.1%
SmallDictionaryBenchmark.Dictionary_Lookup(ItemCount: 64) 296.2 ns 1.0 ns 295.6 ns +0.2%
SmallDictionaryBenchmark.SmallDictionary_Lookup(ItemCount: 64) 1.12 μs 8.7 ns 1.11 μs +0.7%
SmallDictionaryBenchmark.Dictionary_Remove(ItemCount: 8) 1.27 μs 58.0 ns 1.46 μs -13.3%
SmallDictionaryBenchmark.SmallDictionary_Remove(ItemCount: 8) 1.22 μs 64.7 ns 1.49 μs -17.7%
SmallDictionaryBenchmark.Dictionary_Remove(ItemCount: 64) 5.63 μs 786.0 ns 4.93 μs +14.2%
SmallDictionaryBenchmark.SmallDictionary_Remove(ItemCount: 64) 25.99 μs 4.61 μs 28.82 μs -9.8%
SwissSetBenchmark.HashSet_Remove(ItemCount: 1000) 30.03 μs 3.13 μs 27.14 μs +10.6%
SwissSetBenchmark.SwissSet_Remove(ItemCount: 1000) 72.07 μs 11.19 μs 67.87 μs +6.2%
CuckooFilterBenchmark.HashSet_Remove(ItemCount: 1000) 12.75 μs 30.0 ns 10.51 μs +21.3% ⚠️
CuckooFilterBenchmark.CuckooFilter_Remove(ItemCount: 1000) 12.78 μs 37.5 ns 11.06 μs +15.6% ⚠️
SwissSetBenchmark.HashSet_Remove(ItemCount: 100000) 1.70 ms 15.76 μs 1.69 ms +0.2%
SwissSetBenchmark.SwissSet_Remove(ItemCount: 100000) 1.06 ms 11.62 μs 851.61 μs +24.8% ⚠️
CuckooFilterBenchmark.HashSet_Remove(ItemCount: 100000) 3.77 ms 56.43 μs 2.94 ms +28.0% ⚠️
CuckooFilterBenchmark.CuckooFilter_Remove(ItemCount: 100000) 3.94 ms 6.45 μs 3.46 ms +13.9% ⚠️
EnumSetBenchmark.HashSet_Add 634.2 ns 4.7 ns 639.8 ns -0.9%
EnumSetBenchmark.EnumSet_Add 89.1 ns 3.2 ns 85.7 ns +3.9%
CeleritySetBenchmark.HashSet_Add(ItemCount: 1000) 13.68 μs 98.1 ns 13.90 μs -1.6%
RobinHoodSetBenchmark.HashSet_Add(ItemCount: 1000) 13.20 μs 556.9 ns 12.63 μs +4.5%
CeleritySetBenchmark.CeleritySet_Add(ItemCount: 1000) 9.34 μs 71.4 ns 9.25 μs +1.0%
RobinHoodSetBenchmark.RobinHoodSet_Add(ItemCount: 1000) 18.10 μs 112.4 ns 13.27 μs +36.4% ⚠️
CeleritySetBenchmark.HashSet_Add(ItemCount: 100000) 5.22 ms 130.47 μs 5.17 ms +1.0%
RobinHoodSetBenchmark.HashSet_Add(ItemCount: 100000) 4.61 ms 446.86 μs 5.09 ms -9.5%
CeleritySetBenchmark.CeleritySet_Add(ItemCount: 100000) 3.20 ms 24.25 μs 3.25 ms -1.8%
RobinHoodSetBenchmark.RobinHoodSet_Add(ItemCount: 100000) 6.39 ms 39.41 μs 6.64 ms -3.7%
BitSetBenchmark.BitArray_And(ItemCount: 1024) 60.3 ns 0.4 ns 61.6 ns -2.0%
BitSetBenchmark.BitSet_And(ItemCount: 1024) 1.25 μs 3.1 ns 1.21 μs +3.3%
BitSetBenchmark.BitArray_And(ItemCount: 1000000) 44.75 μs 405.6 ns 44.57 μs +0.4%
BitSetBenchmark.BitSet_And(ItemCount: 1000000) 4.48 ms 3.17 μs 4.49 ms -0.1%
EnumSetBenchmark.HashSet_Contains 175.5 ns 0.4 ns 175.3 ns +0.1%
EnumSetBenchmark.EnumSet_Contains 45.9 ns 0.1 ns 46.1 ns -0.2%
CeleritySetBenchmark.HashSet_Contains(ItemCount: 1000) 4.75 μs 21.8 ns 4.80 μs -1.1%
RobinHoodSetBenchmark.HashSet_Contains(ItemCount: 1000) 4.90 μs 178.1 ns 4.77 μs +2.8%
CeleritySetBenchmark.CeleritySet_Contains(ItemCount: 1000) 1.86 μs 8.3 ns 1.86 μs -0.2%
RobinHoodSetBenchmark.RobinHoodSet_Contains(ItemCount: 1000) 2.53 μs 111.3 ns 2.76 μs -8.5%
CeleritySetBenchmark.HashSet_Contains(ItemCount: 100000) 1.57 ms 2.95 μs 1.59 ms -1.0%
RobinHoodSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.59 ms 15.28 μs 1.47 ms +8.1%
CeleritySetBenchmark.CeleritySet_Contains(ItemCount: 100000) 592.78 μs 1.83 μs 592.97 μs -0.0%
RobinHoodSetBenchmark.RobinHoodSet_Contains(ItemCount: 100000) 743.65 μs 2.39 μs 783.22 μs -5.1%
RobinHoodSetBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 4.54 μs 4.6 ns 4.57 μs -0.6%
RobinHoodSetBenchmark.RobinHoodSet_ContainsMissing(ItemCount: 1000) 2.71 μs 3.8 ns 2.70 μs +0.4%
RobinHoodSetBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 1.93 ms 20.71 μs 1.97 ms -1.8%
RobinHoodSetBenchmark.RobinHoodSet_ContainsMissing(ItemCount: 100000) 1.19 ms 1.78 μs 1.28 ms -7.5%
LruCacheBenchmark.Dictionary_Get(ItemCount: 1000) 24.38 μs 110.7 ns 24.84 μs -1.9%
LruCacheBenchmark.LruCache_Get(ItemCount: 1000) 6.85 μs 57.2 ns 6.81 μs +0.6%
LruCacheBenchmark.Dictionary_Get(ItemCount: 100000) 25.81 μs 335.0 ns 25.23 μs +2.3%
LruCacheBenchmark.LruCache_Get(ItemCount: 100000) 6.95 μs 41.6 ns 7.02 μs -0.9%
LruCacheBenchmark.Dictionary_GetMissing(ItemCount: 1000) 4.83 μs 50.8 ns 4.80 μs +0.7%
LruCacheBenchmark.LruCache_GetMissing(ItemCount: 1000) 3.49 μs 4.3 ns 3.50 μs -0.1%
LruCacheBenchmark.Dictionary_GetMissing(ItemCount: 100000) 519.35 μs 683.1 ns 520.14 μs -0.2%
LruCacheBenchmark.LruCache_GetMissing(ItemCount: 100000) 1.38 ms 970.7 ns 1.37 ms +0.2%
FenwickTreeBenchmark.Array_Mixed(ItemCount: 1000) 182.04 μs 461.8 ns 182.21 μs -0.1%
FenwickTreeBenchmark.FenwickTree_Mixed(ItemCount: 1000) 11.31 μs 23.6 ns 11.02 μs +2.6%
FenwickTreeBenchmark.Array_Mixed(ItemCount: 100000) 166.50 ms 758.46 μs 166.42 ms +0.1%
FenwickTreeBenchmark.FenwickTree_Mixed(ItemCount: 100000) 639.33 μs 15.78 μs 628.79 μs +1.7%
BitSetBenchmark.BitArray_Or(ItemCount: 1024) 60.9 ns 0.5 ns 61.2 ns -0.4%
BitSetBenchmark.BitSet_Or(ItemCount: 1024) 1.25 μs 3.7 ns 1.25 μs -0.0%
BitSetBenchmark.BitArray_Or(ItemCount: 1000000) 45.39 μs 492.9 ns 44.72 μs +1.5%
BitSetBenchmark.BitSet_Or(ItemCount: 1000000) 4.48 ms 5.25 μs 4.48 ms -0.0%
BitSetBenchmark.BitArray_PopCount(ItemCount: 1024) 1.24 μs 2.5 ns 1.24 μs -0.1%
BitSetBenchmark.BitSet_PopCount(ItemCount: 1024) 7.1 ns 0.0 ns 7.1 ns -0.2%
BitSetBenchmark.BitArray_PopCount(ItemCount: 1000000) 4.83 ms 2.96 μs 4.83 ms -0.1%
BitSetBenchmark.BitSet_PopCount(ItemCount: 1000000) 4.94 μs 3.5 ns 4.94 μs -0.0%
LruCacheBenchmark.Dictionary_Put(ItemCount: 1000) 110.12 μs 7.17 μs 108.37 μs +1.6%
LruCacheBenchmark.LruCache_Put(ItemCount: 1000) 549.56 μs 22.16 μs 538.01 μs +2.1%
LruCacheBenchmark.Dictionary_Put(ItemCount: 100000) 8.27 ms 58.56 μs 8.36 ms -1.0%
LruCacheBenchmark.LruCache_Put(ItemCount: 100000) 5.76 ms 25.77 μs 5.77 ms -0.2%
FenwickTreeBenchmark.Array_RangeSum(ItemCount: 1000) 221.11 μs 558.3 ns 220.82 μs +0.1%
FenwickTreeBenchmark.FenwickTree_RangeSum(ItemCount: 1000) 7.46 μs 7.2 ns 7.45 μs +0.1%
FenwickTreeBenchmark.Array_RangeSum(ItemCount: 100000) 201.75 ms 20.75 ms 158.83 ms +27.0% ⚠️
FenwickTreeBenchmark.FenwickTree_RangeSum(ItemCount: 100000) 327.95 μs 1.16 μs 323.56 μs +1.4%
EnumSetBenchmark.HashSet_Remove 3.31 μs 478.6 ns 3.40 μs -2.7%
EnumSetBenchmark.EnumSet_Remove 1.09 μs 44.2 ns 1.17 μs -7.0%
CeleritySetBenchmark.HashSet_Remove(ItemCount: 1000) 33.92 μs 4.23 μs 34.77 μs -2.4%
CeleritySetBenchmark.CeleritySet_Remove(ItemCount: 1000) 137.31 μs 10.82 μs 139.39 μs -1.5%
RobinHoodSetBenchmark.HashSet_Remove(ItemCount: 1000) 30.09 μs 4.07 μs 29.01 μs +3.7%
RobinHoodSetBenchmark.RobinHoodSet_Remove(ItemCount: 1000) 134.08 μs 5.53 μs 133.02 μs +0.8%
CeleritySetBenchmark.HashSet_Remove(ItemCount: 100000) 1.81 ms 80.95 μs 1.84 ms -1.7%
CeleritySetBenchmark.CeleritySet_Remove(ItemCount: 100000) 1.48 ms 176.99 μs 1.41 ms +5.6%
RobinHoodSetBenchmark.HashSet_Remove(ItemCount: 100000) 1.88 ms 95.10 μs 1.72 ms +9.3%
RobinHoodSetBenchmark.RobinHoodSet_Remove(ItemCount: 100000) 1.47 ms 123.40 μs 1.49 ms -1.4%
EnumSetBenchmark.HashSet_Union 446.1 ns 5.8 ns 456.3 ns -2.2%
EnumSetBenchmark.EnumSet_Union 23.3 ns 0.1 ns 23.2 ns +0.4%
BitSetBenchmark.BitArray_Xor(ItemCount: 1024) 62.3 ns 2.0 ns 65.7 ns -5.2%
BitSetBenchmark.BitSet_Xor(ItemCount: 1024) 1.25 μs 5.6 ns 1.25 μs +0.1%
BitSetBenchmark.BitArray_Xor(ItemCount: 1000000) 44.56 μs 563.8 ns 45.19 μs -1.4%
BitSetBenchmark.BitSet_Xor(ItemCount: 1000000) 4.48 ms 3.01 μs 4.48 ms +0.0%
HashCachingSetBenchmark.HashSet_Add(ItemCount: 1000) 9.83 μs 60.5 ns 11.81 μs -16.8% ✅
IntSetBenchmark.HashSet_Add(ItemCount: 1000) 9.81 μs 53.9 ns 13.55 μs -27.7% ✅
HashCachingSetBenchmark.HashCachingSet_Add(ItemCount: 1000) 8.50 μs 46.3 ns 10.59 μs -19.7% ✅
IntSetBenchmark.IntSet_Add(ItemCount: 1000) 7.14 μs 131.9 ns 8.95 μs -20.2% ✅
HashCachingSetBenchmark.HashSet_Add(ItemCount: 100000) 4.10 ms 37.32 μs 4.63 ms -11.5% ✅
IntSetBenchmark.HashSet_Add(ItemCount: 100000) 4.29 ms 110.57 μs 5.12 ms -16.2% ✅
HashCachingSetBenchmark.HashCachingSet_Add(ItemCount: 100000) 4.39 ms 97.23 μs 5.18 ms -15.3% ✅
IntSetBenchmark.IntSet_Add(ItemCount: 100000) 2.70 ms 10.86 μs 3.19 ms -15.2% ✅
DisjointSetBenchmark.Dictionary_Components(ItemCount: 1000) 13.87 μs 337.7 ns 18.33 μs -24.4% ✅
DisjointSetBenchmark.DisjointSet_Components(ItemCount: 1000) 12.25 μs 110.6 ns 16.35 μs -25.1% ✅
DisjointSetBenchmark.Dictionary_Components(ItemCount: 100000) 3.59 ms 80.17 μs 4.27 ms -15.9% ✅
DisjointSetBenchmark.DisjointSet_Components(ItemCount: 100000) 2.60 ms 42.62 μs 3.34 ms -22.1% ✅
DisjointSetBenchmark.Dictionary_Connected(ItemCount: 1000) 7.81 μs 409.3 ns 9.46 μs -17.5% ✅
DisjointSetBenchmark.DisjointSet_Connected(ItemCount: 1000) 10.07 μs 5.5 ns 12.10 μs -16.8% ✅
DisjointSetBenchmark.Dictionary_Connected(ItemCount: 100000) 121.01 μs 193.9 ns 252.13 μs -52.0% ✅
DisjointSetBenchmark.DisjointSet_Connected(ItemCount: 100000) 219.96 μs 627.6 ns 344.42 μs -36.1% ✅
HashCachingSetBenchmark.HashSet_Contains(ItemCount: 1000) 3.67 μs 3.0 ns 4.72 μs -22.3% ✅
IntSetBenchmark.HashSet_Contains(ItemCount: 1000) 3.65 μs 3.6 ns 4.74 μs -23.0% ✅
HashCachingSetBenchmark.HashCachingSet_Contains(ItemCount: 1000) 2.06 μs 8.2 ns 2.42 μs -14.8% ✅
IntSetBenchmark.IntSet_Contains(ItemCount: 1000) 1.49 μs 16.5 ns 1.81 μs -17.8% ✅
HashCachingSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.18 ms 1.68 μs 1.56 ms -24.7% ✅
IntSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.23 ms 7.51 μs 1.55 ms -20.5% ✅
HashCachingSetBenchmark.HashCachingSet_Contains(ItemCount: 100000) 581.53 μs 5.74 μs 740.91 μs -21.5% ✅
IntSetBenchmark.IntSet_Contains(ItemCount: 100000) 374.54 μs 5.78 μs 574.62 μs -34.8% ✅
HashCachingSetBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 3.54 μs 8.1 ns 4.56 μs -22.3% ✅
HashCachingSetBenchmark.HashCachingSet_ContainsMissing(ItemCount: 1000) 2.55 μs 10.6 ns 2.80 μs -9.1%
HashCachingSetBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 1.54 ms 3.59 μs 1.93 ms -20.0% ✅
HashCachingSetBenchmark.HashCachingSet_ContainsMissing(ItemCount: 100000) 977.32 μs 1.46 μs 1.16 ms -15.6% ✅
CelerityDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 10.30 μs 96.3 ns 13.76 μs -25.1% ✅
IntDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 10.27 μs 59.8 ns 16.47 μs -37.6% ✅
CelerityDictionaryBenchmark.CelerityDictionary_Insert(ItemCount: 1000) 6.73 μs 58.0 ns 9.19 μs -26.8% ✅
IntDictionaryBenchmark.IntDictionary_Insert(ItemCount: 1000) 6.60 μs 88.6 ns 12.48 μs -47.1% ✅
CelerityDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 3.43 ms 44.88 μs 4.40 ms -22.1% ✅
IntDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 3.36 ms 40.54 μs 4.34 ms -22.7% ✅
CelerityDictionaryBenchmark.CelerityDictionary_Insert(ItemCount: 100000) 4.12 ms 44.70 μs 5.22 ms -21.1% ✅
IntDictionaryBenchmark.IntDictionary_Insert(ItemCount: 100000) 4.17 ms 34.93 μs 5.06 ms -17.5% ✅
CelerityDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 3.81 μs 59.7 ns 4.72 μs -19.2% ✅
IntDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 3.62 μs 48.1 ns 4.77 μs -24.2% ✅
CelerityDictionaryBenchmark.CelerityDictionary_Lookup(ItemCount: 1000) 1.68 μs 12.4 ns 2.34 μs -28.0% ✅
IntDictionaryBenchmark.IntDictionary_Lookup(ItemCount: 1000) 1.62 μs 7.5 ns 2.14 μs -24.5% ✅
CelerityDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.20 ms 37.78 μs 1.54 ms -22.3% ✅
IntDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.20 ms 8.51 μs 1.61 ms -25.5% ✅
CelerityDictionaryBenchmark.CelerityDictionary_Lookup(ItemCount: 100000) 546.41 μs 15.45 μs 695.04 μs -21.4% ✅
IntDictionaryBenchmark.IntDictionary_Lookup(ItemCount: 100000) 597.52 μs 4.75 μs 678.58 μs -11.9% ✅
CelerityDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 62.54 μs 6.09 μs 76.12 μs -17.8% ✅
IntDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 58.73 μs 4.90 μs 82.17 μs -28.5% ✅
IntSetBenchmark.HashSet_Remove(ItemCount: 1000) 22.04 μs 2.11 μs 26.45 μs -16.7% ✅
CelerityDictionaryBenchmark.CelerityDictionary_Remove(ItemCount: 1000) 115.24 μs 5.83 μs 146.89 μs -21.6% ✅
IntDictionaryBenchmark.IntDictionary_Remove(ItemCount: 1000) 70.26 μs 6.25 μs 92.98 μs -24.4% ✅
IntSetBenchmark.IntSet_Remove(ItemCount: 1000) 65.45 μs 6.54 μs 83.80 μs -21.9% ✅
HashCachingSetBenchmark.HashSet_Remove(ItemCount: 1000) 21.55 μs 784.2 ns 30.12 μs -28.5% ✅
HashCachingSetBenchmark.HashCachingSet_Remove(ItemCount: 1000) 85.57 μs 4.42 μs 113.10 μs -24.3% ✅
CelerityDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 1.55 ms 15.30 μs 2.05 ms -24.3% ✅
IntDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 1.54 ms 13.46 μs 2.07 ms -25.7% ✅
IntSetBenchmark.HashSet_Remove(ItemCount: 100000) 1.31 ms 16.58 μs 1.71 ms -23.7% ✅
CelerityDictionaryBenchmark.CelerityDictionary_Remove(ItemCount: 100000) 1.31 ms 17.46 μs 1.89 ms -30.7% ✅
IntDictionaryBenchmark.IntDictionary_Remove(ItemCount: 100000) 2.06 ms 1.43 ms 1.59 ms +29.5%
IntSetBenchmark.IntSet_Remove(ItemCount: 100000) 1.14 ms 21.33 μs 1.33 ms -14.2% ✅
HashCachingSetBenchmark.HashSet_Remove(ItemCount: 100000) 1.32 ms 13.09 μs 1.70 ms -22.5% ✅
HashCachingSetBenchmark.HashCachingSet_Remove(ItemCount: 100000) 1.31 ms 8.39 μs 1.54 ms -14.8% ✅
DisjointSetBenchmark.Dictionary_Union(ItemCount: 1000) 72.81 μs 1.00 μs 95.67 μs -23.9% ✅
DisjointSetBenchmark.DisjointSet_Union(ItemCount: 1000) 21.51 μs 116.7 ns 26.99 μs -20.3% ✅
DisjointSetBenchmark.Dictionary_Union(ItemCount: 100000) 36.17 ms 1.28 ms 43.38 ms -16.6% ✅
DisjointSetBenchmark.DisjointSet_Union(ItemCount: 100000) 6.03 ms 45.63 μs 8.15 ms -26.0% ✅
TrieBenchmark.Dictionary_Add(ItemCount: 1000) 42.85 μs 4.11 μs 39.55 μs +8.3%
TrieBenchmark.Trie_Add(ItemCount: 1000) 647.90 μs 31.45 μs 653.26 μs -0.8%
LongSetBenchmark.HashSet_Add(ItemCount: 1000) 13.45 μs 715.7 ns 13.02 μs +3.2%
SparseSetBenchmark.HashSet_Add(ItemCount: 1000) 8.01 μs 179.6 ns 7.09 μs +13.0% ⚠️
LongSetBenchmark.LongSet_Add(ItemCount: 1000) 9.42 μs 148.7 ns 9.07 μs +3.9%
SparseSetBenchmark.SparseSet_Add(ItemCount: 1000) 6.41 μs 352.4 ns 6.52 μs -1.7%
TrieBenchmark.Dictionary_Add(ItemCount: 100000) 5.40 ms 1.66 ms 4.91 ms +9.9%
TrieBenchmark.Trie_Add(ItemCount: 100000) 24.90 ms 358.13 μs 24.88 ms +0.1%
LongSetBenchmark.HashSet_Add(ItemCount: 100000) 4.57 ms 189.79 μs 4.42 ms +3.2%
SparseSetBenchmark.HashSet_Add(ItemCount: 100000) 1.92 ms 172.96 μs 1.75 ms +9.8%
LongSetBenchmark.LongSet_Add(ItemCount: 100000) 6.11 ms 53.11 μs 6.02 ms +1.5%
SparseSetBenchmark.SparseSet_Add(ItemCount: 100000) 1.48 ms 65.94 μs 1.61 ms -8.2%
SparseSetBenchmark.HashSet_ClearRefill(ItemCount: 1000) 6.04 μs 48.8 ns 6.01 μs +0.4%
SparseSetBenchmark.SparseSet_ClearRefill(ItemCount: 1000) 4.69 μs 56.0 ns 4.58 μs +2.3%
SparseSetBenchmark.HashSet_ClearRefill(ItemCount: 100000) 1.36 ms 6.96 μs 1.38 ms -1.5%
SparseSetBenchmark.SparseSet_ClearRefill(ItemCount: 100000) 646.50 μs 3.35 μs 661.23 μs -2.2%
LongSetBenchmark.HashSet_Contains(ItemCount: 1000) 4.87 μs 37.9 ns 4.74 μs +2.6%
SparseSetBenchmark.HashSet_Contains(ItemCount: 1000) 4.77 μs 122.4 ns 4.66 μs +2.4%
LongSetBenchmark.LongSet_Contains(ItemCount: 1000) 2.00 μs 8.5 ns 2.01 μs -0.4%
SparseSetBenchmark.SparseSet_Contains(ItemCount: 1000) 1.29 μs 2.8 ns 1.32 μs -2.8%
LongSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.59 ms 53.20 μs 1.62 ms -2.1%
SparseSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.35 ms 5.63 μs 1.35 ms +0.5%
LongSetBenchmark.LongSet_Contains(ItemCount: 100000) 643.19 μs 2.53 μs 638.35 μs +0.8%
SparseSetBenchmark.SparseSet_Contains(ItemCount: 100000) 249.98 μs 9.71 μs 260.36 μs -4.0%
LongDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 15.86 μs 533.5 ns 14.48 μs +9.6%
RobinHoodDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 15.22 μs 1.81 μs 14.33 μs +6.2%
LongDictionaryBenchmark.LongDictionary_Insert(ItemCount: 1000) 12.30 μs 328.4 ns 11.42 μs +7.8%
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Insert(ItemCount: 1000) 17.10 μs 164.2 ns 18.10 μs -5.6%
LongDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 5.07 ms 48.60 μs 4.96 ms +2.1%
RobinHoodDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 4.74 ms 75.98 μs 5.20 ms -8.9%
LongDictionaryBenchmark.LongDictionary_Insert(ItemCount: 100000) 6.80 ms 135.73 μs 6.66 ms +2.1%
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Insert(ItemCount: 100000) 7.75 ms 557.87 μs 9.28 ms -16.5% ✅
LongDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.89 μs 27.4 ns 4.92 μs -0.8%
RobinHoodDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.71 μs 21.5 ns 4.73 μs -0.4%
TrieBenchmark.Dictionary_Lookup(ItemCount: 1000) 13.08 μs 617.3 ns 13.21 μs -1.0%
LongDictionaryBenchmark.LongDictionary_Lookup(ItemCount: 1000) 2.27 μs 6.5 ns 2.27 μs -0.2%
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Lookup(ItemCount: 1000) 2.63 μs 11.3 ns 2.89 μs -9.2% ✅
TrieBenchmark.Trie_Lookup(ItemCount: 1000) 40.41 μs 202.7 ns 40.38 μs +0.1%
LongDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.59 ms 4.98 μs 1.58 ms +0.4%
RobinHoodDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.60 ms 3.44 μs 1.61 ms -0.5%
TrieBenchmark.Dictionary_Lookup(ItemCount: 100000) 2.75 ms 25.61 μs 2.68 ms +2.6%
LongDictionaryBenchmark.LongDictionary_Lookup(ItemCount: 100000) 708.98 μs 1.41 μs 697.77 μs +1.6%
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Lookup(ItemCount: 100000) 862.41 μs 39.72 μs 915.57 μs -5.8%
TrieBenchmark.Trie_Lookup(ItemCount: 100000) 9.12 ms 216.04 μs 8.39 ms +8.7%
TrieBenchmark.Dictionary_PrefixMatch(ItemCount: 1000) 73.49 μs 69.5 ns 73.35 μs +0.2%
TrieBenchmark.Trie_PrefixMatch(ItemCount: 1000) 56.44 μs 1.30 μs 52.73 μs +7.0%
TrieBenchmark.Dictionary_PrefixMatch(ItemCount: 100000) 7.44 ms 14.10 μs 7.38 ms +0.8%
TrieBenchmark.Trie_PrefixMatch(ItemCount: 100000) 9.76 ms 457.82 μs 6.99 ms +39.7% ⚠️
LongDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 84.80 μs 7.50 μs 89.75 μs -5.5%
LongSetBenchmark.HashSet_Remove(ItemCount: 1000) 79.93 μs 6.76 μs 80.10 μs -0.2%
RobinHoodDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 84.90 μs 7.87 μs 78.22 μs +8.5%
LongDictionaryBenchmark.LongDictionary_Remove(ItemCount: 1000) 91.04 μs 9.56 μs 93.71 μs -2.8%
LongSetBenchmark.LongSet_Remove(ItemCount: 1000) 87.70 μs 6.09 μs 81.13 μs +8.1%
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Remove(ItemCount: 1000) 138.70 μs 7.61 μs 135.81 μs +2.1%
SparseSetBenchmark.HashSet_Remove(ItemCount: 1000) 30.81 μs 4.49 μs 28.03 μs +9.9%
SparseSetBenchmark.SparseSet_Remove(ItemCount: 1000) 28.23 μs 3.21 μs 32.22 μs -12.4%
LongDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.04 ms 37.55 μs 2.00 ms +2.2%
LongSetBenchmark.HashSet_Remove(ItemCount: 100000) 1.97 ms 14.55 μs 1.98 ms -0.6%
RobinHoodDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.05 ms 7.07 μs 2.01 ms +2.1%
LongDictionaryBenchmark.LongDictionary_Remove(ItemCount: 100000) 2.06 ms 415.62 μs 7.06 ms -70.8% ✅
LongSetBenchmark.LongSet_Remove(ItemCount: 100000) 1.43 ms 15.79 μs 1.42 ms +0.3%
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Remove(ItemCount: 100000) 1.68 ms 48.58 μs 1.82 ms -7.8%
SparseSetBenchmark.HashSet_Remove(ItemCount: 100000) 1.50 ms 21.07 μs 1.76 ms -14.9% ✅
SparseSetBenchmark.SparseSet_Remove(ItemCount: 100000) 820.53 μs 27.24 μs 816.04 μs +0.6%
Hashers (100)
Benchmark This PR StdDev main Δ
StringHasherBenchmark.Bcl_GetHashCode(Shape: ShortAscii) 15.40 μs 17.1 ns 15.39 μs +0.1%
StringHasherBenchmark.EqualityComparer_Default(Shape: ShortAscii) 15.38 μs 9.5 ns 15.35 μs +0.2%
StringHasherBenchmark.Djb2(Shape: ShortAscii) 22.04 μs 26.6 ns 22.02 μs +0.1%
StringHasherBenchmark.Djb2A(Shape: ShortAscii) 22.01 μs 29.3 ns 22.03 μs -0.1%
StringHasherBenchmark.Sdbm(Shape: ShortAscii) 32.83 μs 29.9 ns 32.82 μs +0.0%
StringHasherBenchmark.Elf(Shape: ShortAscii) 44.04 μs 227.6 ns 44.00 μs +0.1%
StringHasherBenchmark.Crc32(Shape: ShortAscii) 49.85 μs 39.2 ns 49.88 μs -0.0%
StringHasherBenchmark.Adler32(Shape: ShortAscii) 96.22 μs 75.6 ns 96.22 μs -0.0%
StringHasherBenchmark.FnV1(Shape: ShortAscii) 25.40 μs 26.4 ns 25.34 μs +0.2%
StringHasherBenchmark.FnV1_64(Shape: ShortAscii) 25.53 μs 69.3 ns 25.44 μs +0.4%
StringHasherBenchmark.FnV1A(Shape: ShortAscii) 10.69 μs 13.1 ns 10.65 μs +0.4%
StringHasherBenchmark.FnV1A_Full(Shape: ShortAscii) 22.93 μs 74.9 ns 22.83 μs +0.5%
StringHasherBenchmark.FnV1A_64(Shape: ShortAscii) 25.76 μs 45.1 ns 25.69 μs +0.3%
StringHasherBenchmark.JenkinsOaat(Shape: ShortAscii) 39.28 μs 60.1 ns 39.26 μs +0.1%
StringHasherBenchmark.Murmur2(Shape: ShortAscii) 15.22 μs 48.6 ns 15.19 μs +0.2%
StringHasherBenchmark.Murmur3(Shape: ShortAscii) 17.30 μs 24.4 ns 17.32 μs -0.1%
StringHasherBenchmark.XxHash32(Shape: ShortAscii) 16.91 μs 14.7 ns 16.91 μs -0.0%
StringHasherBenchmark.XxHash64(Shape: ShortAscii) 18.06 μs 36.2 ns 18.03 μs +0.1%
StringHasherBenchmark.XxHash3(Shape: ShortAscii) 14.89 μs 43.4 ns 14.92 μs -0.2%
StringHasherBenchmark.CityHash64(Shape: ShortAscii) 15.22 μs 6.2 ns 15.22 μs -0.0%
StringHasherBenchmark.MetroHash64(Shape: ShortAscii) 15.00 μs 6.7 ns 15.01 μs -0.1%
StringHasherBenchmark.SipHash13(Shape: ShortAscii) 27.35 μs 13.5 ns 27.36 μs -0.0%
StringHasherBenchmark.SipHash24(Shape: ShortAscii) 38.44 μs 26.1 ns 38.45 μs -0.0%
StringHasherBenchmark.HalfSipHash24(Shape: ShortAscii) 50.01 μs 46.9 ns 49.98 μs +0.1%
StringHasherBenchmark.HighwayHash64(Shape: ShortAscii) 479.51 μs 545.4 ns 479.46 μs +0.0%
StringHasherBenchmark.Bcl_GetHashCode(Shape: LongAscii) 96.83 μs 48.1 ns 96.82 μs +0.0%
StringHasherBenchmark.EqualityComparer_Default(Shape: LongAscii) 96.46 μs 48.4 ns 96.67 μs -0.2%
StringHasherBenchmark.Djb2(Shape: LongAscii) 229.21 μs 66.1 ns 229.23 μs -0.0%
StringHasherBenchmark.Djb2A(Shape: LongAscii) 229.14 μs 81.6 ns 229.14 μs +0.0%
StringHasherBenchmark.Sdbm(Shape: LongAscii) 307.85 μs 83.5 ns 307.91 μs -0.0%
StringHasherBenchmark.Elf(Shape: LongAscii) 577.12 μs 155.7 ns 577.35 μs -0.0%
StringHasherBenchmark.Crc32(Shape: LongAscii) 588.96 μs 177.5 ns 589.35 μs -0.1%
StringHasherBenchmark.Adler32(Shape: LongAscii) 788.64 μs 183.2 ns 788.41 μs +0.0%
StringHasherBenchmark.FnV1(Shape: LongAscii) 289.41 μs 85.8 ns 289.28 μs +0.0%
StringHasherBenchmark.FnV1_64(Shape: LongAscii) 284.29 μs 78.4 ns 284.27 μs +0.0%
StringHasherBenchmark.FnV1A(Shape: LongAscii) 122.23 μs 87.2 ns 122.22 μs +0.0%
StringHasherBenchmark.FnV1A_Full(Shape: LongAscii) 281.47 μs 77.2 ns 281.46 μs +0.0%
StringHasherBenchmark.FnV1A_64(Shape: LongAscii) 286.42 μs 258.4 ns 286.73 μs -0.1%
StringHasherBenchmark.JenkinsOaat(Shape: LongAscii) 378.32 μs 154.2 ns 378.53 μs -0.1%
StringHasherBenchmark.Murmur2(Shape: LongAscii) 101.65 μs 196.3 ns 103.57 μs -1.9%
StringHasherBenchmark.Murmur3(Shape: LongAscii) 110.76 μs 809.1 ns 112.85 μs -1.8%
StringHasherBenchmark.XxHash32(Shape: LongAscii) 73.30 μs 152.6 ns 73.36 μs -0.1%
StringHasherBenchmark.XxHash64(Shape: LongAscii) 90.54 μs 928.9 ns 90.74 μs -0.2%
StringHasherBenchmark.XxHash3(Shape: LongAscii) 69.95 μs 118.2 ns 70.33 μs -0.5%
StringHasherBenchmark.CityHash64(Shape: LongAscii) 122.70 μs 1.27 μs 122.74 μs -0.0%
StringHasherBenchmark.MetroHash64(Shape: LongAscii) 77.66 μs 2.42 μs 77.18 μs +0.6%
StringHasherBenchmark.SipHash13(Shape: LongAscii) 114.69 μs 197.2 ns 114.53 μs +0.1%
StringHasherBenchmark.SipHash24(Shape: LongAscii) 160.79 μs 590.1 ns 161.25 μs -0.3%
StringHasherBenchmark.HalfSipHash24(Shape: LongAscii) 247.60 μs 188.9 ns 247.46 μs +0.1%
StringHasherBenchmark.HighwayHash64(Shape: LongAscii) 833.96 μs 5.76 μs 832.00 μs +0.2%
StringHasherBenchmark.Bcl_GetHashCode(Shape: NonAscii) 22.89 μs 36.6 ns 22.86 μs +0.1%
StringHasherBenchmark.EqualityComparer_Default(Shape: NonAscii) 22.83 μs 12.8 ns 22.82 μs +0.0%
StringHasherBenchmark.Djb2(Shape: NonAscii) 43.41 μs 29.0 ns 43.38 μs +0.1%
StringHasherBenchmark.Djb2A(Shape: NonAscii) 43.43 μs 36.1 ns 43.41 μs +0.1%
StringHasherBenchmark.Sdbm(Shape: NonAscii) 61.58 μs 42.5 ns 61.55 μs +0.0%
StringHasherBenchmark.Elf(Shape: NonAscii) 99.52 μs 119.7 ns 99.62 μs -0.1%
StringHasherBenchmark.Crc32(Shape: NonAscii) 102.64 μs 70.2 ns 102.58 μs +0.1%
StringHasherBenchmark.Adler32(Shape: NonAscii) 175.33 μs 70.6 ns 175.33 μs +0.0%
StringHasherBenchmark.FnV1(Shape: NonAscii) 47.61 μs 36.2 ns 47.62 μs -0.0%
StringHasherBenchmark.FnV1_64(Shape: NonAscii) 50.01 μs 48.6 ns 49.98 μs +0.1%
StringHasherBenchmark.FnV1A(Shape: NonAscii) 21.64 μs 26.2 ns 21.63 μs +0.0%
StringHasherBenchmark.FnV1A_Full(Shape: NonAscii) 45.03 μs 35.6 ns 45.03 μs -0.0%
StringHasherBenchmark.FnV1A_64(Shape: NonAscii) 49.58 μs 27.3 ns 49.56 μs +0.0%
StringHasherBenchmark.JenkinsOaat(Shape: NonAscii) 73.06 μs 53.7 ns 73.07 μs -0.0%
StringHasherBenchmark.Murmur2(Shape: NonAscii) 27.25 μs 185.0 ns 27.83 μs -2.1%
StringHasherBenchmark.Murmur3(Shape: NonAscii) 31.85 μs 91.7 ns 32.09 μs -0.7%
StringHasherBenchmark.XxHash32(Shape: NonAscii) 23.89 μs 14.3 ns 23.97 μs -0.3%
StringHasherBenchmark.XxHash64(Shape: NonAscii) 29.09 μs 12.2 ns 29.19 μs -0.3%
StringHasherBenchmark.XxHash3(Shape: NonAscii) 22.87 μs 28.8 ns 22.93 μs -0.3%
StringHasherBenchmark.CityHash64(Shape: NonAscii) 22.00 μs 22.1 ns 22.06 μs -0.3%
StringHasherBenchmark.MetroHash64(Shape: NonAscii) 25.61 μs 6.8 ns 25.63 μs -0.1%
StringHasherBenchmark.SipHash13(Shape: NonAscii) 36.92 μs 112.9 ns 36.92 μs +0.0%
StringHasherBenchmark.SipHash24(Shape: NonAscii) 51.44 μs 455.6 ns 51.49 μs -0.1%
StringHasherBenchmark.HalfSipHash24(Shape: NonAscii) 72.70 μs 811.9 ns 72.65 μs +0.1%
StringHasherBenchmark.HighwayHash64(Shape: NonAscii) 513.17 μs 1.33 μs 514.04 μs -0.2%
IntegerHasherBenchmark.Guid_Bcl 1.27 μs 2.0 ns 1.26 μs +0.8%
IntegerHasherBenchmark.Guid_EqualityComparer 3.49 μs 14.6 ns 3.47 μs +0.4%
IntegerHasherBenchmark.Guid_Celerity 8.04 μs 5.5 ns 8.03 μs +0.1%
IntegerHasherBenchmark.Int32_Bcl 705.3 ns 4.3 ns 696.7 ns +1.2%
IntegerHasherBenchmark.Int32_EqualityComparer 713.4 ns 2.9 ns 711.4 ns +0.3%
IntegerHasherBenchmark.Int32_Identity 703.0 ns 4.9 ns 693.7 ns +1.3%
IntegerHasherBenchmark.Int32_WangNaive 1.25 μs 0.7 ns 1.25 μs -0.0%
IntegerHasherBenchmark.Int32_Wang 3.02 μs 3.2 ns 3.02 μs +0.2%
IntegerHasherBenchmark.Int32_Murmur3 2.64 μs 1.9 ns 2.65 μs -0.0%
IntegerHasherBenchmark.Int64_Bcl 1.27 μs 1.8 ns 1.27 μs +0.0%
IntegerHasherBenchmark.Int64_EqualityComparer 1.25 μs 0.5 ns 1.25 μs +0.0%
IntegerHasherBenchmark.Int64_Identity 691.3 ns 4.1 ns 688.4 ns +0.4%
IntegerHasherBenchmark.Int64_WangNaive 1.87 μs 2.5 ns 1.87 μs +0.0%
IntegerHasherBenchmark.Int64_Wang 4.16 μs 3.2 ns 4.16 μs -0.0%
IntegerHasherBenchmark.Int64_Murmur3 2.37 μs 1.6 ns 2.37 μs +0.0%
IntegerHasherBenchmark.UInt32_Bcl 685.8 ns 1.5 ns 687.5 ns -0.3%
IntegerHasherBenchmark.UInt32_EqualityComparer 707.9 ns 2.4 ns 705.0 ns +0.4%
IntegerHasherBenchmark.UInt32_Default 1.25 μs 0.6 ns 1.25 μs -0.0%
IntegerHasherBenchmark.UInt32_Wang 3.02 μs 2.7 ns 3.02 μs -0.0%
IntegerHasherBenchmark.UInt32_Murmur3 2.65 μs 5.2 ns 2.65 μs +0.2%
IntegerHasherBenchmark.UInt64_Bcl 1.27 μs 0.8 ns 1.27 μs -0.1%
IntegerHasherBenchmark.UInt64_EqualityComparer 1.25 μs 0.5 ns 1.25 μs +0.0%
IntegerHasherBenchmark.UInt64_Default 2.37 μs 2.2 ns 2.37 μs -0.0%
IntegerHasherBenchmark.UInt64_Wang 4.16 μs 1.5 ns 4.16 μs -0.1%
IntegerHasherBenchmark.UInt64_WangNaive 1.87 μs 0.9 ns 1.87 μs +0.0%

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

Copilot AI 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 30 out of 30 changed files in this pull request and generated 1 comment.

Comment thread ROADMAP.md Outdated
"and it string-keyed" reads as a missing word; the ordered-lane sentence now
ends "and that one string-keyed".

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

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

Comments suppressed due to low confidence (1)

CHANGELOG.md:9

  • The new [Unreleased] entry is significantly longer than the repo’s changelog guidance (“a few sentences at most”) and includes implementation-detail phrasing. Consider tightening it to a short, user-facing summary so future releases don’t risk oversized release bodies.
- **`BTreeDictionary<TKey, TValue, TComparer>` and `BTreeSet<T, TComparer>`** (with `BTreeDictionary<TKey, TValue>` / `BTreeSet<T>` aliases and the `DefaultComparer<T>` struct comparer) in `Celerity.Collections` — the library's first sorted map and set, and the B-tree the BCL lacks. Up to 31 keys per node keep a lookup `log₃₂(n)` node visits deep instead of chasing the `log₂(n)` pointers a red-black tree costs, and both add the ordered surface a hash table cannot answer: `Min` / `Max`, lower / upper bound, `EnumerateRange` in `O(log n + k)`, and in-order enumeration. They win on the interleaved insert + lookup + range-scan workload and on memory, and lose slightly on a delete-dominated one. Not thread-safe. Closes [#305](https://github.com/marius-bughiu/Celerity/issues/305).

@marius-bughiu

Copy link
Copy Markdown
Owner Author

Review loop is quiet — the latest Copilot pass (on d283291) generated no new comments, and CI is green: build-and-test on all three OSes, all three aot-publish TFMs, and the coverage gate. The benchmark shards are still running; they were re-triggered on each push and I cancelled the superseded runs by hand so the head commit's CI could get a runner (that starvation is #319).

Three threads are deliberately left unresolved for your call, each with the reasoning in-thread:

  1. Type-parameter names on the ship cards (web/index.html) — Copilot wants BTreeDictionary<TKey, TValue, TComparer>; the neighbouring cards already use LruCache<K, V, H> and IndexedPriorityQueue<E, P, H>, so I matched the page's existing convention. Happy to switch all the cards if you'd rather standardise the other way.
  2. Shared B-tree core between BTreeSet and BTreeDictionary — the split/merge/borrow and cursor logic is duplicated. I kept them separate: every set/dictionary pair in the library already ships as two implementations, and the cheap consolidation (BTreeSet<T> over BTreeDictionary<T, byte>) would put a dead value array in every node, which is where the set's 0.24x allocation advantage comes from. If you want the consolidation, it seems like a family-wide follow-up rather than this PR.
  3. Mixed benchmark uses an in-order prefix scan, not EnumerateRange — the misleading comment is fixed; the code is deliberate. SortedDictionary has no range view, so folding the range API into Mixed would let one O(n)-vs-O(log n + k) ratio dominate a row meant to measure the steady-state mixed load. RangeScan isolates that asymmetry separately. Two-line change if you disagree.

One more, from the suppressed low-confidence block rather than a thread: Copilot has twice asked for a shorter [Unreleased] entry. I condensed it once already (three bullets → one). At its current length it matches the FenwickTree and Trie entries directly beneath it in the same file, so trimming further would make it shorter than the entries it sits beside rather than more consistent — flagging it in case you'd rather it be terser still.

@marius-bughiu
marius-bughiu merged commit 780e1a1 into main Jul 26, 2026
17 checks passed
@marius-bughiu
marius-bughiu deleted the feat/issue-305-btree branch July 26, 2026 07:03
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 BTreeDictionary<TKey,TValue,TComparer> and BTreeSet<T,TComparer> — the library has no sorted map or set

2 participants