InlineCollections 0.1.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package InlineCollections --version 0.1.0
                    
NuGet\Install-Package InlineCollections -Version 0.1.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="InlineCollections" Version="0.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="InlineCollections" Version="0.1.0" />
                    
Directory.Packages.props
<PackageReference Include="InlineCollections" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add InlineCollections --version 0.1.0
                    
#r "nuget: InlineCollections, 0.1.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package InlineCollections@0.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=InlineCollections&version=0.1.0
                    
Install as a Cake Addin
#tool nuget:?package=InlineCollections&version=0.1.0
                    
Install as a Cake Tool

.NET 8.0+ License: MIT Allocations: Zero Performance: Ultra--Low--Latency

⚡ InlineCollections

InlineCollections provides high-performance, zero-allocation collection primitives for .NET with a fixed capacity of 32 elements. The collections are implemented as ref struct types optimized for ultra-low latency scenarios where heap allocations must be eliminated.

🚀 Overview

InlineList32<T>, InlineStack32<T>, and InlineQueue32<T> provide stack-allocated storage via the InlineArray language feature (C# 12+), enabling:

  • ✨ Zero heap allocations for the fast path
  • 🏎️ Minimal GC pressure
  • 🎯 Predictable memory layout for cache optimization
  • 🛡️ High-throughput, low-latency execution

Positioning Statement: This library is not a general-purpose replacement for the standard BCL collections types. Standard collections are designed for flexibility and large datasets. InlineCollections are "surgical tools" designed for High-Performance hot-paths where the developer has a guaranteed bound on the number of elements (≤ 32) and must eliminate heap allocations to reduce GC pressure and latency.


🛠️ Getting Started

📦 Installation

Add the package to your project via .NET CLI:

dotnet add package InlineCollections

🚀 Quick Start & Usage

InlineCollections are ref struct types designed for stack allocation. They ensure Zero Heap Allocation for up to 32 elements.

using InlineCollections;

// Initialize on stack (Zero Allocation)
var list = new InlineList32<int>();

list.Add(10);
list.Add(20);

// High-performance iteration (Modify in-place via Span)
foreach (ref int item in list.AsSpan())
{
    item += 1; 
}

💡 Why this library exists

Standard .NET collections (List<T>, Stack<T>, Queue<T>) allocate on the heap, requiring GC overhead and cache misses for small working sets. In high-performance scenarios (real-time systems, game engines, network processors, serialization hotspots), this overhead is unacceptable. InlineCollections eliminates allocations by storing 32 elements inline within the struct itself.

Performance highlights

  • Zero Allocations — for up to 32 elements these collections avoid heap allocations.
  • 🗑️ Reduced GC Pressure — fewer short-lived allocations means fewer GC cycles and pauses.
  • ⚖️ Predictable Latency — bounded-capacity operations reduce variance in execution time.

✅ When to use

  • Hot-path code that creates many short-lived small collections
  • Real-time systems requiring predictable latency
  • Game engine frame-local processing
  • Network packet processing
  • Serialization/deserialization buffers
  • Stack frames with bounded depth

When to use (with subtle icons)

  • ⚡ Hot-path code that creates many short-lived small collections
  • ⏱️ Real-time systems requiring predictable latency
  • 🎮 Game engine frame-local processing (per-frame temporary buffers)
  • ⚡ Network packet processing and protocol parsing
  • 🔁 Serialization/deserialization buffers where allocations matter
  • 🧠 Stack-like or frame-local data with bounded depth

When NOT to use

  • Collections that routinely exceed 32 elements
  • Scenarios requiring thread-safety or concurrent access
  • Reference-type or nullable element types
  • When API compatibility with List<T> is required
  • Managed heap scenarios where GC pressure is not a primary concern

How it works

Memory model

Each collection type uses the InlineArray32<T> struct, which leverages the [InlineArray(32)] attribute to embed 32 elements directly inside the struct. This is a value-type collection stored on the stack (when not captured in a reference type).

  • Inline storage: 32 elements stored as struct fields
  • No heap allocation
  • ref struct semantics (no boxing, no reference storage)

Constraints

  • Unmanaged element types only (constraint: T : unmanaged, IEquatable<T>)
  • Fixed capacity of exactly 32 elements
  • Throws InvalidOperationException when capacity is exceeded
  • Value-type semantics: copies on assignment/parameter passing

Collections provided

InlineList32<T>

A list with a maximum capacity of 32 unmanaged elements.

Key methods:

  • Add(T item) — add to end; throws if full
  • TryAdd(T item) — add to end; returns false if full
  • AddRange(ReadOnlySpan<T> items) — bulk add
  • Insert(int index, T item) — insert at index
  • Remove(T item) — remove first occurrence
  • RemoveAt(int index) — remove by index
  • T this[int index] — indexer with ref return for in-place modification
  • Span<T> AsSpan() — get current elements as a span
  • Contains(T item) — linear search
  • Clear() — empty the list

Example:

var list = new InlineList32<int>();
list.Add(1);
list.Add(2);
list.Add(3);
int value = list[0];  // 1

var span = list.AsSpan();
foreach (var item in span) {
    Console.WriteLine(item);
}

foreach (var item in list) {
    Console.WriteLine(item);
}

InlineStack32<T>

LIFO (Last-In-First-Out) collection with maximum capacity of 32 elements.

Key methods:

  • Push(T item) — push to stack; throws if full
  • TryPush(T item) — push; returns false if full
  • T Pop() — pop and return; throws if empty
  • bool TryPop(out T result) — pop safely
  • ref T Peek() — return ref to top without removing; throws if empty
  • Span<T> AsSpan() — get all elements (in insertion order)
  • Clear() — empty the stack

Example:

var stack = new InlineStack32<int>();
stack.Push(10);
stack.Push(20);
stack.Push(30);

int top = stack.Pop();  // 30
int next = stack.Pop(); // 20

ref int peek = ref stack.Peek();
peek = 100;  // modify in-place

foreach (var item in stack) {
    Console.WriteLine(item);  // Iterates in reverse order (LIFO)
}

InlineQueue32<T>

FIFO (First-In-First-Out) collection with maximum capacity of 32 elements. Internally uses a circular buffer for O(1) enqueue/dequeue.

Key methods:

  • Enqueue(T item) — add to back; throws if full
  • TryEnqueue(T item) — add safely; returns false if full
  • T Dequeue() — remove and return from front; throws if empty
  • bool TryDequeue(out T result) — dequeue safely
  • ref T Peek() — return ref to front without removing; throws if empty
  • Clear() — empty the queue

Example:

var queue = new InlineQueue32<int>();
queue.Enqueue(1);
queue.Enqueue(2);
queue.Enqueue(3);

int first = queue.Dequeue();  // 1
int second = queue.Dequeue(); // 2

ref int front = ref queue.Peek();
front = 999;  // modify in-place

foreach (var item in queue) {
    Console.WriteLine(item);  // Iterates in FIFO order
}

Limitations and exceptions

  • Fixed capacity: Exactly 32 elements; exceeding capacity throws InvalidOperationException.
  • Unmanaged types only: T must satisfy T : unmanaged, IEquatable<T>.
  • Value semantics: Assignment and parameter passing copy the entire struct.
  • Struct size: Each collection is 32 * sizeof(T) bytes plus overhead. Large T types increase stack usage.
  • ref struct: Cannot be stored in fields of reference types or classes; cannot be boxed.
  • No null elements: Elements must be valid unmanaged values.
  • Exceptions:
    • InvalidOperationException — capacity exceeded or collection is empty (on Pop/Peek/Dequeue without Try- variant)
    • ArgumentOutOfRangeException — invalid index (RemoveAt)

Performance characteristics

All operations are O(1) constant time except:

  • Remove(T item) — O(n) linear search and shift
  • RemoveAt(int index) — O(n) shifts remaining elements
  • Insert(int index, T item) — O(n) shifts elements to the right

Indexer access (this[int index]) and Peek/Pop operations have zero bounds checking and are aggressively inlined.

For detailed benchmarks and comparisons with List<T>, Stack<T>, and Queue<T>, see docs/benchmarks.md.

Documentation

NuGet package (planned)

Once released, install via:

dotnet add package InlineCollections

Package name: InlineCollections Namespace: InlineCollections

Benchmarks

BenchmarkDotNet results comparing InlineCollections with standard BCL collections are available in the benchmarks/ directory. Run:

dotnet run --project benchmarks/InlineCollections.Benchmarks -c Release

Key findings:

  • Add operations: InlineList32 is 3-5x faster than List<T> for small collections (zero allocations)
  • Indexer access: Near-identical performance to List<T> (both use direct memory access)
  • Memory: Zero heap allocations vs one allocation for List<T>

See docs/benchmarks.md for full results.

What InlineCollections is

  • Optimized for hot paths in high-performance systems
  • Zero-allocation primitive for small collections
  • Reference-type performance with stack allocation semantics
  • Deterministic and cache-friendly

What InlineCollections is NOT

  • A replacement for List<T>, Stack<T>, or Queue<T>
  • A thread-safe or concurrent collection
  • A general-purpose data structure for arbitrary workloads
  • A garbage-collected or reference-type collection

Trade-offs

Inline vs heap

Inline (InlineCollections):

  • ✅ No allocation
  • ✅ Cache-friendly
  • ✅ Fast small operations
  • ❌ Fixed capacity
  • ❌ Struct copying cost
  • ❌ Stack size cost

Heap (List<T>):

  • ✅ Dynamic capacity
  • ✅ Unbounded growth
  • ✅ No copying (reference type)
  • ❌ Allocation overhead
  • ❌ GC pressure
  • ❌ Cache misses

Unsafe optimization

Bounds-checked (List<T>):

  • ✅ Safe by default
  • ❌ Branch misprediction overhead

Unchecked (InlineCollections):

  • ✅ 0 branches in hot loops
  • ✅ Faster indexing
  • ❌ Caller must ensure valid indices (in practice, usually guaranteed)

Contributing

Contributions are welcome. See CONTRIBUTING.md for guidelines on code style, tests, and benchmarks.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net8.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.2.0 87 3/3/2026
0.1.0 81 2/26/2026