- It is fully based on unmanaged memory, allowing developers to manipulate memory with lower overhead and more control, while offering a wide range of container types.
- The library provides extensive support for
Span<T>andunsafeoperations, making it suitable for scenarios with strict performance and memory behavior requirements.
- ✅ GC-Free Allocation: Most container data is allocated using unmanaged memory, without relying on the CLR garbage collector.
- ✅ High Performance: Compact structures, memory alignment, zero boxing, and support for high-performance algorithms.
- ✅ Span Support: Most containers support
Span<T>/ReadOnlySpan<T>, enabling in-place modification and zero-copy data passing. - ✅ Thread-Safe Containers: Includes several concurrent container variants suitable for multithreaded environments.
- ✅ Easy Integration: Uses standard C#, making it easy to replace existing containers.
Most containers in the standard library cannot be used in unmanaged environments, and many lack support for Span<T> or ReadOnlySpan<T>.
For example:
List<T>does not allow fast access viaSpan<T>orReadOnlySpan<T>, which limits both performance and development efficiency.- In older versions of .NET,
Dictionary<TKey, TValue>does not expose direct references to values, requiring operations to be performed on copies instead. This adds unnecessary overhead in performance-critical scenarios. - In many cases, types like
stringare overkill when only aReadOnlySpan<char>is needed. By usingNativeString, it’s possible to avoid frequent string allocations and reduce GC pressure significantly.
- All containers are value types or wrap unmanaged pointers. Please avoid using them before proper initialization to prevent undefined behavior.
- Most containers require calling
Dispose()after use to free unmanaged resources properly. - Usage of most containers is very similar to the standard library counterparts, with added convenience methods like converting to
Span<T>orReadOnlySpan<T>. - For short-lived containers, you can take advantage of the
usingstatement to automatically callDispose(). - For
StackallocCollectionseries, you can use thestackallocsyntax. Alternatively, you can provide any fixed buffer from outside, such as unmanaged memory or fixed managed memory. - For
NativeCollectionseries, they act as wrappers around theUnsafeCollectionseries and additionally store a handle pointer for managing the underlying resource. - For
UnsafeCollectionseries, they do not store a handle pointer themselves and are implemented directly as structs, providing a more lightweight but less managed usage. - You can use
NativeMemoryAllocator.Customto override:public static void* AlignedAlloc(uint byteCount, uint alignment)public static void* AlignedAllocZeroed(uint byteCount, uint alignment)public static void AlignedFree(void* ptr)
- You can use
NativeHashCode.Customto override:public static int GetHashCode(ReadOnlySpan<byte> buffer).
- You can use
NativeString.Customto override:public static int GetHashCode(ReadOnlySpan<char> buffer).
This project is actively under development. Welcome your suggestions and feedback.
This project is licensed under the MIT License.
BitArrayConcurrentDictionary<TKey, TValue>ConcurrentHashSet<T>ConcurrentQueue<T>ConcurrentStack<T>Deque<T>Dictionary<TKey, TValue>HashSet<T>List<T>MemoryStreamOrderedDictionary<TKey, TValue>OrderedHashSet<T>PriorityQueue<TKey, TValue>Queue<T>SortedDictionary<TKey, TValue>SortedList<TKey, TValue>SortedSet<T>SparseSet<T>Stack<T>StringStringBuilder<T>