Skip to content

feat(collections): add Trie<TValue> — ordered prefix tree with O(prefix) prefix search & longest-prefix match - #286

Merged
marius-bughiu merged 14 commits into
mainfrom
feat/issue-285-trie
Jul 23, 2026
Merged

feat(collections): add Trie<TValue> — ordered prefix tree with O(prefix) prefix search & longest-prefix match#286
marius-bughiu merged 14 commits into
mainfrom
feat/issue-285-trie

Conversation

@marius-bughiu

Copy link
Copy Markdown
Owner

What

Adds Trie<TValue> to Celerity.Collections — an ordered prefix tree mapping string keys to values, filling a genuine BCL gap (.NET ships no trie). Closes #285.

Dictionary<string, TValue> answers exact-key lookups in O(1) but has no efficient prefix operation. The trie answers those directly from its structure:

  • GetByPrefix / GetKeysWithPrefix — every entry whose key starts with a prefix, in O(prefix + matches) and ascending key order (autocomplete, typeahead, namespace/route listing). A Dictionary must scan every key and run StartsWith.
  • TryGetLongestPrefix — the longest stored key that is a prefix of a query, in O(query) (routing tables, tokenizer/dictionary matching, longest-match).
  • Ordered iteration for free (a Dictionary is unordered).

Exact Add / TryGetValue favour a Dictionary (one hash vs a per-character walk) — that's documented, and the prefix operations are the win (Guiding Principle: beats the BCL on ≥1 documented workload).

Design. Each node keeps its child edges in two parallel arrays sorted by edge char, so a child lookup is a binary search and a pre-order walk is ordinal-ordered (sorted enumeration for free). Removal prunes dead paths bottom-up, so the structure never retains nodes that lead to no key. The empty string is a valid key. Implements IReadOnlyDictionary<string, TValue>. Not thread-safe.

Parity rollout (all in this PR)

  • Collectionsrc/Celerity/Collections/Trie.cs.
  • Dedicated testsTrieTests, TriePrefixTests, TrieEnumerationTests, TrieDifferentialTests (4,000-step randomized battery per seed vs a SortedDictionary<string,int> ordinal oracle), mirroring the Deque* / DisjointSet* four-file layout. 109 Trie tests; full suite 4255 passing.
  • BenchmarkTrieBenchmark (Trie<int> vs Dictionary<string,int>, Add / Lookup / PrefixMatch), registered in Program.cs's CoreBenchmarks.
  • Dashboard — ship card in web/index.html; COLLECTIONS arrays in web/dev/bench/index.html and web/dev/bench/detail.html.
  • Docs — full API section in docs/api/collections.md; README Collections list ("Prefix trees"), quick-start <details>, and a "Choosing a collection" row.
  • CHANGELOG — a bullet per facet under [Unreleased].

Parity facets that genuinely don't apply

Test plan

  • dotnet build (whole solution, Debug) — 0 errors.
  • dotnet test (net9.0) — 4255 passed, 0 failed (109 new Trie tests).
  • CI matrix (net8.0 / net9.0 / net10.0 × ubuntu / windows / macos), coverage gate (line ≥95% / branch ≥90%), and AOT smoke test — via CI.
  • Benchmark run + gh-pages dashboard refresh on merge to main (the new Trie card renders once data.js publishes).

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

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown

Coverage

Metric Value
Line 98.58% (6792/6890)
Branch 97.05% (2859/2946)
Files below 100% line coverage
File Line Branch
src/Celerity/Collections/TopKEntry.cs 80% n/a
src/Celerity/Collections/XorFilter.cs 94.29% 90%
src/Celerity/Collections/EnumMap.cs 95.09% 92.19%
src/Celerity/Collections/IndexedPriorityQueue.cs 96.23% 90.91%
src/Celerity/Collections/CuckooFilter.cs 96.6% 89.42%

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 a new Trie<TValue> collection to Celerity.Collections (string-keyed ordered prefix tree) along with parity rollout: tests, benchmarks, docs, website/dashboard wiring, and changelog/README updates.

Changes:

  • Introduces Trie<TValue> implementing IReadOnlyDictionary<string, TValue> with prefix enumeration and longest-prefix match APIs.
  • Adds a comprehensive xUnit test suite (core, prefix, enumeration, differential/oracle).
  • Adds BenchmarkDotNet coverage + wires the collection into the benchmark dashboard and documentation.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
web/index.html Adds “Trie” to the “What ships in the box” page.
web/dev/bench/index.html Adds Trie to the benchmark collection list (ops: Add/Lookup/PrefixMatch).
web/dev/bench/detail.html Adds Trie to the benchmark detail page collection list.
src/Celerity/Collections/Trie.cs New Trie<TValue> implementation (ordered prefix tree).
src/Celerity.Tests/Collections/TrieTests.cs Core behavior and exception-contract tests for Trie<TValue>.
src/Celerity.Tests/Collections/TriePrefixTests.cs Tests for ContainsPrefix, GetByPrefix, TryGetLongestPrefix.
src/Celerity.Tests/Collections/TrieEnumerationTests.cs Tests for ordering, IReadOnlyDictionary surface, and mutation-during-enumeration behavior.
src/Celerity.Tests/Collections/TrieDifferentialTests.cs Differential randomized tests vs SortedDictionary oracle.
src/Celerity.Benchmarks/TrieBenchmark.cs Adds Trie<int> vs Dictionary<string,int> benchmark, including prefix match workload.
src/Celerity.Benchmarks/Program.cs Registers TrieBenchmark in the core benchmark suite.
README.md Documents the new trie and adds usage/selection guidance.
docs/api/collections.md Adds full API reference section for Trie<TValue>.
CHANGELOG.md Adds [Unreleased] entries describing the new trie and rollout facets.

Comment thread src/Celerity/Collections/Trie.cs Outdated
Comment thread src/Celerity/Collections/Trie.cs
Comment thread src/Celerity/Collections/Trie.cs Outdated
Comment thread src/Celerity/Collections/Trie.cs Outdated
Comment thread src/Celerity/Collections/Trie.cs Outdated
Comment thread src/Celerity/Collections/Trie.cs Outdated
Comment thread src/Celerity/Collections/Trie.cs
Comment thread src/Celerity/Collections/Trie.cs Outdated
Comment thread src/Celerity/Collections/Trie.cs
Comment thread CHANGELOG.md Outdated
@github-actions

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown

Benchmarks

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

Highlights

