Skip to content

Commit 2d863bb

Browse files
Merge pull request #67 from marius-bughiu/docs/readme-usage-examples
Add Quick start usage examples to README
2 parents 9078f25 + c3adbe4 commit 2d863bb

2 files changed

Lines changed: 99 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ All notable changes to Celerity are documented here. This project follows [Keep
44

55
## [Unreleased]
66

7+
### Added
8+
9+
- `README.md` — new "Quick start" section with concrete, runnable usage examples for `IntDictionary`, `CelerityDictionary` (with `GuidHasher`, `StringFnV1AHasher`, `DefaultHasher<T>`), the sets (`IntSet`, `CeleritySet`), and the `IEnumerable<KeyValuePair<,>>` constructor. Covers indexer get/set, `TryAdd` / `Add` semantics, `TryGetValue`, removal, and bulk-load from a BCL `Dictionary<,>`. Closes the "Add usage examples to README" item from issue #15.
10+
711
## [1.1.2] - 2026-05-01
812

913
First successful 1.1.x publish. Tags `v1.1.0` and `v1.1.1` exist on the repository but never published to nuget.org: `v1.1.0` failed at deploy with HTTP 403 (NuGet API key had expired), and the follow-up `v1.1.1` failed with HTTP 401 because the trusted-publishing migration used the wrong NuGet account name (`marius-bughiu` instead of `marius.bughiu`). 1.1.2 is the same library code as the 1.1.0 tag plus the trusted-publishing migration with the correct user, shipped under a fresh version because the failed tags couldn't be cleanly recycled.

README.md

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,101 @@ Celerity is a .NET library that provides specialized high-performance collection
1313

1414
All dictionaries implement `IReadOnlyDictionary<TKey, TValue?>` and ship allocation-free struct enumerators, `Keys` / `Values` views, and an `IEnumerable<KeyValuePair<TKey, TValue>>` constructor. All collections handle `default(TKey)` (or zero for `int` / `long` keys, `null` for reference-type keys) out-of-band so it never collides with the empty-slot sentinel.
1515

16+
## Quick start
17+
18+
Install from NuGet:
19+
20+
```bash
21+
dotnet add package Celerity.Collections
22+
```
23+
24+
### `IntDictionary` — the int-keyed fast path
25+
26+
`IntDictionary<TValue>` defaults to `Int32WangNaiveHasher`, so most callers don't need to pick a hasher.
27+
28+
```csharp
29+
using Celerity.Collections;
30+
31+
var counts = new IntDictionary<int>();
32+
counts[42] = 1;
33+
counts[42]++; // indexer get/set
34+
counts.TryAdd(7, 100); // returns false if key already present, no overwrite
35+
counts.Add(8, 200); // throws ArgumentException if key already present
36+
37+
if (counts.TryGetValue(42, out var hits))
38+
Console.WriteLine(hits); // 2
39+
40+
counts.Remove(7);
41+
Console.WriteLine(counts.Count); // 2
42+
43+
// foreach is allocation-free — Enumerator is a struct.
44+
foreach (var kvp in counts)
45+
Console.WriteLine($"{kvp.Key} -> {kvp.Value}");
46+
```
47+
48+
The zero key is a legitimate value, not the empty-slot sentinel — `counts[0] = 99` round-trips correctly. `LongDictionary<TValue>` follows the exact same surface for `long` keys (defaulting to `Int64WangHasher`).
49+
50+
### `CelerityDictionary` — generic keys with a struct hasher
51+
52+
For non-`int`/`long` keys, pick a hasher from `Celerity.Hashing` (or supply your own). `DefaultHasher<T>` falls back to `EqualityComparer<T>.Default.GetHashCode()` for arbitrary types.
53+
54+
```csharp
55+
using Celerity.Collections;
56+
using Celerity.Hashing;
57+
58+
var byId = new CelerityDictionary<Guid, string, GuidHasher>();
59+
byId[Guid.NewGuid()] = "alice";
60+
61+
var byName = new CelerityDictionary<string, int, StringFnV1AHasher>();
62+
byName["bob"] = 1;
63+
64+
// DefaultHasher<T> works for any type but pays the EqualityComparer<T> dispatch.
65+
var byKey = new CelerityDictionary<DateOnly, string, DefaultHasher<DateOnly>>();
66+
byKey[DateOnly.FromDateTime(DateTime.UtcNow)] = "today";
67+
```
68+
69+
The hasher is a `struct` and is supplied as a generic constraint, so the JIT devirtualizes and inlines the `Hash()` call on the probe path.
70+
71+
### Sets
72+
73+
`IntSet` and `CeleritySet<T, THasher>` mirror the dictionary types for membership-only workloads.
74+
75+
```csharp
76+
using Celerity.Collections;
77+
using Celerity.Hashing;
78+
79+
var seen = new IntSet();
80+
seen.Add(1);
81+
seen.Add(2);
82+
Console.WriteLine(seen.Contains(1)); // true
83+
seen.Remove(2);
84+
85+
var visitedIds = new CeleritySet<Guid, GuidHasher>();
86+
visitedIds.TryAdd(Guid.NewGuid()); // returns true on first add, false on duplicate
87+
```
88+
89+
### Construct from an existing collection
90+
91+
The dictionaries accept any `IEnumerable<KeyValuePair<TKey, TValue>>`. When the source implements `ICollection<T>`, its `Count` is used to pre-size the backing storage so the bulk fill avoids resize work.
92+
93+
```csharp
94+
var bcl = new Dictionary<int, string> { [1] = "a", [2] = "b", [3] = "c" };
95+
var fast = new IntDictionary<string>(bcl);
96+
97+
var fromKvps = new CelerityDictionary<string, int, StringFnV1AHasher>(
98+
new[]
99+
{
100+
new KeyValuePair<string, int>("alice", 1),
101+
new KeyValuePair<string, int>("bob", 2),
102+
});
103+
```
104+
105+
Duplicate keys (including duplicate `default(TKey)` / zero-key entries) throw `ArgumentException`, matching BCL `Dictionary<,>` semantics.
106+
107+
### Custom hasher
108+
109+
Implement `IHashProvider<T>` as a `struct` to plug in your own hash function. See [Custom hashing](#custom-hashing) below for the contract and a worked example.
110+
16111
## Benchmarks
17112

18113
#### CelerityDictionary

0 commit comments

Comments
 (0)