Celerity.

High-performance .NET collections that beat the BCL on documented workloads.

Celerity ships specialised dictionaries and sets with struct-based hashers, zero-cost generic dispatch, and continuous performance tracking on every commit. If a type doesn't outperform its System.Collections.Generic counterpart on a real benchmark, it doesn't ship.

dotnet add package Celerity.Collections

Latest measurement vs .NET BCL

Full dashboard →
Lookup
vs Dictionary / HashSet
Insert
vs Dictionary / HashSet
Remove
vs Dictionary / HashSet

What ships in the box

IntDictionary<TValue>
int-keyed dictionary, default Wang hash.
LongDictionary<TValue>
long-keyed dictionary, default Wang hash.
CelerityDictionary<K, V, H>
Generic dictionary with a struct hasher constraint.
RobinHoodDictionary<K, V, H>
Robin Hood open addressing: bounded probe variance for clustered keys.
SwissDictionary<K, V, H>
Swiss-table SIMD group probing: one Vector128 compare tests 16 slots per lookup.
HashCachingDictionary<K, V, H>
Struct-of-arrays layout with a cached-fingerprint side array: probes scan metadata only and short-circuit expensive key equality.
PooledCelerityDictionary<K, V, H>
ArrayPool-backed, disposable dictionary that recycles its buffers to cut GC pressure.
FrozenCelerityDictionary<V>
Build-once string-keyed dictionary with perfect hashing for single-probe lookups.
CelerityMultiMap<K, V, H>
One-to-many map: each key groups multiple values. Implements ILookup.
CelerityMultiSet<T, H>
Counting multiset (bag): each element maps to its multiplicity. Single-probe Add for frequency counting.
SmallDictionary<K, V>
Flat-array, linear-scan dictionary tuned for the very-small (n ≤ ~16) case.
EnumMap<TEnum, V>
Dense array-backed dictionary for enum keys (the .NET EnumMap): a lookup is a direct array index — no hashing, no probing, no collisions. Ascending-value enumeration. The dictionary counterpart of EnumSet.
IntSet
int-keyed set, default Wang hash.
LongSet
long-keyed set, default Wang hash.
CeleritySet<T, H>
Generic set with a struct hasher constraint.
SwissSet<T, H>
Swiss-table SIMD group probing for sets: one Vector128 compare tests 16 slots per membership check, so negative lookups stay cheap. The set counterpart of SwissDictionary.
RobinHoodSet<T, H>
Robin Hood open addressing for sets: bounded probe variance and early-exit negative lookups on clustered elements. The set counterpart of RobinHoodDictionary.
HashCachingSet<T, H>
Struct-of-arrays layout with a cached-fingerprint side array for sets: probes scan metadata only and short-circuit expensive element equality. The set counterpart of HashCachingDictionary.
PooledCeleritySet<T, H>
ArrayPool-backed, disposable set that rents its backing array and returns it on Dispose, recycling buffers to cut GC pressure on short-lived, frequently-rebuilt sets. The set counterpart of PooledCelerityDictionary.
FrozenCeleritySet<H>
Build-once string set with perfect hashing for single-probe membership tests. Implements IReadOnlySet.
SmallSet<T>
Flat-array, linear-scan set tuned for the very-small (n ≤ ~16) case. No hasher; the default element is stored inline. The set counterpart of SmallDictionary.
EnumSet<TEnum>
Bit-vector set for enum keys (the .NET EnumSet): membership is a single bit test and set algebra is word-wise bitwise ops — no hashing, no boxing. Ascending-value enumeration.
SparseSet
Bounded-universe integer set (Briggs–Torczon sparse set): O(1) Clear that leaves the backing arrays untouched and dense, cache-friendly iteration — for clear-and-rebuild "visited" sets in graph / ECS / sweep-line code.
BloomFilter<T, H>
Probabilistic membership filter: bit-array storage, no false negatives, tunable false-positive rate. A fraction of a HashSet's memory.
CuckooFilter<T, H>
Probabilistic membership filter that supports deletion: fingerprint buckets, no false negatives, tunable false-positive rate, ≤2 cache lines per lookup. The Bloom filter you can Remove from.
XorFilter<T, H>
Probabilistic membership filter that is build-once & immutable: ~9.84 bits/element (smaller than a Bloom filter at the same rate), three probes + two XORs per lookup. The smallest, fastest-to-query filter for a fixed element set.
BitSet
Dense exact bit vector: O(n/64) population count and SIMD-accelerated bulk And/Or/Xor/Not over 64-bit words. A faster, count-aware BitArray.
HyperLogLog<T, H>
Probabilistic cardinality estimator: counts distinct elements in a fixed few KB with ~0.8% error, no matter how many you add. Mergeable; a fraction of a HashSet's memory.
CountMinSketch<T, H>
Probabilistic frequency estimator: estimates how often each element occurs from a fixed few KB, never underestimating. Mergeable; a fraction of a frequency-table Dictionary's memory.
TopKSketch<T, H>
Top-k / heavy-hitters sketch (Space-Saving): reports a stream's most frequent elements from a fixed k monitors, never underestimating. O(k) memory instead of one entry per distinct key.
LruCache<K, V, H>
Fixed-capacity least-recently-used cache with O(1) get/put and automatic eviction. Recency runs through an intrusive list over fixed arrays, so the hot get/put/evict path allocates nothing — unlike the idiomatic Dictionary+LinkedList LRU that allocates a node per insert.
Deque<T>
Growable double-ended queue backed by a circular buffer: O(1) push/pop/peek at both ends and O(1) random access. The array-backed deque the BCL lacks — a bounded churn allocates nothing (vs a node per op for LinkedList) and enumerates contiguous memory.
DisjointSet<T>
Union-find over arbitrary elements: partitions them into disjoint sets with near-O(1) amortized Union/Find/Connected via union-by-size and path halving. The union-find the BCL lacks — incremental connectivity, connected components, and Kruskal MST in near-linear time, where a Dictionary+HashSet set-merge is quadratic.
IndexedPriorityQueue<E, P, H>
Addressable binary min-heap: unlike the BCL PriorityQueue it can change a queued element's priority (Update / decrease-key) and remove an arbitrary element in O(log n), and answer Contains/TryGetPriority in O(1). The heap the priority-relaxation loop of Dijkstra / Prim / A* needs — no lazy-deletion heap growth.
Trie<TValue>
Ordered prefix tree mapping string keys to values: GetByPrefix lists every entry under a prefix in O(prefix + matches) and TryGetLongestPrefix finds the longest stored prefix of a query in O(query). The trie the BCL lacks — autocomplete, routing, and ordered iteration, where a Dictionary must scan every key and run StartsWith.
FenwickTree<T>
Binary Indexed Tree over a fixed-length numeric sequence: point update and prefix / range sum both in O(log n), in one array with no per-node overhead. The prefix-sum structure the BCL lacks — running aggregates, rank counters and cumulative-frequency tables, where a plain array is O(n) per query or O(n) per update.
BTreeDictionary<K, V, C>
Sorted map backed by a B-tree with up to 31 keys per node in flat arrays, so a lookup visits ~log32(n) nodes instead of chasing ~log2(n) pointers. The B-tree the BCL lacks — Min/Max, lower/upper bound and O(log n + k) range scans, where SortedDictionary is a red-black tree with an object per entry and SortedList memmoves on every insert.
BTreeSet<T, C>
The set counterpart: ordered elements packed 31 to a node, with the same ordered surface and an in-order walk over contiguous arrays instead of successor pointers. Beats SortedSet on the interleaved insert + membership + range-scan workload, and stores no values, so the memory saving is larger still.
Celerity.Hashing
Wang, Murmur3, FNV-1a, Guid, default fallback.