Benchmark This PR StdDev main Δ
HyperLogLogBenchmark.HyperLogLog_Add(ItemCount: 100000) 575.59 μs 978.7 ns 490.18 μs +17.4% ⚠️
HyperLogLogBenchmark.HyperLogLog_Estimate(ItemCount: 1000) 23.46 μs 36.8 ns 26.39 μs -11.1% ✅
HyperLogLogBenchmark.HyperLogLog_Estimate(ItemCount: 100000) 22.98 μs 8.7 ns 27.96 μs -17.8% ✅
EnumSetBenchmark.EnumSet_Add 117.3 ns 0.3 ns 85.2 ns +37.6% ⚠️
EnumSetBenchmark.HashSet_Contains 126.1 ns 0.5 ns 175.4 ns -28.1% ✅
EnumSetBenchmark.EnumSet_Contains 40.5 ns 0.0 ns 46.0 ns -12.0% ✅
EnumSetBenchmark.EnumSet_Union 26.5 ns 0.9 ns 22.0 ns +20.3% ⚠️
CountMinSketchBenchmark.Dictionary_Add(ItemCount: 1000) 10.41 μs 64.9 ns 8.45 μs +23.2% ⚠️
CountMinSketchBenchmark.CountMinSketch_Add(ItemCount: 1000) 13.10 μs 202.2 ns 9.35 μs +40.2% ⚠️
CountMinSketchBenchmark.Dictionary_Add(ItemCount: 100000) 1.47 ms 17.49 μs 1.11 ms +32.1% ⚠️
CountMinSketchBenchmark.CountMinSketch_Add(ItemCount: 100000) 1.14 ms 6.13 μs 756.58 μs +51.2% ⚠️
CountMinSketchBenchmark.Dictionary_Estimate(ItemCount: 1000) 4.68 μs 32.5 ns 3.40 μs +37.8% ⚠️
CountMinSketchBenchmark.CountMinSketch_Estimate(ItemCount: 1000) 8.19 μs 301.7 ns 5.93 μs +38.2% ⚠️
CountMinSketchBenchmark.Dictionary_Estimate(ItemCount: 100000) 561.75 μs 30.95 μs 366.46 μs +53.3% ⚠️
EnumMapBenchmark.EnumMap_Remove 1.15 μs 61.4 ns 1.57 μs -26.8% ✅
SmallDictionaryBenchmark.Dictionary_Insert(ItemCount: 8) 169.7 ns 3.0 ns 195.4 ns -13.2% ✅
CelerityDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 15.31 μs 648.1 ns 13.46 μs +13.7% ⚠️
CelerityDictionaryBenchmark.CelerityDictionary_Lookup(ItemCount: 1000) 2.15 μs 3.7 ns 6.17 μs -65.1% ✅
SmallDictionaryBenchmark.SmallDictionary_Remove(ItemCount: 64) 31.40 μs 424.0 ns 21.31 μs +47.3% ⚠️
SmallSetBenchmark.SmallSet_Remove(ItemCount: 64) 31.16 μs 829.3 ns 26.44 μs +17.9% ⚠️
CelerityDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.32 ms 259.88 μs 2.04 ms +13.4% ⚠️
BloomFilterBenchmark.HashSet_Add(ItemCount: 1000) 16.22 μs 3.62 μs 12.27 μs +32.1% ⚠️
CeleritySetBenchmark.HashSet_Add(ItemCount: 1000) 12.55 μs 84.7 ns 13.95 μs -10.0% ✅
IndexedPriorityQueueBenchmark.PriorityQueue_DecreaseKey(ItemCount: 1000) 144.71 μs 893.4 ns 79.81 μs +81.3% ⚠️
IndexedPriorityQueueBenchmark.IndexedPriorityQueue_DecreaseKey(ItemCount: 1000) 251.66 μs 1.17 μs 178.81 μs +40.7% ⚠️
FrozenCelerityDictionaryBenchmark.FrozenCelerityDictionary_Build(ItemCount: 1000) 3.41 ms 44.80 μs 3.89 ms -12.5% ✅
CuckooFilterBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 2.27 ms 5.66 μs 2.00 ms +13.9% ⚠️
CuckooFilterBenchmark.CuckooFilter_ContainsMissing(ItemCount: 100000) 1.15 ms 1.53 μs 985.28 μs +16.7% ⚠️
FrozenCelerityDictionaryBenchmark.FrozenCelerityDictionary_Lookup(ItemCount: 100000) 8.26 ms 36.71 μs 7.37 ms +12.0% ⚠️
Collections (396)
Benchmark This PR StdDev main Δ
HyperLogLogBenchmark.HashSet_Add(ItemCount: 1000) 12.90 μs 407.2 ns 13.39 μs -3.7%
HyperLogLogBenchmark.HyperLogLog_Add(ItemCount: 1000) 27.44 μs 95.1 ns 30.04 μs -8.6%
HyperLogLogBenchmark.HashSet_Add(ItemCount: 100000) 4.94 ms 81.85 μs 5.04 ms -2.0%
HyperLogLogBenchmark.HyperLogLog_Add(ItemCount: 100000) 575.59 μs 978.7 ns 490.18 μs +17.4% ⚠️
HyperLogLogBenchmark.HashSet_Estimate(ItemCount: 1000) 0.0 ns 0.0 ns 0.0 ns -52.0%
HyperLogLogBenchmark.HyperLogLog_Estimate(ItemCount: 1000) 23.46 μs 36.8 ns 26.39 μs -11.1% ✅
HyperLogLogBenchmark.HashSet_Estimate(ItemCount: 100000) 0.0 ns 0.0 ns 0.0 ns +509.0%
HyperLogLogBenchmark.HyperLogLog_Estimate(ItemCount: 100000) 22.98 μs 8.7 ns 27.96 μs -17.8% ✅
EnumSetBenchmark.HashSet_Add 597.6 ns 18.6 ns 577.0 ns +3.6%
EnumSetBenchmark.EnumSet_Add 117.3 ns 0.3 ns 85.2 ns +37.6% ⚠️
LongSetBenchmark.HashSet_Add(ItemCount: 1000) 13.40 μs 419.1 ns 13.44 μs -0.3%
LongSetBenchmark.LongSet_Add(ItemCount: 1000) 9.22 μs 288.4 ns 9.55 μs -3.5%
LongSetBenchmark.HashSet_Add(ItemCount: 100000) 4.10 ms 158.56 μs 4.30 ms -4.7%
LongSetBenchmark.LongSet_Add(ItemCount: 100000) 6.04 ms 151.24 μs 6.10 ms -0.9%
EnumSetBenchmark.HashSet_Contains 126.1 ns 0.5 ns 175.4 ns -28.1% ✅
EnumSetBenchmark.EnumSet_Contains 40.5 ns 0.0 ns 46.0 ns -12.0% ✅
LongSetBenchmark.HashSet_Contains(ItemCount: 1000) 3.60 μs 5.4 ns 3.62 μs -0.5%
LongSetBenchmark.LongSet_Contains(ItemCount: 1000) 1.98 μs 15.8 ns 1.98 μs -0.3%
LongSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.48 ms 2.52 μs 1.49 ms -0.5%
LongSetBenchmark.LongSet_Contains(ItemCount: 100000) 665.81 μs 5.34 μs 669.93 μs -0.6%
CelerityMultiSetBenchmark.Dictionary_Count(ItemCount: 1000) 8.12 μs 41.0 ns 7.96 μs +2.0%
CelerityMultiSetBenchmark.CelerityMultiSet_Count(ItemCount: 1000) 4.65 μs 43.6 ns 4.61 μs +0.7%
CelerityMultiSetBenchmark.Dictionary_Count(ItemCount: 100000) 1.13 ms 8.54 μs 1.11 ms +1.8%
CelerityMultiSetBenchmark.CelerityMultiSet_Count(ItemCount: 100000) 689.27 μs 6.28 μs 676.53 μs +1.9%
DequeBenchmark.LinkedList_Enumerate(ItemCount: 1000) 1.65 μs 1.0 ns 1.66 μs -0.4%
DequeBenchmark.Deque_Enumerate(ItemCount: 1000) 773.0 ns 1.5 ns 777.7 ns -0.6%
DequeBenchmark.LinkedList_Enumerate(ItemCount: 100000) 204.84 μs 777.6 ns 205.40 μs -0.3%
DequeBenchmark.Deque_Enumerate(ItemCount: 100000) 76.31 μs 82.2 ns 76.80 μs -0.6%
HashCachingDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 15.40 μs 75.0 ns 14.12 μs +9.0%
HashCachingDictionaryBenchmark.HashCachingDictionary_Insert(ItemCount: 1000) 11.91 μs 241.3 ns 11.71 μs +1.7%
HashCachingDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 4.39 ms 120.88 μs 4.30 ms +2.0%
HashCachingDictionaryBenchmark.HashCachingDictionary_Insert(ItemCount: 100000) 6.76 ms 117.65 μs 6.61 ms +2.3%
CelerityMultiSetBenchmark.Dictionary_Lookup(ItemCount: 1000) 3.62 μs 81.3 ns 3.61 μs +0.2%
HashCachingDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 3.56 μs 23.9 ns 3.40 μs +4.7%
CelerityMultiSetBenchmark.CelerityMultiSet_Lookup(ItemCount: 1000) 1.55 μs 15.7 ns 1.54 μs +0.9%
HashCachingDictionaryBenchmark.HashCachingDictionary_Lookup(ItemCount: 1000) 2.44 μs 14.2 ns 2.42 μs +1.0%
CelerityMultiSetBenchmark.Dictionary_Lookup(ItemCount: 100000) 381.51 μs 2.59 μs 378.09 μs +0.9%
HashCachingDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.46 ms 6.58 μs 1.44 ms +1.3%
CelerityMultiSetBenchmark.CelerityMultiSet_Lookup(ItemCount: 100000) 174.05 μs 854.8 ns 173.73 μs +0.2%
HashCachingDictionaryBenchmark.HashCachingDictionary_Lookup(ItemCount: 100000) 931.95 μs 3.35 μs 1.04 ms -10.6%
DequeBenchmark.LinkedList_PushFront(ItemCount: 1000) 41.68 μs 5.79 μs 37.04 μs +12.5%
DequeBenchmark.Deque_PushFront(ItemCount: 1000) 18.85 μs 7.17 μs 22.01 μs -14.3%
DequeBenchmark.LinkedList_PushFront(ItemCount: 100000) 2.04 ms 66.44 μs 2.10 ms -3.0%
DequeBenchmark.Deque_PushFront(ItemCount: 100000) 574.70 μs 85.29 μs 494.30 μs +16.3%
DequeBenchmark.LinkedList_Queue(ItemCount: 1000) 50.76 μs 2.18 μs 56.67 μs -10.4%
DequeBenchmark.Deque_Queue(ItemCount: 1000) 25.26 μs 7.06 μs 19.61 μs +28.8%
DequeBenchmark.LinkedList_Queue(ItemCount: 100000) 4.17 ms 175.82 μs 4.46 ms -6.6%
DequeBenchmark.Deque_Queue(ItemCount: 100000) 396.69 μs 98.94 μs 352.37 μs +12.6%
EnumSetBenchmark.HashSet_Remove 3.59 μs 1.28 μs 2.97 μs +20.7%
EnumSetBenchmark.EnumSet_Remove 1.36 μs 737.1 ns 1.09 μs +24.6%
CelerityMultiSetBenchmark.Dictionary_Remove(ItemCount: 1000) 50.48 μs 9.66 μs 49.78 μs +1.4%
HashCachingDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 73.85 μs 11.43 μs 71.46 μs +3.3%
LongSetBenchmark.HashSet_Remove(ItemCount: 1000) 66.58 μs 8.89 μs 67.32 μs -1.1%
CelerityMultiSetBenchmark.CelerityMultiSet_Remove(ItemCount: 1000) 92.98 μs 9.14 μs 84.97 μs +9.4%
HashCachingDictionaryBenchmark.HashCachingDictionary_Remove(ItemCount: 1000) 98.76 μs 8.95 μs 96.26 μs +2.6%
LongSetBenchmark.LongSet_Remove(ItemCount: 1000) 71.36 μs 13.18 μs 69.79 μs +2.3%
CelerityMultiSetBenchmark.Dictionary_Remove(ItemCount: 100000) 594.47 μs 20.28 μs 605.11 μs -1.8%
HashCachingDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 1.84 ms 32.85 μs 1.83 ms +0.5%
LongSetBenchmark.HashSet_Remove(ItemCount: 100000) 1.81 ms 22.36 μs 1.80 ms +0.6%
CelerityMultiSetBenchmark.CelerityMultiSet_Remove(ItemCount: 100000) 971.87 μs 274.40 μs 1.04 ms -6.5%
HashCachingDictionaryBenchmark.HashCachingDictionary_Remove(ItemCount: 100000) 2.72 ms 1.62 ms 2.71 ms +0.4%
LongSetBenchmark.LongSet_Remove(ItemCount: 100000) 1.62 ms 21.54 μs 1.63 ms -0.9%
EnumSetBenchmark.HashSet_Union 425.9 ns 10.8 ns 420.7 ns +1.2%
EnumSetBenchmark.EnumSet_Union 26.5 ns 0.9 ns 22.0 ns +20.3% ⚠️
EnumMapBenchmark.Dictionary_Add 639.3 ns 9.5 ns 633.4 ns +0.9%
EnumMapBenchmark.EnumMap_Add 110.3 ns 0.4 ns 111.8 ns -1.4%
CountMinSketchBenchmark.Dictionary_Add(ItemCount: 1000) 10.41 μs 64.9 ns 8.45 μs +23.2% ⚠️
IntSetBenchmark.HashSet_Add(ItemCount: 1000) 12.87 μs 177.3 ns 13.22 μs -2.7%
SwissSetBenchmark.HashSet_Add(ItemCount: 1000) 12.66 μs 76.6 ns 13.50 μs -6.2%
CountMinSketchBenchmark.CountMinSketch_Add(ItemCount: 1000) 13.10 μs 202.2 ns 9.35 μs +40.2% ⚠️
IntSetBenchmark.IntSet_Add(ItemCount: 1000) 9.53 μs 156.4 ns 9.38 μs +1.6%
SwissSetBenchmark.SwissSet_Add(ItemCount: 1000) 25.76 μs 72.2 ns 26.05 μs -1.1%
CountMinSketchBenchmark.Dictionary_Add(ItemCount: 100000) 1.47 ms 17.49 μs 1.11 ms +32.1% ⚠️
IntSetBenchmark.HashSet_Add(ItemCount: 100000) 5.24 ms 150.45 μs 5.24 ms +0.1%
SwissSetBenchmark.HashSet_Add(ItemCount: 100000) 4.97 ms 98.49 μs 4.94 ms +0.5%
CountMinSketchBenchmark.CountMinSketch_Add(ItemCount: 100000) 1.14 ms 6.13 μs 756.58 μs +51.2% ⚠️
IntSetBenchmark.IntSet_Add(ItemCount: 100000) 3.48 ms 17.75 μs 3.50 ms -0.4%
SwissSetBenchmark.SwissSet_Add(ItemCount: 100000) 4.51 ms 83.86 μs 4.39 ms +2.6%
BitSetBenchmark.BitArray_And(ItemCount: 1024) 93.6 ns 0.6 ns 93.9 ns -0.3%
BitSetBenchmark.BitSet_And(ItemCount: 1024) 1.23 μs 3.3 ns 1.23 μs -0.0%
BitSetBenchmark.BitArray_And(ItemCount: 1000000) 45.66 μs 386.1 ns 46.09 μs -0.9%
BitSetBenchmark.BitSet_And(ItemCount: 1000000) 5.04 ms 7.50 μs 5.03 ms +0.1%
IntSetBenchmark.HashSet_Contains(ItemCount: 1000) 4.71 μs 12.4 ns 4.71 μs +0.0%
SwissSetBenchmark.HashSet_Contains(ItemCount: 1000) 4.73 μs 3.0 ns 4.74 μs -0.2%
IntSetBenchmark.IntSet_Contains(ItemCount: 1000) 1.91 μs 21.3 ns 1.91 μs +0.1%
SwissSetBenchmark.SwissSet_Contains(ItemCount: 1000) 2.73 μs 2.1 ns 2.74 μs -0.3%
IntSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.51 ms 4.62 μs 1.50 ms +0.6%
SwissSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.51 ms 5.25 μs 1.51 ms -0.1%
IntSetBenchmark.IntSet_Contains(ItemCount: 100000) 495.49 μs 8.57 μs 490.25 μs +1.1%
SwissSetBenchmark.SwissSet_Contains(ItemCount: 100000) 475.25 μs 5.75 μs 482.85 μs -1.6%
SwissSetBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 4.57 μs 6.0 ns 4.57 μs -0.0%
SwissSetBenchmark.SwissSet_ContainsMissing(ItemCount: 1000) 2.51 μs 4.6 ns 2.51 μs +0.0%
SwissSetBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 2.00 ms 3.43 μs 1.99 ms +0.1%
SwissSetBenchmark.SwissSet_ContainsMissing(ItemCount: 100000) 314.57 μs 1.03 μs 316.02 μs -0.5%
EnumMapBenchmark.Dictionary_Enumerate 43.1 ns 0.1 ns 43.1 ns -0.0%
EnumMapBenchmark.EnumMap_Enumerate 38.0 ns 0.2 ns 38.0 ns -0.2%
CountMinSketchBenchmark.Dictionary_Estimate(ItemCount: 1000) 4.68 μs 32.5 ns 3.40 μs +37.8% ⚠️
CountMinSketchBenchmark.CountMinSketch_Estimate(ItemCount: 1000) 8.19 μs 301.7 ns 5.93 μs +38.2% ⚠️
CountMinSketchBenchmark.Dictionary_Estimate(ItemCount: 100000) 561.75 μs 30.95 μs 366.46 μs +53.3% ⚠️
CountMinSketchBenchmark.CountMinSketch_Estimate(ItemCount: 100000) 2.34 ms 973.6 ns 2.38 ms -2.0%
LruCacheBenchmark.Dictionary_Get(ItemCount: 1000) 24.38 μs 296.4 ns 24.62 μs -1.0%
LruCacheBenchmark.LruCache_Get(ItemCount: 1000) 7.70 μs 347.0 ns 7.46 μs +3.2%
LruCacheBenchmark.Dictionary_Get(ItemCount: 100000) 24.94 μs 474.3 ns 25.02 μs -0.3%
LruCacheBenchmark.LruCache_Get(ItemCount: 100000) 7.48 μs 35.9 ns 7.64 μs -2.1%
LruCacheBenchmark.Dictionary_GetMissing(ItemCount: 1000) 4.59 μs 4.3 ns 4.58 μs +0.1%
LruCacheBenchmark.LruCache_GetMissing(ItemCount: 1000) 3.62 μs 2.2 ns 3.61 μs +0.1%
LruCacheBenchmark.Dictionary_GetMissing(ItemCount: 100000) 536.09 μs 2.85 μs 556.64 μs -3.7%
LruCacheBenchmark.LruCache_GetMissing(ItemCount: 100000) 1.55 ms 2.77 μs 1.55 ms +0.1%
CelerityMultiMapBenchmark.Dictionary_Insert(ItemCount: 1000) 27.83 μs 373.6 ns 28.77 μs -3.2%
CelerityMultiMapBenchmark.CelerityMultiMap_Insert(ItemCount: 1000) 39.43 μs 423.9 ns 39.98 μs -1.4%
CelerityMultiMapBenchmark.Dictionary_Insert(ItemCount: 100000) 14.04 ms 869.93 μs 13.89 ms +1.1%
CelerityMultiMapBenchmark.CelerityMultiMap_Insert(ItemCount: 100000) 18.82 ms 233.71 μs 19.66 ms -4.3%
EnumMapBenchmark.Dictionary_Lookup 136.2 ns 0.5 ns 136.3 ns -0.1%
EnumMapBenchmark.EnumMap_Lookup 69.7 ns 0.1 ns 69.7 ns +0.0%
CelerityMultiMapBenchmark.Dictionary_Lookup(ItemCount: 1000) 5.10 μs 22.6 ns 5.08 μs +0.2%
CelerityMultiMapBenchmark.CelerityMultiMap_Lookup(ItemCount: 1000) 2.45 μs 2.4 ns 2.45 μs -0.2%
CelerityMultiMapBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.79 ms 2.60 μs 1.79 ms -0.0%
CelerityMultiMapBenchmark.CelerityMultiMap_Lookup(ItemCount: 100000) 713.56 μs 14.75 μs 695.15 μs +2.6%
BitSetBenchmark.BitArray_Or(ItemCount: 1024) 95.5 ns 0.2 ns 92.6 ns +3.0%
BitSetBenchmark.BitSet_Or(ItemCount: 1024) 1.23 μs 5.0 ns 1.23 μs +0.0%
BitSetBenchmark.BitArray_Or(ItemCount: 1000000) 45.58 μs 244.8 ns 45.78 μs -0.4%
BitSetBenchmark.BitSet_Or(ItemCount: 1000000) 5.04 ms 9.29 μs 5.04 ms +0.0%
BitSetBenchmark.BitArray_PopCount(ItemCount: 1024) 1.29 μs 61.1 ns 1.27 μs +1.7%
BitSetBenchmark.BitSet_PopCount(ItemCount: 1024) 7.0 ns 0.0 ns 6.9 ns +0.5%
BitSetBenchmark.BitArray_PopCount(ItemCount: 1000000) 5.48 ms 1.18 μs 5.48 ms -0.1%
BitSetBenchmark.BitSet_PopCount(ItemCount: 1000000) 5.55 μs 3.3 ns 5.58 μs -0.6%
LruCacheBenchmark.Dictionary_Put(ItemCount: 1000) 89.15 μs 2.81 μs 94.17 μs -5.3%
LruCacheBenchmark.LruCache_Put(ItemCount: 1000) 474.06 μs 18.95 μs 492.11 μs -3.7%
LruCacheBenchmark.Dictionary_Put(ItemCount: 100000) 7.76 ms 118.31 μs 7.65 ms +1.4%
LruCacheBenchmark.LruCache_Put(ItemCount: 100000) 6.37 ms 21.20 μs 6.42 ms -0.8%
EnumMapBenchmark.Dictionary_Remove 3.03 μs 506.0 ns 2.98 μs +1.8%
EnumMapBenchmark.EnumMap_Remove 1.15 μs 61.4 ns 1.57 μs -26.8% ✅
CelerityMultiMapBenchmark.Dictionary_Remove(ItemCount: 1000) 29.12 μs 2.62 μs 31.32 μs -7.0%
IntSetBenchmark.HashSet_Remove(ItemCount: 1000) 26.09 μs 1.61 μs 30.28 μs -13.8%
CelerityMultiMapBenchmark.CelerityMultiMap_Remove(ItemCount: 1000) 146.92 μs 5.22 μs 143.66 μs +2.3%
IntSetBenchmark.IntSet_Remove(ItemCount: 1000) 80.29 μs 7.09 μs 80.69 μs -0.5%
SwissSetBenchmark.HashSet_Remove(ItemCount: 1000) 30.18 μs 2.31 μs 26.93 μs +12.1%
SwissSetBenchmark.SwissSet_Remove(ItemCount: 1000) 70.73 μs 7.90 μs 67.36 μs +5.0%
CelerityMultiMapBenchmark.Dictionary_Remove(ItemCount: 100000) 2.91 ms 319.59 μs 3.05 ms -4.6%
IntSetBenchmark.HashSet_Remove(ItemCount: 100000) 1.67 ms 14.68 μs 1.67 ms -0.5%
CelerityMultiMapBenchmark.CelerityMultiMap_Remove(ItemCount: 100000) 2.70 ms 259.87 μs 2.42 ms +11.6%
IntSetBenchmark.IntSet_Remove(ItemCount: 100000) 1.43 ms 10.24 μs 1.43 ms +0.1%
SwissSetBenchmark.HashSet_Remove(ItemCount: 100000) 1.71 ms 19.04 μs 1.74 ms -1.7%
SwissSetBenchmark.SwissSet_Remove(ItemCount: 100000) 872.70 μs 21.79 μs 947.79 μs -7.9%
BitSetBenchmark.BitArray_Xor(ItemCount: 1024) 94.2 ns 0.8 ns 93.8 ns +0.4%
BitSetBenchmark.BitSet_Xor(ItemCount: 1024) 1.23 μs 3.5 ns 1.23 μs +0.2%
BitSetBenchmark.BitArray_Xor(ItemCount: 1000000) 45.78 μs 351.8 ns 46.38 μs -1.3%
BitSetBenchmark.BitSet_Xor(ItemCount: 1000000) 5.03 ms 6.61 μs 5.04 ms -0.2%
SmallSetBenchmark.HashSet_Add(ItemCount: 8) 166.5 ns 2.3 ns 176.2 ns -5.5%
SmallSetBenchmark.SmallSet_Add(ItemCount: 8) 46.2 ns 0.4 ns 48.6 ns -4.9%
SmallSetBenchmark.HashSet_Add(ItemCount: 64) 781.0 ns 17.1 ns 801.0 ns -2.5%
SmallSetBenchmark.SmallSet_Add(ItemCount: 64) 1.67 μs 3.8 ns 1.67 μs +0.2%
RobinHoodSetBenchmark.HashSet_Add(ItemCount: 1000) 12.72 μs 370.5 ns 13.11 μs -3.0%
TopKSketchBenchmark.Dictionary_Add(ItemCount: 1000) 13.99 μs 286.9 ns 13.02 μs +7.5%
RobinHoodSetBenchmark.RobinHoodSet_Add(ItemCount: 1000) 17.48 μs 470.7 ns 17.84 μs -2.0%
TopKSketchBenchmark.TopKSketch_Add(ItemCount: 1000) 83.07 μs 564.1 ns 82.36 μs +0.9%
RobinHoodSetBenchmark.HashSet_Add(ItemCount: 100000) 4.25 ms 523.91 μs 4.30 ms -1.2%
TopKSketchBenchmark.Dictionary_Add(ItemCount: 100000) 3.36 ms 66.01 μs 3.40 ms -1.1%
RobinHoodSetBenchmark.RobinHoodSet_Add(ItemCount: 100000) 6.29 ms 34.97 μs 6.35 ms -1.0%
TopKSketchBenchmark.TopKSketch_Add(ItemCount: 100000) 13.81 ms 59.01 μs 13.77 ms +0.3%
DisjointSetBenchmark.Dictionary_Components(ItemCount: 1000) 18.97 μs 152.1 ns 19.34 μs -1.9%
DisjointSetBenchmark.DisjointSet_Components(ItemCount: 1000) 16.74 μs 166.3 ns 17.09 μs -2.0%
DisjointSetBenchmark.Dictionary_Components(ItemCount: 100000) 4.33 ms 90.99 μs 4.37 ms -0.8%
DisjointSetBenchmark.DisjointSet_Components(ItemCount: 100000) 3.15 ms 16.80 μs 3.19 ms -1.3%
DisjointSetBenchmark.Dictionary_Connected(ItemCount: 1000) 9.40 μs 261.9 ns 9.17 μs +2.5%
DisjointSetBenchmark.DisjointSet_Connected(ItemCount: 1000) 12.24 μs 26.5 ns 12.15 μs +0.7%
DisjointSetBenchmark.Dictionary_Connected(ItemCount: 100000) 256.18 μs 4.57 μs 262.04 μs -2.2%
DisjointSetBenchmark.DisjointSet_Connected(ItemCount: 100000) 337.42 μs 1.07 μs 343.05 μs -1.6%
SmallSetBenchmark.HashSet_Contains(ItemCount: 8) 37.2 ns 0.0 ns 37.1 ns +0.2%
SmallSetBenchmark.SmallSet_Contains(ItemCount: 8) 19.1 ns 0.1 ns 19.7 ns -3.3%
SmallSetBenchmark.HashSet_Contains(ItemCount: 64) 299.3 ns 0.2 ns 300.0 ns -0.2%
SmallSetBenchmark.SmallSet_Contains(ItemCount: 64) 1.10 μs 10.9 ns 1.09 μs +0.2%
RobinHoodSetBenchmark.HashSet_Contains(ItemCount: 1000) 4.72 μs 7.3 ns 5.91 μs -20.1%
RobinHoodSetBenchmark.RobinHoodSet_Contains(ItemCount: 1000) 2.42 μs 4.4 ns 2.43 μs -0.3%
RobinHoodSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.58 ms 1.70 μs 1.59 ms -0.4%
RobinHoodSetBenchmark.RobinHoodSet_Contains(ItemCount: 100000) 737.96 μs 2.24 μs 744.09 μs -0.8%
RobinHoodSetBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 4.54 μs 6.2 ns 4.54 μs -0.1%
RobinHoodSetBenchmark.RobinHoodSet_ContainsMissing(ItemCount: 1000) 2.71 μs 4.4 ns 2.72 μs -0.1%
RobinHoodSetBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 1.94 ms 10.68 μs 1.93 ms +0.7%
RobinHoodSetBenchmark.RobinHoodSet_ContainsMissing(ItemCount: 100000) 1.18 ms 4.29 μs 1.18 ms +0.6%
SmallDictionaryBenchmark.Dictionary_Insert(ItemCount: 8) 169.7 ns 3.0 ns 195.4 ns -13.2% ✅
SmallDictionaryBenchmark.SmallDictionary_Insert(ItemCount: 8) 91.5 ns 2.7 ns 90.3 ns +1.3%
SmallDictionaryBenchmark.Dictionary_Insert(ItemCount: 64) 835.8 ns 21.7 ns 812.8 ns +2.8%
SmallDictionaryBenchmark.SmallDictionary_Insert(ItemCount: 64) 1.09 μs 17.1 ns 1.09 μs +0.1%
CelerityDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 15.31 μs 648.1 ns 13.46 μs +13.7% ⚠️
PooledCelerityDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 16.47 μs 693.0 ns 15.06 μs +9.3%
CelerityDictionaryBenchmark.CelerityDictionary_Insert(ItemCount: 1000) 12.41 μs 342.1 ns 12.02 μs +3.3%
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Insert(ItemCount: 1000) 8.41 μs 308.1 ns 8.40 μs +0.2%
CelerityDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 4.25 ms 70.26 μs 4.19 ms +1.4%
PooledCelerityDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 5.08 ms 55.47 μs 5.08 ms -0.0%
CelerityDictionaryBenchmark.CelerityDictionary_Insert(ItemCount: 100000) 4.91 ms 60.76 μs 4.83 ms +1.7%
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Insert(ItemCount: 100000) 2.98 ms 17.41 μs 2.97 ms +0.4%
SmallDictionaryBenchmark.Dictionary_Lookup(ItemCount: 8) 37.0 ns 0.0 ns 37.0 ns -0.0%
SmallDictionaryBenchmark.SmallDictionary_Lookup(ItemCount: 8) 22.5 ns 0.1 ns 22.2 ns +1.4%
SmallDictionaryBenchmark.Dictionary_Lookup(ItemCount: 64) 295.9 ns 0.7 ns 296.8 ns -0.3%
SmallDictionaryBenchmark.SmallDictionary_Lookup(ItemCount: 64) 1.11 μs 9.7 ns 1.10 μs +0.3%
CelerityDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.71 μs 13.9 ns 4.73 μs -0.4%
PooledCelerityDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.72 μs 21.9 ns 4.70 μs +0.4%
CelerityDictionaryBenchmark.CelerityDictionary_Lookup(ItemCount: 1000) 2.15 μs 3.7 ns 6.17 μs -65.1% ✅
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Lookup(ItemCount: 1000) 2.35 μs 27.4 ns 6.22 μs -62.2%
CelerityDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.60 ms 6.31 μs 1.59 ms +0.2%
PooledCelerityDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.61 ms 5.10 μs 1.56 ms +3.0%
CelerityDictionaryBenchmark.CelerityDictionary_Lookup(ItemCount: 100000) 694.21 μs 1.37 μs 695.73 μs -0.2%
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Lookup(ItemCount: 100000) 815.71 μs 119.15 μs 698.44 μs +16.8%
SmallDictionaryBenchmark.Dictionary_Remove(ItemCount: 8) 1.66 μs 289.7 ns 1.62 μs +2.2%
SmallSetBenchmark.HashSet_Remove(ItemCount: 8) 698.6 ns 202.4 ns 444.9 ns +57.0%
SmallDictionaryBenchmark.SmallDictionary_Remove(ItemCount: 8) 1.24 μs 128.4 ns 1.27 μs -3.1%
SmallSetBenchmark.SmallSet_Remove(ItemCount: 8) 1.46 μs 265.5 ns 1.22 μs +19.9%
SmallDictionaryBenchmark.Dictionary_Remove(ItemCount: 64) 5.50 μs 861.5 ns 4.81 μs +14.3%
SmallSetBenchmark.HashSet_Remove(ItemCount: 64) 1.81 μs 293.6 ns 1.52 μs +19.1%
SmallDictionaryBenchmark.SmallDictionary_Remove(ItemCount: 64) 31.40 μs 424.0 ns 21.31 μs +47.3% ⚠️
SmallSetBenchmark.SmallSet_Remove(ItemCount: 64) 31.16 μs 829.3 ns 26.44 μs +17.9% ⚠️
CelerityDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 86.42 μs 9.75 μs 84.22 μs +2.6%
PooledCelerityDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 83.24 μs 7.32 μs 87.61 μs -5.0%
CelerityDictionaryBenchmark.CelerityDictionary_Remove(ItemCount: 1000) 138.95 μs 9.68 μs 147.30 μs -5.7%
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Remove(ItemCount: 1000) 143.77 μs 11.62 μs 145.34 μs -1.1%
RobinHoodSetBenchmark.HashSet_Remove(ItemCount: 1000) 34.23 μs 1.89 μs 30.55 μs +12.0%
RobinHoodSetBenchmark.RobinHoodSet_Remove(ItemCount: 1000) 129.88 μs 6.24 μs 124.38 μs +4.4%
CelerityDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.32 ms 259.88 μs 2.04 ms +13.4% ⚠️
PooledCelerityDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.05 ms 17.19 μs 2.04 ms +0.3%
CelerityDictionaryBenchmark.CelerityDictionary_Remove(ItemCount: 100000) 1.77 ms 231.57 μs 1.58 ms +11.8%
PooledCelerityDictionaryBenchmark.PooledCelerityDictionary_Remove(ItemCount: 100000) 1.57 ms 14.78 μs 1.57 ms -0.0%
RobinHoodSetBenchmark.HashSet_Remove(ItemCount: 100000) 1.71 ms 16.30 μs 1.71 ms +0.2%
RobinHoodSetBenchmark.RobinHoodSet_Remove(ItemCount: 100000) 1.39 ms 59.61 μs 1.38 ms +0.9%
TopKSketchBenchmark.Dictionary_TopK(ItemCount: 1000) 32.5 ns 0.6 ns 30.5 ns +6.6%
TopKSketchBenchmark.TopKSketch_TopK(ItemCount: 1000) 1.30 μs 13.5 ns 1.24 μs +4.9%
TopKSketchBenchmark.Dictionary_TopK(ItemCount: 100000) 32.4 ns 0.5 ns 30.4 ns +6.4%
TopKSketchBenchmark.TopKSketch_TopK(ItemCount: 100000) 1.26 μs 23.1 ns 1.16 μs +8.4%
DisjointSetBenchmark.Dictionary_Union(ItemCount: 1000) 99.62 μs 994.1 ns 101.02 μs -1.4%
DisjointSetBenchmark.DisjointSet_Union(ItemCount: 1000) 27.49 μs 263.3 ns 27.32 μs +0.6%
DisjointSetBenchmark.Dictionary_Union(ItemCount: 100000) 49.00 ms 2.87 ms 50.03 ms -2.1%
DisjointSetBenchmark.DisjointSet_Union(ItemCount: 100000) 8.21 ms 75.64 μs 8.35 ms -1.6%
TrieBenchmark.Dictionary_Add(ItemCount: 1000) 36.97 μs 8.01 μs n/a 🆕 new
TrieBenchmark.Trie_Add(ItemCount: 1000) 559.81 μs 20.83 μs n/a 🆕 new
BloomFilterBenchmark.HashSet_Add(ItemCount: 1000) 16.22 μs 3.62 μs 12.27 μs +32.1% ⚠️
CeleritySetBenchmark.HashSet_Add(ItemCount: 1000) 12.55 μs 84.7 ns 13.95 μs -10.0% ✅
HashCachingSetBenchmark.HashSet_Add(ItemCount: 1000) 12.79 μs 271.8 ns 12.66 μs +1.0%
BloomFilterBenchmark.BloomFilter_Add(ItemCount: 1000) 14.49 μs 10.6 ns 14.47 μs +0.1%
CeleritySetBenchmark.CeleritySet_Add(ItemCount: 1000) 8.95 μs 38.1 ns 9.44 μs -5.2%
HashCachingSetBenchmark.HashCachingSet_Add(ItemCount: 1000) 10.96 μs 178.1 ns 11.39 μs -3.7%
TrieBenchmark.Dictionary_Add(ItemCount: 100000) 5.25 ms 1.78 ms n/a 🆕 new
TrieBenchmark.Trie_Add(ItemCount: 100000) 25.08 ms 401.13 μs n/a 🆕 new
BloomFilterBenchmark.HashSet_Add(ItemCount: 100000) 4.68 ms 154.67 μs 4.67 ms +0.1%
CeleritySetBenchmark.HashSet_Add(ItemCount: 100000) 5.02 ms 112.80 μs 5.16 ms -2.8%
HashCachingSetBenchmark.HashSet_Add(ItemCount: 100000) 4.39 ms 449.02 μs 4.44 ms -1.3%
BloomFilterBenchmark.BloomFilter_Add(ItemCount: 100000) 1.10 ms 4.95 μs 1.10 ms -0.3%
CeleritySetBenchmark.CeleritySet_Add(ItemCount: 100000) 3.20 ms 16.85 μs 3.16 ms +1.0%
HashCachingSetBenchmark.HashCachingSet_Add(ItemCount: 100000) 5.30 ms 68.23 μs 5.28 ms +0.4%
BloomFilterBenchmark.HashSet_Contains(ItemCount: 1000) 4.73 μs 18.0 ns 4.73 μs +0.0%
CeleritySetBenchmark.HashSet_Contains(ItemCount: 1000) 4.90 μs 141.4 ns 4.75 μs +3.2%
HashCachingSetBenchmark.HashSet_Contains(ItemCount: 1000) 4.73 μs 8.7 ns 4.72 μs +0.1%
BloomFilterBenchmark.BloomFilter_Contains(ItemCount: 1000) 13.12 μs 8.3 ns 13.11 μs +0.1%
CeleritySetBenchmark.CeleritySet_Contains(ItemCount: 1000) 1.83 μs 29.2 ns 1.86 μs -1.7%
HashCachingSetBenchmark.HashCachingSet_Contains(ItemCount: 1000) 2.43 μs 3.6 ns 2.43 μs +0.1%
BloomFilterBenchmark.HashSet_Contains(ItemCount: 100000) 1.58 ms 39.88 μs 1.61 ms -1.9%
CeleritySetBenchmark.HashSet_Contains(ItemCount: 100000) 1.57 ms 14.09 μs 1.56 ms +1.1%
HashCachingSetBenchmark.HashSet_Contains(ItemCount: 100000) 1.57 ms 14.66 μs 1.58 ms -0.2%
BloomFilterBenchmark.BloomFilter_Contains(ItemCount: 100000) 870.20 μs 1.04 μs 869.36 μs +0.1%
CeleritySetBenchmark.CeleritySet_Contains(ItemCount: 100000) 590.63 μs 900.0 ns 587.60 μs +0.5%
HashCachingSetBenchmark.HashCachingSet_Contains(ItemCount: 100000) 742.38 μs 2.60 μs 748.89 μs -0.9%
BloomFilterBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 4.54 μs 2.9 ns 4.54 μs +0.0%
HashCachingSetBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 4.54 μs 7.8 ns 4.54 μs +0.0%
BloomFilterBenchmark.BloomFilter_ContainsMissing(ItemCount: 1000) 3.53 μs 10.4 ns 3.53 μs -0.0%
HashCachingSetBenchmark.HashCachingSet_ContainsMissing(ItemCount: 1000) 2.80 μs 3.8 ns 2.80 μs +0.0%
BloomFilterBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 1.94 ms 4.31 μs 1.94 ms -0.0%
HashCachingSetBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 1.88 ms 61.55 μs 1.94 ms -3.4%
BloomFilterBenchmark.BloomFilter_ContainsMissing(ItemCount: 100000) 1.49 ms 1.65 μs 1.49 ms +0.0%
HashCachingSetBenchmark.HashCachingSet_ContainsMissing(ItemCount: 100000) 1.16 ms 2.08 μs 1.16 ms +0.1%
IndexedPriorityQueueBenchmark.PriorityQueue_DecreaseKey(ItemCount: 1000) 144.71 μs 893.4 ns 79.81 μs +81.3% ⚠️
IndexedPriorityQueueBenchmark.IndexedPriorityQueue_DecreaseKey(ItemCount: 1000) 251.66 μs 1.17 μs 178.81 μs +40.7% ⚠️
IndexedPriorityQueueBenchmark.PriorityQueue_DecreaseKey(ItemCount: 100000) 32.84 ms 192.30 μs 35.50 ms -7.5%
IndexedPriorityQueueBenchmark.IndexedPriorityQueue_DecreaseKey(ItemCount: 100000) 54.48 ms 282.43 μs 55.07 ms -1.1%
IndexedPriorityQueueBenchmark.PriorityQueue_Enqueue(ItemCount: 1000) 4.75 μs 99.2 ns 4.79 μs -0.8%
IndexedPriorityQueueBenchmark.IndexedPriorityQueue_Enqueue(ItemCount: 1000) 29.78 μs 222.0 ns 28.20 μs +5.6%
IndexedPriorityQueueBenchmark.PriorityQueue_Enqueue(ItemCount: 100000) 1.09 ms 15.48 μs 1.15 ms -5.5%
IndexedPriorityQueueBenchmark.IndexedPriorityQueue_Enqueue(ItemCount: 100000) 6.17 ms 160.15 μs 6.14 ms +0.5%
IntDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 14.32 μs 553.9 ns 13.76 μs +4.1%
RobinHoodDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 13.87 μs 392.2 ns 13.73 μs +1.0%
IntDictionaryBenchmark.IntDictionary_Insert(ItemCount: 1000) 11.77 μs 115.4 ns 11.51 μs +2.3%
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Insert(ItemCount: 1000) 17.64 μs 173.9 ns 17.62 μs +0.1%
IntDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 4.22 ms 87.24 μs 4.19 ms +0.9%
RobinHoodDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 4.79 ms 75.03 μs 4.79 ms +0.1%
IntDictionaryBenchmark.IntDictionary_Insert(ItemCount: 100000) 4.92 ms 85.27 μs 4.89 ms +0.7%
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Insert(ItemCount: 100000) 8.07 ms 463.16 μs 7.93 ms +1.7%
IntDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.74 μs 11.4 ns 4.74 μs -0.1%
RobinHoodDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.71 μs 17.4 ns 4.70 μs +0.1%
TrieBenchmark.Dictionary_Lookup(ItemCount: 1000) 13.35 μs 481.0 ns n/a 🆕 new
IntDictionaryBenchmark.IntDictionary_Lookup(ItemCount: 1000) 2.16 μs 20.0 ns 2.14 μs +0.8%
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Lookup(ItemCount: 1000) 2.62 μs 3.8 ns 2.63 μs -0.3%
TrieBenchmark.Trie_Lookup(ItemCount: 1000) 40.31 μs 291.2 ns n/a 🆕 new
IntDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.65 ms 6.93 μs 1.60 ms +3.2%
RobinHoodDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.61 ms 2.12 μs 1.58 ms +2.1%
TrieBenchmark.Dictionary_Lookup(ItemCount: 100000) 2.69 ms 7.60 μs n/a 🆕 new
IntDictionaryBenchmark.IntDictionary_Lookup(ItemCount: 100000) 689.64 μs 11.52 μs 687.51 μs +0.3%
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Lookup(ItemCount: 100000) 845.33 μs 6.01 μs 840.62 μs +0.6%
TrieBenchmark.Trie_Lookup(ItemCount: 100000) 8.73 ms 154.21 μs n/a 🆕 new
TrieBenchmark.Dictionary_PrefixMatch(ItemCount: 1000) 73.84 μs 276.9 ns n/a 🆕 new
TrieBenchmark.Trie_PrefixMatch(ItemCount: 1000) 54.19 μs 576.0 ns n/a 🆕 new
TrieBenchmark.Dictionary_PrefixMatch(ItemCount: 100000) 7.42 ms 32.51 μs n/a 🆕 new
TrieBenchmark.Trie_PrefixMatch(ItemCount: 100000) 7.72 ms 285.61 μs n/a 🆕 new
CeleritySetBenchmark.HashSet_Remove(ItemCount: 1000) 28.92 μs 3.82 μs 26.60 μs +8.7%
IntDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 86.35 μs 10.25 μs 87.63 μs -1.5%
RobinHoodDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 84.31 μs 8.56 μs 85.42 μs -1.3%
CeleritySetBenchmark.CeleritySet_Remove(ItemCount: 1000) 149.97 μs 16.65 μs 133.99 μs +11.9%
IntDictionaryBenchmark.IntDictionary_Remove(ItemCount: 1000) 95.71 μs 7.51 μs 95.03 μs +0.7%
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Remove(ItemCount: 1000) 141.31 μs 5.07 μs 141.17 μs +0.1%
HashCachingSetBenchmark.HashSet_Remove(ItemCount: 1000) 27.95 μs 1.36 μs 29.52 μs -5.3%
HashCachingSetBenchmark.HashCachingSet_Remove(ItemCount: 1000) 121.39 μs 15.71 μs 113.55 μs +6.9%
CeleritySetBenchmark.HashSet_Remove(ItemCount: 100000) 1.72 ms 15.75 μs 1.72 ms -0.0%
IntDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.05 ms 10.25 μs 2.11 ms -2.7%
RobinHoodDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.07 ms 19.31 μs 2.06 ms +0.6%
CeleritySetBenchmark.CeleritySet_Remove(ItemCount: 100000) 1.31 ms 56.54 μs 1.41 ms -6.8%
IntDictionaryBenchmark.IntDictionary_Remove(ItemCount: 100000) 2.78 ms 2.13 ms 1.75 ms +58.7%
RobinHoodDictionaryBenchmark.RobinHoodDictionary_Remove(ItemCount: 100000) 1.73 ms 74.93 μs 1.68 ms +3.1%
HashCachingSetBenchmark.HashSet_Remove(ItemCount: 100000) 1.73 ms 17.74 μs 1.71 ms +1.0%
HashCachingSetBenchmark.HashCachingSet_Remove(ItemCount: 100000) 1.53 ms 70.19 μs 1.56 ms -2.1%
CuckooFilterBenchmark.HashSet_Add(ItemCount: 1000) 13.22 μs 154.1 ns 12.61 μs +4.8%
PooledCeleritySetBenchmark.HashSet_Add(ItemCount: 1000) 13.90 μs 153.4 ns 13.63 μs +2.0%
CuckooFilterBenchmark.CuckooFilter_Add(ItemCount: 1000) 7.97 μs 22.2 ns 7.93 μs +0.5%
PooledCeleritySetBenchmark.PooledCeleritySet_Add(ItemCount: 1000) 9.57 μs 198.8 ns 9.81 μs -2.5%
CuckooFilterBenchmark.HashSet_Add(ItemCount: 100000) 4.75 ms 134.36 μs 4.82 ms -1.4%
PooledCeleritySetBenchmark.HashSet_Add(ItemCount: 100000) 5.06 ms 51.49 μs 5.11 ms -0.9%
CuckooFilterBenchmark.CuckooFilter_Add(ItemCount: 100000) 2.32 ms 2.80 μs 2.31 ms +0.2%
PooledCeleritySetBenchmark.PooledCeleritySet_Add(ItemCount: 100000) 3.19 ms 6.92 μs 3.15 ms +1.5%
FrozenCelerityDictionaryBenchmark.FrozenDictionary_Build(ItemCount: 1000) 165.54 μs 845.4 ns 161.69 μs +2.4%
FrozenCeleritySetBenchmark.FrozenSet_Build(ItemCount: 1000) 173.08 μs 539.2 ns 172.64 μs +0.3%
XorFilterBenchmark.HashSet_Build(ItemCount: 1000) 8.32 μs 42.5 ns 8.58 μs -3.1%
FrozenCelerityDictionaryBenchmark.FrozenCelerityDictionary_Build(ItemCount: 1000) 3.41 ms 44.80 μs 3.89 ms -12.5% ✅
FrozenCeleritySetBenchmark.FrozenCeleritySet_Build(ItemCount: 1000) 2.32 ms 31.47 μs 2.42 ms -4.2%
XorFilterBenchmark.XorFilter_Build(ItemCount: 1000) 41.73 μs 429.8 ns 44.51 μs -6.3%
FrozenCelerityDictionaryBenchmark.FrozenDictionary_Build(ItemCount: 100000) 29.84 ms 244.74 μs 29.37 ms +1.6%
FrozenCeleritySetBenchmark.FrozenSet_Build(ItemCount: 100000) 29.42 ms 236.45 μs 29.51 ms -0.3%
XorFilterBenchmark.HashSet_Build(ItemCount: 100000) 2.06 ms 20.88 μs 2.09 ms -1.3%
FrozenCelerityDictionaryBenchmark.FrozenCelerityDictionary_Build(ItemCount: 100000) 1.82 s 81.06 ms 1.99 s -8.4%
FrozenCeleritySetBenchmark.FrozenCeleritySet_Build(ItemCount: 100000) 1.45 s 37.43 ms 1.39 s +4.7%
XorFilterBenchmark.XorFilter_Build(ItemCount: 100000) 13.56 ms 102.48 μs 13.64 ms -0.6%
CuckooFilterBenchmark.HashSet_Contains(ItemCount: 1000) 4.76 μs 33.6 ns 4.74 μs +0.6%
FrozenCeleritySetBenchmark.FrozenSet_Contains(ItemCount: 1000) 7.10 μs 8.1 ns 7.26 μs -2.2%
PooledCeleritySetBenchmark.HashSet_Contains(ItemCount: 1000) 4.71 μs 8.8 ns 4.71 μs -0.1%
XorFilterBenchmark.HashSet_Contains(ItemCount: 1000) 4.79 μs 47.8 ns 4.74 μs +1.1%
CuckooFilterBenchmark.CuckooFilter_Contains(ItemCount: 1000) 5.56 μs 13.6 ns 5.55 μs +0.1%
FrozenCeleritySetBenchmark.FrozenCeleritySet_Contains(ItemCount: 1000) 78.98 μs 78.5 ns 78.90 μs +0.1%
PooledCeleritySetBenchmark.PooledCeleritySet_Contains(ItemCount: 1000) 2.04 μs 25.7 ns 2.05 μs -0.1%
XorFilterBenchmark.XorFilter_Contains(ItemCount: 1000) 7.55 μs 4.2 ns 7.56 μs -0.1%
CuckooFilterBenchmark.HashSet_Contains(ItemCount: 100000) 1.51 ms 3.97 μs 1.51 ms -0.2%
FrozenCeleritySetBenchmark.FrozenSet_Contains(ItemCount: 100000) 1.86 ms 3.68 μs 1.84 ms +1.4%
PooledCeleritySetBenchmark.HashSet_Contains(ItemCount: 100000) 1.51 ms 3.84 μs 1.46 ms +3.4%
XorFilterBenchmark.HashSet_Contains(ItemCount: 100000) 1.51 ms 3.21 μs 1.52 ms -0.4%
CuckooFilterBenchmark.CuckooFilter_Contains(ItemCount: 100000) 1.97 ms 3.49 μs 1.97 ms +0.1%
FrozenCeleritySetBenchmark.FrozenCeleritySet_Contains(ItemCount: 100000) 8.14 ms 47.32 μs 8.59 ms -5.2%
PooledCeleritySetBenchmark.PooledCeleritySet_Contains(ItemCount: 100000) 489.22 μs 17.44 μs 509.05 μs -3.9%
XorFilterBenchmark.XorFilter_Contains(ItemCount: 100000) 801.64 μs 649.8 ns 801.26 μs +0.0%
CuckooFilterBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 4.57 μs 4.4 ns 4.57 μs -0.1%
XorFilterBenchmark.HashSet_ContainsMissing(ItemCount: 1000) 4.56 μs 5.7 ns 4.57 μs -0.1%
CuckooFilterBenchmark.CuckooFilter_ContainsMissing(ItemCount: 1000) 9.63 μs 5.8 ns 9.64 μs -0.0%
XorFilterBenchmark.XorFilter_ContainsMissing(ItemCount: 1000) 7.55 μs 5.0 ns 7.55 μs +0.0%
CuckooFilterBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 2.27 ms 5.66 μs 2.00 ms +13.9% ⚠️
XorFilterBenchmark.HashSet_ContainsMissing(ItemCount: 100000) 1.99 ms 2.70 μs 2.05 ms -2.8%
CuckooFilterBenchmark.CuckooFilter_ContainsMissing(ItemCount: 100000) 1.15 ms 1.53 μs 985.28 μs +16.7% ⚠️
XorFilterBenchmark.XorFilter_ContainsMissing(ItemCount: 100000) 804.81 μs 446.1 ns 804.94 μs -0.0%
LongDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 16.04 μs 255.9 ns 15.35 μs +4.5%
SwissDictionaryBenchmark.Dictionary_Insert(ItemCount: 1000) 14.08 μs 435.8 ns 14.14 μs -0.4%
LongDictionaryBenchmark.LongDictionary_Insert(ItemCount: 1000) 9.23 μs 139.5 ns 9.05 μs +2.0%
SwissDictionaryBenchmark.SwissDictionary_Insert(ItemCount: 1000) 30.08 μs 205.7 ns 30.11 μs -0.1%
LongDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 5.31 ms 44.24 μs 5.31 ms -0.1%
SwissDictionaryBenchmark.Dictionary_Insert(ItemCount: 100000) 5.01 ms 99.84 μs 5.03 ms -0.4%
LongDictionaryBenchmark.LongDictionary_Insert(ItemCount: 100000) 7.69 ms 137.74 μs 7.72 ms -0.4%
SwissDictionaryBenchmark.SwissDictionary_Insert(ItemCount: 100000) 3.93 ms 34.83 μs 3.88 ms +1.2%
FrozenCelerityDictionaryBenchmark.FrozenDictionary_Lookup(ItemCount: 1000) 7.61 μs 12.3 ns 7.34 μs +3.7%
LongDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 5.03 μs 38.9 ns 5.03 μs +0.0%
SwissDictionaryBenchmark.Dictionary_Lookup(ItemCount: 1000) 4.73 μs 98.1 ns 4.73 μs +0.1%
FrozenCelerityDictionaryBenchmark.FrozenCelerityDictionary_Lookup(ItemCount: 1000) 83.00 μs 185.7 ns 89.39 μs -7.1%
LongDictionaryBenchmark.LongDictionary_Lookup(ItemCount: 1000) 2.30 μs 4.6 ns 2.35 μs -2.3%
SwissDictionaryBenchmark.SwissDictionary_Lookup(ItemCount: 1000) 2.93 μs 21.6 ns 2.94 μs -0.2%
FrozenCelerityDictionaryBenchmark.FrozenDictionary_Lookup(ItemCount: 100000) 1.82 ms 42.08 μs 1.94 ms -6.5%
LongDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.56 ms 20.34 μs 1.58 ms -1.5%
SwissDictionaryBenchmark.Dictionary_Lookup(ItemCount: 100000) 1.63 ms 27.15 μs 1.61 ms +1.4%
FrozenCelerityDictionaryBenchmark.FrozenCelerityDictionary_Lookup(ItemCount: 100000) 8.26 ms 36.71 μs 7.37 ms +12.0% ⚠️
LongDictionaryBenchmark.LongDictionary_Lookup(ItemCount: 100000) 682.13 μs 22.00 μs 700.89 μs -2.7%
SwissDictionaryBenchmark.SwissDictionary_Lookup(ItemCount: 100000) 649.83 μs 22.38 μs 665.17 μs -2.3%
LongDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 86.41 μs 3.69 μs 83.74 μs +3.2%
PooledCeleritySetBenchmark.HashSet_Remove(ItemCount: 1000) 27.81 μs 1.60 μs 28.10 μs -1.0%
SwissDictionaryBenchmark.Dictionary_Remove(ItemCount: 1000) 83.10 μs 6.29 μs 77.64 μs +7.0%
LongDictionaryBenchmark.LongDictionary_Remove(ItemCount: 1000) 85.00 μs 4.95 μs 84.12 μs +1.0%
PooledCeleritySetBenchmark.PooledCeleritySet_Remove(ItemCount: 1000) 154.02 μs 5.12 μs 147.83 μs +4.2%
SwissDictionaryBenchmark.SwissDictionary_Remove(ItemCount: 1000) 79.02 μs 3.17 μs 72.61 μs +8.8%
CuckooFilterBenchmark.HashSet_Remove(ItemCount: 1000) 14.84 μs 1.07 μs 13.76 μs +7.9%
CuckooFilterBenchmark.CuckooFilter_Remove(ItemCount: 1000) 14.38 μs 19.0 ns 14.30 μs +0.6%
LongDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.20 ms 253.52 μs 2.01 ms +9.5%
PooledCeleritySetBenchmark.HashSet_Remove(ItemCount: 100000) 1.68 ms 17.41 μs 1.69 ms -0.2%
SwissDictionaryBenchmark.Dictionary_Remove(ItemCount: 100000) 2.18 ms 133.23 μs 1.99 ms +9.4%
LongDictionaryBenchmark.LongDictionary_Remove(ItemCount: 100000) 2.13 ms 365.23 μs 2.05 ms +4.2%
PooledCeleritySetBenchmark.PooledCeleritySet_Remove(ItemCount: 100000) 1.37 ms 65.84 μs 1.37 ms +0.3%
SwissDictionaryBenchmark.SwissDictionary_Remove(ItemCount: 100000) 1.59 ms 245.49 μs 1.35 ms +17.5%
CuckooFilterBenchmark.HashSet_Remove(ItemCount: 100000) 3.76 ms 47.40 μs 3.79 ms -0.8%
CuckooFilterBenchmark.CuckooFilter_Remove(ItemCount: 100000) 4.51 ms 5.42 μs 4.51 ms -0.1%
Hashers (100)
Benchmark This PR StdDev main Δ
StringHasherBenchmark.Bcl_GetHashCode(Shape: ShortAscii) 15.40 μs 32.6 ns 15.40 μs -0.0%
StringHasherBenchmark.EqualityComparer_Default(Shape: ShortAscii) 15.40 μs 24.0 ns 15.42 μs -0.1%
StringHasherBenchmark.Djb2(Shape: ShortAscii) 22.04 μs 30.5 ns 22.05 μs -0.0%
StringHasherBenchmark.Djb2A(Shape: ShortAscii) 22.02 μs 15.8 ns 22.06 μs -0.1%
StringHasherBenchmark.Sdbm(Shape: ShortAscii) 32.85 μs 21.5 ns 32.85 μs -0.0%
StringHasherBenchmark.Elf(Shape: ShortAscii) 43.91 μs 122.0 ns 43.83 μs +0.2%
StringHasherBenchmark.Crc32(Shape: ShortAscii) 49.92 μs 60.4 ns 49.90 μs +0.0%
StringHasherBenchmark.Adler32(Shape: ShortAscii) 96.21 μs 67.1 ns 96.21 μs -0.0%
StringHasherBenchmark.FnV1(Shape: ShortAscii) 25.38 μs 17.7 ns 25.35 μs +0.1%
StringHasherBenchmark.FnV1_64(Shape: ShortAscii) 25.49 μs 21.3 ns 25.50 μs -0.1%
StringHasherBenchmark.FnV1A(Shape: ShortAscii) 10.65 μs 27.2 ns 10.65 μs -0.0%
StringHasherBenchmark.FnV1A_Full(Shape: ShortAscii) 22.87 μs 18.9 ns 22.87 μs +0.0%
StringHasherBenchmark.FnV1A_64(Shape: ShortAscii) 25.75 μs 32.2 ns 25.75 μs +0.0%
StringHasherBenchmark.JenkinsOaat(Shape: ShortAscii) 39.31 μs 19.6 ns 39.31 μs +0.0%
StringHasherBenchmark.Murmur2(Shape: ShortAscii) 15.22 μs 37.4 ns 15.20 μs +0.1%
StringHasherBenchmark.Murmur3(Shape: ShortAscii) 17.35 μs 20.9 ns 17.35 μs -0.0%
StringHasherBenchmark.XxHash32(Shape: ShortAscii) 16.93 μs 16.7 ns 16.93 μs -0.0%
StringHasherBenchmark.XxHash64(Shape: ShortAscii) 18.13 μs 13.7 ns 18.09 μs +0.2%
StringHasherBenchmark.XxHash3(Shape: ShortAscii) 14.90 μs 67.8 ns 14.88 μs +0.1%
StringHasherBenchmark.CityHash64(Shape: ShortAscii) 15.23 μs 5.9 ns 15.24 μs -0.0%
StringHasherBenchmark.MetroHash64(Shape: ShortAscii) 15.03 μs 24.1 ns 15.02 μs +0.1%
StringHasherBenchmark.SipHash13(Shape: ShortAscii) 27.41 μs 31.6 ns 27.41 μs +0.0%
StringHasherBenchmark.SipHash24(Shape: ShortAscii) 38.52 μs 45.3 ns 38.51 μs +0.0%
StringHasherBenchmark.HalfSipHash24(Shape: ShortAscii) 50.04 μs 52.3 ns 50.07 μs -0.1%
StringHasherBenchmark.HighwayHash64(Shape: ShortAscii) 482.52 μs 1.39 μs 480.17 μs +0.5%
StringHasherBenchmark.Bcl_GetHashCode(Shape: LongAscii) 96.97 μs 73.2 ns 97.03 μs -0.1%
StringHasherBenchmark.EqualityComparer_Default(Shape: LongAscii) 96.69 μs 55.2 ns 96.64 μs +0.1%
StringHasherBenchmark.Djb2(Shape: LongAscii) 229.42 μs 64.2 ns 229.56 μs -0.1%
StringHasherBenchmark.Djb2A(Shape: LongAscii) 229.46 μs 98.4 ns 229.55 μs -0.0%
StringHasherBenchmark.Sdbm(Shape: LongAscii) 308.06 μs 129.7 ns 308.23 μs -0.1%
StringHasherBenchmark.Elf(Shape: LongAscii) 577.76 μs 465.4 ns 577.96 μs -0.0%
StringHasherBenchmark.Crc32(Shape: LongAscii) 589.39 μs 241.6 ns 589.86 μs -0.1%
StringHasherBenchmark.Adler32(Shape: LongAscii) 789.04 μs 217.5 ns 789.34 μs -0.0%
StringHasherBenchmark.FnV1(Shape: LongAscii) 289.63 μs 118.3 ns 289.87 μs -0.1%
StringHasherBenchmark.FnV1_64(Shape: LongAscii) 284.57 μs 147.5 ns 284.65 μs -0.0%
StringHasherBenchmark.FnV1A(Shape: LongAscii) 122.35 μs 62.5 ns 122.49 μs -0.1%
StringHasherBenchmark.FnV1A_Full(Shape: LongAscii) 281.85 μs 76.6 ns 281.94 μs -0.0%
StringHasherBenchmark.FnV1A_64(Shape: LongAscii) 287.09 μs 107.7 ns 287.13 μs -0.0%
StringHasherBenchmark.JenkinsOaat(Shape: LongAscii) 378.85 μs 200.6 ns 378.92 μs -0.0%
StringHasherBenchmark.Murmur2(Shape: LongAscii) 102.03 μs 69.2 ns 102.00 μs +0.0%
StringHasherBenchmark.Murmur3(Shape: LongAscii) 111.57 μs 1.59 μs 113.05 μs -1.3%
StringHasherBenchmark.XxHash32(Shape: LongAscii) 73.44 μs 206.8 ns 73.32 μs +0.2%
StringHasherBenchmark.XxHash64(Shape: LongAscii) 91.20 μs 1.08 μs 91.07 μs +0.1%
StringHasherBenchmark.XxHash3(Shape: LongAscii) 70.18 μs 273.1 ns 70.65 μs -0.7%
StringHasherBenchmark.CityHash64(Shape: LongAscii) 122.96 μs 1.17 μs 121.64 μs +1.1%
StringHasherBenchmark.MetroHash64(Shape: LongAscii) 77.42 μs 2.35 μs 77.78 μs -0.5%
StringHasherBenchmark.SipHash13(Shape: LongAscii) 114.64 μs 48.1 ns 114.71 μs -0.1%
StringHasherBenchmark.SipHash24(Shape: LongAscii) 161.20 μs 842.6 ns 161.32 μs -0.1%
StringHasherBenchmark.HalfSipHash24(Shape: LongAscii) 248.03 μs 298.5 ns 247.71 μs +0.1%
StringHasherBenchmark.HighwayHash64(Shape: LongAscii) 826.38 μs 2.18 μs 828.61 μs -0.3%
StringHasherBenchmark.Bcl_GetHashCode(Shape: NonAscii) 22.93 μs 15.9 ns 22.89 μs +0.1%
StringHasherBenchmark.EqualityComparer_Default(Shape: NonAscii) 22.88 μs 45.9 ns 22.86 μs +0.1%
StringHasherBenchmark.Djb2(Shape: NonAscii) 43.50 μs 77.0 ns 43.42 μs +0.2%
StringHasherBenchmark.Djb2A(Shape: NonAscii) 43.72 μs 330.4 ns 43.48 μs +0.5%
StringHasherBenchmark.Sdbm(Shape: NonAscii) 61.72 μs 99.1 ns 61.60 μs +0.2%
StringHasherBenchmark.Elf(Shape: NonAscii) 99.70 μs 131.1 ns 99.75 μs -0.0%
StringHasherBenchmark.Crc32(Shape: NonAscii) 102.71 μs 114.3 ns 102.68 μs +0.0%
StringHasherBenchmark.Adler32(Shape: NonAscii) 175.48 μs 165.8 ns 175.45 μs +0.0%
StringHasherBenchmark.FnV1(Shape: NonAscii) 47.70 μs 55.1 ns 47.68 μs +0.1%
StringHasherBenchmark.FnV1_64(Shape: NonAscii) 50.05 μs 47.0 ns 50.07 μs -0.0%
StringHasherBenchmark.FnV1A(Shape: NonAscii) 21.64 μs 26.9 ns 21.64 μs -0.0%
StringHasherBenchmark.FnV1A_Full(Shape: NonAscii) 45.13 μs 45.6 ns 45.10 μs +0.1%
StringHasherBenchmark.FnV1A_64(Shape: NonAscii) 49.65 μs 44.4 ns 49.61 μs +0.1%
StringHasherBenchmark.JenkinsOaat(Shape: NonAscii) 73.27 μs 88.7 ns 73.17 μs +0.1%
StringHasherBenchmark.Murmur2(Shape: NonAscii) 27.28 μs 124.8 ns 27.28 μs -0.0%
StringHasherBenchmark.Murmur3(Shape: NonAscii) 31.88 μs 98.8 ns 31.87 μs +0.0%
StringHasherBenchmark.XxHash32(Shape: NonAscii) 23.94 μs 17.1 ns 23.93 μs +0.0%
StringHasherBenchmark.XxHash64(Shape: NonAscii) 29.18 μs 27.4 ns 29.14 μs +0.1%
StringHasherBenchmark.XxHash3(Shape: NonAscii) 22.98 μs 113.2 ns 22.95 μs +0.1%
StringHasherBenchmark.CityHash64(Shape: NonAscii) 22.06 μs 20.5 ns 22.03 μs +0.1%
StringHasherBenchmark.MetroHash64(Shape: NonAscii) 25.65 μs 15.8 ns 25.66 μs -0.0%
StringHasherBenchmark.SipHash13(Shape: NonAscii) 36.96 μs 84.2 ns 36.95 μs +0.0%
StringHasherBenchmark.SipHash24(Shape: NonAscii) 51.60 μs 624.7 ns 51.42 μs +0.4%
StringHasherBenchmark.HalfSipHash24(Shape: NonAscii) 73.05 μs 735.6 ns 73.24 μs -0.3%
StringHasherBenchmark.HighwayHash64(Shape: NonAscii) 514.09 μs 2.87 μs 516.61 μs -0.5%
IntegerHasherBenchmark.Guid_Bcl 1.66 μs 2.7 ns 1.61 μs +2.7%
IntegerHasherBenchmark.Guid_EqualityComparer 2.07 μs 15.6 ns 2.00 μs +3.4%
IntegerHasherBenchmark.Guid_Celerity 4.85 μs 33.1 ns 4.85 μs +0.1%
IntegerHasherBenchmark.Int32_Bcl 843.0 ns 5.4 ns 822.4 ns +2.5%
IntegerHasherBenchmark.Int32_EqualityComparer 885.9 ns 2.2 ns 862.5 ns +2.7%
IntegerHasherBenchmark.Int32_Identity 845.6 ns 5.1 ns 825.5 ns +2.4%
IntegerHasherBenchmark.Int32_WangNaive 1.35 μs 7.6 ns 1.32 μs +2.2%
IntegerHasherBenchmark.Int32_Wang 2.95 μs 21.3 ns 2.89 μs +1.9%
IntegerHasherBenchmark.Int32_Murmur3 2.15 μs 5.0 ns 2.10 μs +2.6%
IntegerHasherBenchmark.Int64_Bcl 1.34 μs 2.3 ns 1.32 μs +1.9%
IntegerHasherBenchmark.Int64_EqualityComparer 1.35 μs 2.8 ns 1.32 μs +2.2%
IntegerHasherBenchmark.Int64_Identity 854.5 ns 1.5 ns 835.3 ns +2.3%
IntegerHasherBenchmark.Int64_WangNaive 1.99 μs 4.0 ns 1.96 μs +1.8%
IntegerHasherBenchmark.Int64_Wang 3.95 μs 8.5 ns 3.88 μs +2.0%
IntegerHasherBenchmark.Int64_Murmur3 2.29 μs 4.6 ns 2.24 μs +1.9%
IntegerHasherBenchmark.UInt32_Bcl 835.1 ns 2.6 ns 826.9 ns +1.0%
IntegerHasherBenchmark.UInt32_EqualityComparer 879.1 ns 3.6 ns 866.1 ns +1.5%
IntegerHasherBenchmark.UInt32_Default 1.35 μs 5.2 ns 1.32 μs +1.9%
IntegerHasherBenchmark.UInt32_Wang 2.94 μs 15.2 ns 2.89 μs +1.7%
IntegerHasherBenchmark.UInt32_Murmur3 2.13 μs 9.3 ns 2.10 μs +1.4%
IntegerHasherBenchmark.UInt64_Bcl 1.33 μs 5.7 ns 1.31 μs +1.1%
IntegerHasherBenchmark.UInt64_EqualityComparer 1.34 μs 2.9 ns 1.33 μs +1.2%
IntegerHasherBenchmark.UInt64_Default 2.27 μs 5.0 ns 2.24 μs +1.2%
IntegerHasherBenchmark.UInt64_Wang 3.93 μs 14.1 ns 3.89 μs +1.0%
IntegerHasherBenchmark.UInt64_WangNaive 1.96 μs 6.8 ns 1.96 μs -0.1%

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

