SwiftCollections Overview
SwiftCollections provides specialized .NET collections for hot paths where storage layout, allocation behavior, deterministic hashing, dense iteration, pooling, or spatial query performance matter more than broad general-purpose ergonomics.
Use the standard .NET collections first when the workload is ordinary. Reach for SwiftCollections when the code is already performance-sensitive, when a benchmark points at collection cost, or when the data model naturally fits one of the specialized containers below.
Browse the documentation site, core API reference, spatial query API, including FixedMathSharp integrations, or coverage report.
Design Goals
- Keep common operations low time complexity.
- Prefer contiguous storage and dense iteration where it improves cache behavior.
- Avoid hidden allocations in simulation and query hot paths.
- Keep APIs framework-agnostic and usable from .NET, game engines, tools, and servers.
- Preserve deterministic-friendly behavior where the collection owns hashing or ordering choices.
- Keep serialization explicit through state-backed types and package variants.
Core Collections
| Type | Primary Role | Notes |
|---|---|---|
SwiftList<T> |
Dynamic contiguous list | Familiar list shape with SwiftCollections growth, span helpers, and explicit SortInPlace scratch-buffer sorting. |
SwiftQueue<T> |
Circular-buffer queue | Suited for repeated enqueue/dequeue workloads. |
SwiftStack<T> |
Array-backed stack | Simple LIFO storage for low-overhead stack workloads. |
SwiftSortedList<T> |
Sorted dynamic collection | Keeps values ordered for search and ordered iteration. |
SwiftDictionary<TKey, TValue> |
Hash table key/value lookup | Uses deterministic default string comparers when no comparer is supplied. |
SwiftHashSet<T> |
Hash table set membership | Uses deterministic default string comparers when no comparer is supplied. |
SwiftBiDictionary<TLeft, TRight> |
Two-way lookup | Maintains forward and reverse mappings. |
SwiftDictionary<TKey, TValue> and SwiftHashSet<T> are the closest
alternatives to Dictionary<TKey, TValue> and HashSet<T>. They are not
intended as blind drop-in replacements. Benchmark the workload you care about,
especially when custom comparers, string keys, collision behavior, or
trim/resize patterns are important.
Specialized Containers
| Use case | Better fit | Why |
|---|---|---|
| Store this object and give me a stable slot | SwiftBucket<T> |
The container owns integer slot assignment and can reuse freed slots. |
| Store this object and protect against stale references | SwiftGenerationalBucket<T> |
Handles include index plus generation, so reused slots invalidate old handles. |
| I already have a compact non-negative int ID; track membership | SwiftSparseSet |
Sparse lookup plus dense key storage gives O(1) membership and dense iteration. |
| I already have a compact non-negative int ID; attach a value | SwiftSparseMap<T> |
Sparse lookup maps external IDs to densely stored values. |
| I need dense unique-value iteration with hash-backed membership | SwiftPackedSet<T> |
Values are packed for iteration while membership remains hash-backed. |
| IDs are arbitrary, huge, or widely sparse | SwiftHashSet<int> / SwiftDictionary<int, T> |
Hash tables avoid allocating sparse arrays up to the highest ID. |
Sparse containers are strongest when IDs are compact, non-negative, and externally owned by a simulation, ECS, partition, or handle system. Their memory usage scales with the highest stored ID, not only with the number of live IDs.
SwiftSparseSet and SwiftSparseMap<T> can copy dense keys into caller-owned
SwiftList<int> buffers, including sorted ascending export through
CopySortedKeysTo(...). Use that path for deterministic per-frame scratch
ordering instead of building a persistent SwiftSortedList<T> solely to sort
transient keys.
Spatial Query Structures
The query namespace provides mutable broad-phase structures over typed bounds:
| Type | Best Fit |
|---|---|
SwiftBVH<TKey> / SwiftBVH<TKey, TVolume> |
Mixed-size objects, broad intersection queries, and heterogeneous scenes. |
SwiftSpatialHash<TKey> / SwiftSpatialHash<TKey, TVolume> |
High-churn scenes with mostly uniform object sizes and sparse query windows. |
SwiftOctree<TKey> / SwiftOctree<TKey, TVolume> |
Dynamic scenes with uneven density and repeated regional queries. |
The default wrappers use System.Numerics BoundVolume. The
SwiftCollections.FixedMathSharp package adds fixed-point wrappers for
deterministic simulations:
SwiftFixedBVH<TKey>SwiftFixedSpatialHash<TKey>SwiftFixedOctree<TKey>FixedBoundVolume
FixedBoundVolume normalizes its two supplied endpoints and delegates derived
metadata to FixedBoundBox. Centers therefore use a full-domain nearest-even
midpoint. Fixed octree subdivision compares each prospective child span in raw
unsigned space, so even the complete scalar domain can be partitioned without
materializing an unrepresentable full size. Reading Size or Volume throws
OverflowException when an exact positive component span cannot fit in
Fixed64; it never substitutes a saturated under-size.
SwiftFixedSpatialHash<TKey>.GetCellIndex(...) exposes the hash's exact Q32.32
floor mapping for callers that must classify bounds with the same cell contract.
CollectPointCandidates(...) appends every entry from that mapped cell into
caller-owned storage without exact-bound filtering; use Query(...) when exact
intersection results are required.
Fixed BVH insertion does not materialize Volume. Its insertion cost delegates
to FixedMathSharp's exact 192-bit union-volume growth metric and clamps only the
final public long cost, so third and later insertions remain deterministic
across full-domain unions.
Query structures are mutable runtime indexes. Treat them as single-owner structures unless you add synchronization externally.
Pools
SwiftCollections includes general and typed pool helpers:
SwiftObjectPool<T>SwiftArrayPool<T>SwiftCollectionPool<TCollection, TItem>- typed pool helpers for
SwiftList<T>,SwiftQueue<T>,SwiftHashSet<T>,SwiftDictionary<TKey, TValue>,SwiftStack<T>,SwiftPackedSet<T>, andSwiftSparseMap<T>
Pools are useful when collection instances are repeatedly rented, cleared, and reused across simulation frames or query batches.
Observable Collections
Observable collections are intended for tooling, editor, diagnostics, or host-facing change tracking:
SwiftObservableArray<T>SwiftObservableList<T>SwiftObservableDictionary<TKey, TValue>SwiftObservableProperty<TValue>
Avoid using observable notifications in authoritative per-frame simulation paths unless the ordering and notification cost are explicitly tested and benchmarked.
Serialization
The standard packages include MemoryPack support where the source type is marked
with [MemoryPackable]. Lean packages compile the same collection APIs without
the MemoryPack dependency by using compatibility shims and excluding
MemoryPack-specific source.
Package variants:
SwiftCollectionsSwiftCollections.LeanSwiftCollections.FixedMathSharpSwiftCollections.FixedMathSharp.Lean
State-backed collection types expose explicit state structs such as
SwiftArrayState<T>, SwiftBucketState<T>,
SwiftDictionaryState<TKey, TValue>, SwiftGenerationalBucketState<T>, and
SwiftSparseMapState<T>.
Diagnostics
SwiftCollections.Diagnostics provides a small opt-in diagnostic surface:
DiagnosticChannelDiagnosticEventDiagnosticLevelSwiftCollectionDiagnostics.Shared- interpolated diagnostic handlers that avoid formatting when disabled
SwiftThrowHelperguard methods with caller-expression names, canonical default messages, and lazy interpolated exception messages for condition-gated throws
Diagnostics are disabled by default until a minimum level and sink are configured.
Development And Verification
Build:
dotnet build SwiftCollections.slnx -c Debug
Run tests:
dotnet test tests/SwiftCollections.Tests/SwiftCollections.Tests.csproj -c Debug --no-build
Run coverage:
dotnet test tests/SwiftCollections.Tests/SwiftCollections.Tests.csproj -c Debug --no-build --collect:"XPlat Code Coverage" --settings tests/SwiftCollections.Tests/coverlet.runsettings
List benchmark aliases:
dotnet run --project tests/SwiftCollections.Benchmarks/SwiftCollections.Benchmarks.csproj -c Release -f net8 -- list
Run selected benchmarks:
dotnet run --project tests/SwiftCollections.Benchmarks/SwiftCollections.Benchmarks.csproj -c Release -f net8 -- dictionary
dotnet run --project tests/SwiftCollections.Benchmarks/SwiftCollections.Benchmarks.csproj -c Release -f net8 -- query --list flat
dotnet run --project tests/SwiftCollections.Benchmarks/SwiftCollections.Benchmarks.csproj -c Release -f net8 -- all --list flat