Built with Celerity

Standalone packages built on the core — add only the one you need
Celerity.Ring
Consistent-hash & rendezvous (HRW) rings for sharding and request routing. Byte-identical node assignment across OS, architecture, and runtime (x64, arm64, Blazor WASM), so every node in a cluster agrees on the mapping. Fills a gap the BCL has no type for. Separate NuGet package.
Celerity.Sentinel
Streaming abuse / heavy-hitter detection: top offenders, per-key rate, and fan-out cardinality of a request stream in a fixed footprint regardless of key cardinality, so it survives the attacker key-rotation that OOMs a Dictionary<,> counter. Separate NuGet package.
Celerity.Cardinality
Mergeable approximate COUNT(DISTINCT) and windowed dedup over unbounded streams: exact for small inputs, promoting to a fixed ~16 KB estimator, with deterministic cross-shard merge identical on every runtime. Separate NuGet package.

Design notes

Hashers are structs passed as generic constraints (where THasher : struct, IHashProvider<T>) so the JIT devirtualizes and inlines Hash() on the probe path. Dictionaries implement IReadOnlyDictionary<TKey, TValue>, ship allocation-free struct enumerators, and handle default(TKey) out-of-band so the zero / null key never collides with the empty-slot sentinel. Celerity is single-threaded and does not guarantee iteration order — if you need either, use ConcurrentDictionary<,> or stay on the BCL.