Skip to content

Commit c2c32b4

Browse files
committed
Add LongDictionary<TValue> for 64-bit keys
Mirrors the IntDictionary surface for `long` keys: convenience subclass defaulting to Int64WangHasher, generic LongDictionary<TValue, THasher> base class implementing IReadOnlyDictionary<long, TValue?>, struct Enumerator + KeyCollection / ValueCollection allocation-free views, the IEnumerable<KeyValuePair<long,TValue>> constructor, full Add/TryAdd/TryGetValue/Clear surface, and constructor validation. The zero key (0L) collides with the EMPTY_KEY sentinel exactly as on IntDictionary and is stored out-of-band via _hasZeroKey + _zeroValue. Tests mirror the IntDictionary coverage and add long-specific cases: extreme keys (long.MinValue / long.MaxValue / boundaries around the int range / -1L) and a regression test that two keys sharing the same lower 32 bits but differing in the upper 32 bits are kept distinct (guards against any accidental int-truncation on the probe path). Closes the last collection-shape gap on milestone 1.1.0.
1 parent 4378904 commit c2c32b4

4 files changed

Lines changed: 1152 additions & 1 deletion

File tree

CHANGELOG.md

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

77
### Added
88

9+
- `LongDictionary<TValue, THasher>` and the `LongDictionary<TValue>` convenience subclass — high-performance dictionary keyed by `long`, mirroring the `IntDictionary` surface for 64-bit keys. Defaults to `Int64WangHasher`. Implements `IReadOnlyDictionary<long, TValue?>`, ships allocation-free struct enumerator and `KeyCollection` / `ValueCollection` views, the `IEnumerable<KeyValuePair<long, TValue>>` constructor, full `Add` / `TryAdd` / `TryGetValue` / `Clear` surface, and constructor validation matching `IntDictionary`. The zero key (`0L`) collides with the `EMPTY_KEY` sentinel exactly as on `IntDictionary` and is stored out-of-band via a dedicated flag + value slot, so `map[0L] = x` is round-trippable. Closes the last collection-shape gap in milestone 1.1.0.
10+
- `LongDictionaryTests` — mirrors the `IntDictionaryTests` coverage (CRUD, zero-key, resize survival, remove-then-reinsert, constructor validation, `IEnumerable` constructor, `Add` / `TryAdd` duplicate semantics, struct-enumerator and `Keys` / `Values` views, and the boxed `IReadOnlyDictionary<long, TValue?>` surface) plus long-specific cases: extreme key values (`long.MaxValue`, `long.MinValue`, `int.MaxValue + 1L`, `int.MinValue - 1L`, `-1L`) and a regression test that two keys sharing the same lower 32 bits but differing in the upper 32 bits are kept distinct (guards against any accidental int-truncation on the probe path).
911
- `IEnumerable<KeyValuePair<TKey, TValue>>` constructor on both `CelerityDictionary<TKey, TValue, THasher>` and `IntDictionary<TValue, THasher>` (and the `IntDictionary<TValue>` convenience subclass). Matches BCL `Dictionary<,>` semantics: throws `ArgumentNullException` on a null source and `ArgumentException` on duplicate keys (including duplicate zero / default keys). When the source implements `ICollection<T>`, its `Count` is used to size the backing storage so the initial fill avoids at least some resize work; non-collection enumerables fall back to the caller-supplied `capacity` parameter. The out-of-band zero-key / default-key slot is populated correctly when the source contains an entry with `default(TKey)`. Completes the last of the milestone 1.1.0 API-parity items on the dictionaries.
1012
- `IEnumerableConstructorTests` — 28 tests covering null-source and invalid-load-factor validation, empty sources, array / list / non-collection enumerable sources, duplicate-key detection (including duplicate zero / default keys), zero-key and null-reference-key capture, 500-entry large-source round-trip, source-independence after construction, caller-specified capacity dominating the source count, cross-dictionary copy via `Select`, and projection through `IReadOnlyDictionary<,>` to verify the new ctor flows into the existing interface surface.
1113
- `IReadOnlyDictionary<TKey, TValue?>` implementation on both `CelerityDictionary<TKey, TValue, THasher>` and `IntDictionary<TValue, THasher>` — the dictionaries can now be passed to any API that accepts `IReadOnlyDictionary<,>` (LINQ, DI, BCL `ToDictionary`, etc.) without a wrapper. The implementation is a thin set of explicit interface forwarders on top of the existing struct `KeyCollection` / `ValueCollection` views and struct `Enumerator`, so the zero-allocation `foreach (var kvp in map)` / `foreach (var k in map.Keys)` fast paths remain unchanged and the interface path boxes the enumerator exactly once per call, matching BCL `Dictionary<,>` behaviour. The out-of-band default-key / zero-key entry is surfaced through every interface member (`ContainsKey`, `TryGetValue`, indexer, `Keys`, `Values`, generic `IEnumerable<KeyValuePair<TKey, TValue?>>`, and non-generic `IEnumerable`), and mid-enumeration mutation still throws `InvalidOperationException`. Closes issue #9; completes the last of the 1.1.0 API-parity collection work.

ROADMAP.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ The next release rounds out the `Celerity.Collections` package with missing coll
4242
### Collections
4343

4444
- Implement `CeleritySet<T, THasher>` — set counterpart to `CelerityDictionary`. (#16) Status: `done`.
45-
- Implement `LongDictionary<TValue>``IntDictionary` equivalent for `long` keys. (#17)
45+
- Implement `LongDictionary<TValue>``IntDictionary` equivalent for `long` keys. (#17) Status: `done`.
4646
- Implement `IReadOnlyDictionary<TKey, TValue>` on `CelerityDictionary` and `IntDictionary`. Status: `done`.
4747
- Add `Keys` / `Values` enumerable views and `GetEnumerator()`. Status: `done`.
4848
- Constructor accepting `IEnumerable<KeyValuePair<TKey, TValue>>`. Status: `done`.

0 commit comments

Comments
 (0)