…ix) prefix search & longest-prefix match

The BCL ships no trie. `Dictionary<string, TValue>` answers exact-key lookups but has no
efficient prefix operation. `Trie<TValue>` maps string keys to values as a shared-prefix tree:

- `GetByPrefix` / `GetKeysWithPrefix` — every entry under a prefix in O(prefix + matches),
  ascending key order (autocomplete, namespace/route listing).
- `TryGetLongestPrefix` — the longest stored key that is a prefix of a query in O(query)
  (routing tables, tokenizer/dictionary matching).
- Ordered iteration for free; implements IReadOnlyDictionary<string, TValue>.

Nodes keep child edges in arrays sorted by edge char (binary-search lookup, ordered walk);
removal prunes dead paths bottom-up. The empty string is a valid key. Not thread-safe.

Full parity rollout in one PR: dedicated tests (Tests/Prefix/Enumeration/Differential vs a
SortedDictionary ordinal oracle), TrieBenchmark + Program.cs registration, dashboard wiring
(web/index.html + bench index/detail), docs (collections.md + README list/decision-table/
quick-start), and CHANGELOG. The int-keyed hash-family shared suites do not apply (same as
Deque/DisjointSet); the roadmap has no Trie item to flip (post-roadmap tier-c enhancement).

Closes #285.

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

- Snapshot the enumerator version at enumerable/enumerator creation (GetEnumerator /
  GetByPrefix / Keys / Values) and pass it into the DFS, so a mutation between handing out
  the sequence and the first MoveNext is detected on that first MoveNext (BCL-style), not one
  item late. Adds a leading version check + a covering test.
- Annotate the non-interface out-params: Remove(out TValue?) and
  TryGetLongestPrefix(out string? key, out TValue? value), assigning plain null/default on the
  false path. TryGetValue keeps the IReadOnlyDictionary-matched signature (avoids CS8767).
- Fix the misleading null-key exception in the bulk constructor and the stale "arrays are null"
  Node comment.
- Condense the CHANGELOG [Unreleased] entry to one user-facing bullet per the CONTRIBUTING /
  CLAUDE.md brevity rule (the full rollout detail lives in the PR body).

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

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

Comment thread src/Celerity/Collections/Trie.cs
Comment thread docs/api/collections.md Outdated
Copilot AI review requested due to automatic review settings July 21, 2026 20:22

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

Comment thread src/Celerity/Collections/Trie.cs Outdated
Comment thread src/Celerity/Collections/Trie.cs
Comment thread docs/api/collections.md Outdated
…ersion-check missing-prefix stream, doc nullability

- TryGetLongestPrefix reuses the query string on an exact match and string.Empty on the
  empty-key match, so only a proper interior prefix allocates a Substring copy.
- GetByPrefix now routes a missing prefix through the same version-checked walk (Enumerate
  accepts a nullable start), so an empty prefix result honours the enumerator-invalidation
  contract like a matching one instead of returning a bare Enumerable.Empty.
- Update the docs method table to the actual out-param nullability
  (TryGetLongestPrefix / Remove: out string? / out TValue?).
- Tests: exact/empty match reuse the source string (ReferenceEquals); a missing-prefix stream
  still throws when the trie is modified mid-enumeration.

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

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

Comments suppressed due to low confidence (1)

CHANGELOG.md:9

  • The new changelog entry is quite long and reads more like a mini-design doc. CONTRIBUTING.md asks for changelog bullets to be “a few sentences at most” and user-facing (the release workflow copies the whole section into the GitHub Release body).

Please shorten this entry to the user-visible addition and keep the details in the PR description/docs.

- **`Trie<TValue>`** in `Celerity.Collections` — an ordered prefix tree mapping `string` keys to values, filling a BCL gap (.NET ships no trie). `GetByPrefix` lists every entry whose key starts with a prefix in `O(prefix + matches)` and in ascending key order, and `TryGetLongestPrefix` finds the longest stored key that is a prefix of a query in `O(query)` — the autocomplete, longest-prefix-routing, and ordered-iteration workloads a `Dictionary<string, TValue>` can only answer with an `O(n)` scan plus a `StartsWith` per key. Exact `Add` / `TryGetValue` favour a `Dictionary`, so the trie earns its place on the prefix operations. Implements `IReadOnlyDictionary<string, TValue>`; not thread-safe. Closes [#285](https://github.com/marius-bughiu/Celerity/issues/285).

Comment thread src/Celerity/Collections/Trie.cs Outdated
Comment thread src/Celerity/Collections/Trie.cs Outdated
Comment thread src/Celerity/Collections/Trie.cs Outdated
Comment thread README.md Outdated
…vention, drop LINQ

- Implement IReadOnlyDictionary<string, TValue?> (was TValue), matching CelerityDictionary
  and the rest of the dictionary surface: public getters stay non-null (TValue), the nullable
  interface indexer is provided explicitly, and TryGetValue / Values / GetEnumerator now carry
  the TValue? annotation. Resolves the README "all dictionaries implement ...TValue?" tension.
- Replace the two LINQ Select usages (GetKeysWithPrefix, Values) — the only LINQ in
  src/Celerity/Collections — with plain iterator helpers (EnumerateKeys / EnumerateValues),
  keeping the eager version snapshot.
- Update docs/README to IReadOnlyDictionary<string, TValue?>.

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

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

Comment thread docs/api/collections.md Outdated
Comment thread docs/api/collections.md Outdated
Comment thread docs/api/collections.md Outdated
Comment thread docs/api/collections.md Outdated
Comment thread CHANGELOG.md Outdated
…surface

Follow-up to the IReadOnlyDictionary<string, TValue?> switch: the docs method table
still showed the pre-change non-nullable signatures and the changelog still said
IReadOnlyDictionary<string, TValue>. Align them:
- TryGetValue -> out TValue? value
- GetByPrefix -> IEnumerable<KeyValuePair<string, TValue?>>
- Values -> IEnumerable<TValue?>
- GetEnumerator -> IEnumerator<KeyValuePair<string, TValue?>>
- CHANGELOG: implements IReadOnlyDictionary<string, TValue?>

(The public indexer getter and the constructor input stay TValue, matching the code.)

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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 6 comments.

Comments suppressed due to low confidence (1)

docs/api/collections.md:3522

  • Trie<TValue>.TryGetLongestPrefix is declared with nullable out parameters (out string? key, out TValue? value). Using out string route, out string handler in the example implies non-nullable outs and will produce nullable-mismatch warnings for consumers who copy/paste. Update the example to use string? outs to match the API.
if (routes.TryGetLongestPrefix("/api/v1/users/42", out string route, out string handler))

Comment thread src/Celerity.Tests/Collections/TriePrefixTests.cs Outdated
Comment thread src/Celerity.Tests/Collections/TriePrefixTests.cs Outdated
Comment thread src/Celerity.Tests/Collections/TriePrefixTests.cs Outdated
Comment thread src/Celerity.Tests/Collections/TrieDifferentialTests.cs Outdated
Comment thread README.md Outdated
Comment thread src/Celerity/Collections/Trie.cs
… leaf enumeration allocs

- Test call sites and the README quick-start now declare the TryGetLongestPrefix key out-param
  as `string?` (matching the API), and the README example guards on the bool return — no more
  nullable-mismatch warnings and it demonstrates correct usage.
- Enumerate short-circuits when the start node has no children (empty trie, or a prefix landing
  on a leaf key), skipping the StringBuilder + Stack allocation on those common small cases.

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

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

Comment thread src/Celerity/Collections/Trie.cs
Comment thread src/Celerity/Collections/Trie.cs
Comment thread src/Celerity/Collections/Trie.cs
Comment thread src/Celerity/Collections/Trie.cs
Comment thread src/Celerity/Collections/Trie.cs Outdated
Comment thread src/Celerity/Collections/Trie.cs Outdated
Copilot AI review requested due to automatic review settings July 22, 2026 06:31

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

Comments suppressed due to low confidence (1)

src/Celerity/Collections/Trie.cs:465

  • Keys/Values are exposed as IEnumerable<...> sequences backed by iterator blocks, which means iterating them allocates an iterator state machine (and in Keys also the traversal stack/StringBuilder used by Enumerate). In this codebase, dictionary-like collections typically expose lightweight struct KeyCollection/ValueCollection views to avoid per-iteration allocations (e.g. CelerityDictionary’s Keys/Values). Consider adding non-allocating view types here too (even if traversal still needs a pooled stack), and keep the IReadOnlyDictionary members as explicit interface implementations if needed.
    /// <summary>Gets the keys in ascending ordinal order.</summary>
    public IEnumerable<string> Keys => GetKeysWithPrefix(string.Empty);

    /// <summary>Gets the values ordered by their keys' ascending ordinal order.</summary>
    public IEnumerable<TValue?> Values => EnumerateValues(_root, _version);

Comment thread src/Celerity/Collections/Trie.cs Outdated
Comment thread src/Celerity.Benchmarks/TrieBenchmark.cs
…line

- GetEnumerator() now returns a public struct Enumerator (like Deque / DisjointSet /
  CelerityDictionary), so `foreach` over a Trie avoids the compiler-generated iterator
  state-machine allocation and enumerator boxing. The struct is the single traversal source:
  the internal Enumerate IEnumerable (for the GetByPrefix / Keys streams) now drives it, so the
  pre-order walk and modification detection live in one place. It lazily allocates its stack /
  StringBuilder only when the start node has children, preserving the leaf/empty fast path.
  Node is now `internal` (was private) so the public struct can name it as a ctor parameter.
- TrieBenchmark: pre-size the Dictionary_Add baseline to ItemCount so the Add category measures
  per-insert cost rather than the dictionary's resize/rehash growth (matching sibling benchmarks).
- Tests: struct-enumerator foreach / Reset / Dispose, single-leaf enumeration, and Reset-throws-
  on-modification.

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

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

Comments suppressed due to low confidence (1)

CHANGELOG.md:9

  • The new CHANGELOG entry under [Unreleased] is much longer than the contributor guidance (“a few sentences at most”). Since the release workflow extracts the entire version section as the GitHub Release body, keeping this bullet tighter helps avoid release-size issues and keeps the changelog more scannable.
- **`Trie<TValue>`** in `Celerity.Collections` — an ordered prefix tree mapping `string` keys to values, filling a BCL gap (.NET ships no trie). `GetByPrefix` lists every entry whose key starts with a prefix in `O(prefix + matches)` and in ascending key order, and `TryGetLongestPrefix` finds the longest stored key that is a prefix of a query in `O(query)` — the autocomplete, longest-prefix-routing, and ordered-iteration workloads a `Dictionary<string, TValue>` can only answer with an `O(n)` scan plus a `StartsWith` per key. Exact `Add` / `TryGetValue` favour a `Dictionary`, so the trie earns its place on the prefix operations. Implements `IReadOnlyDictionary<string, TValue?>`; not thread-safe. Closes [#285](https://github.com/marius-bughiu/Celerity/issues/285).

Comment thread docs/api/collections.md
…e API reference

Mirror the note already in the type remarks: the O(prefix + matches) / O(query) forms
count a character step as O(1), which is strictly O(log b) per node (constant for a
bounded alphabet).

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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment thread src/Celerity/Collections/Trie.cs Outdated
…eset to 0

The field is bumped on every post-construction mutation; the bulk-load constructor resets it
to 0 after populating (no enumerator can exist during construction). Comment-only.

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

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

Comments suppressed due to low confidence (1)

CHANGELOG.md:9

  • This changelog bullet is much longer than the repo’s stated guideline (“a few sentences at most” and user-facing). Consider shortening it to a concise description of the new collection and its key capabilities, leaving the detailed rationale/complexity discussion to the PR description/docs.
- **`Trie<TValue>`** in `Celerity.Collections` — an ordered prefix tree mapping `string` keys to values, filling a BCL gap (.NET ships no trie). `GetByPrefix` lists every entry whose key starts with a prefix in `O(prefix + matches)` and in ascending key order, and `TryGetLongestPrefix` finds the longest stored key that is a prefix of a query in `O(query)` — the autocomplete, longest-prefix-routing, and ordered-iteration workloads a `Dictionary<string, TValue>` can only answer with an `O(n)` scan plus a `StartsWith` per key. Exact `Add` / `TryGetValue` favour a `Dictionary`, so the trie earns its place on the prefix operations. Implements `IReadOnlyDictionary<string, TValue?>`; not thread-safe. Closes [#285](https://github.com/marius-bughiu/Celerity/issues/285).

Comment thread docs/api/collections.md Outdated
Match the actual API (public struct Enumerator, added in the struct-enumerator change) and the
way every other collection's enumerator is documented in this file.

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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comments suppressed due to low confidence (1)

CHANGELOG.md:9

  • This [Unreleased] changelog entry is significantly longer than the repo guideline (“a few sentences at most”); overlong entries can also break the release workflow that uses the full section as the GitHub Release body. Consider condensing to 1–2 user-facing sentences and leaving implementation/perf nuance to the PR description.
- **`Trie<TValue>`** in `Celerity.Collections` — an ordered prefix tree mapping `string` keys to values, filling a BCL gap (.NET ships no trie). `GetByPrefix` lists every entry whose key starts with a prefix in `O(prefix + matches)` and in ascending key order, and `TryGetLongestPrefix` finds the longest stored key that is a prefix of a query in `O(query)` — the autocomplete, longest-prefix-routing, and ordered-iteration workloads a `Dictionary<string, TValue>` can only answer with an `O(n)` scan plus a `StartsWith` per key. Exact `Add` / `TryGetValue` favour a `Dictionary`, so the trie earns its place on the prefix operations. Implements `IReadOnlyDictionary<string, TValue?>`; not thread-safe. Closes [#285](https://github.com/marius-bughiu/Celerity/issues/285).

Comment thread README.md Outdated
…ter)

Written as IReadOnlySet<,> (two params); the interface is IReadOnlySet<T>. Corrected to
IReadOnlySet<>.

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

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

Comments suppressed due to low confidence (1)

CHANGELOG.md:9

  • The new [Unreleased] changelog bullet is longer than the contributor guideline (“a few sentences at most”) and increases the risk of release-body size issues (the release workflow uses the full section verbatim). Please condense to a short, user-facing summary of the observable capability and why it matters.
- **`Trie<TValue>`** in `Celerity.Collections` — an ordered prefix tree mapping `string` keys to values, filling a BCL gap (.NET ships no trie). `GetByPrefix` lists every entry whose key starts with a prefix in `O(prefix + matches)` and in ascending key order, and `TryGetLongestPrefix` finds the longest stored key that is a prefix of a query in `O(query)` — the autocomplete, longest-prefix-routing, and ordered-iteration workloads a `Dictionary<string, TValue>` can only answer with an `O(n)` scan plus a `StartsWith` per key. Exact `Add` / `TryGetValue` favour a `Dictionary`, so the trie earns its place on the prefix operations. Implements `IReadOnlyDictionary<string, TValue?>`; not thread-safe. Closes [#285](https://github.com/marius-bughiu/Celerity/issues/285).

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

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

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

Full suite green after the merge: 4413 passed, 0 failed.
@marius-bughiu
marius-bughiu deleted the feat/issue-285-trie branch July 24, 2026 22:45
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 Trie<TValue> — ordered prefix tree with O(prefix) prefix search and longest-prefix match

2 participants