AndanteSoft.ArrayPoolCollection
1.1.0
dotnet add package AndanteSoft.ArrayPoolCollection --version 1.1.0
NuGet\Install-Package AndanteSoft.ArrayPoolCollection -Version 1.1.0
<PackageReference Include="AndanteSoft.ArrayPoolCollection" Version="1.1.0" />
paket add AndanteSoft.ArrayPoolCollection --version 1.1.0
#r "nuget: AndanteSoft.ArrayPoolCollection, 1.1.0"
// Install AndanteSoft.ArrayPoolCollection as a Cake Addin #addin nuget:?package=AndanteSoft.ArrayPoolCollection&version=1.1.0 // Install AndanteSoft.ArrayPoolCollection as a Cake Tool #tool nuget:?package=AndanteSoft.ArrayPoolCollection&version=1.1.0
ArrayPoolCollection
A low-allocation collection library using pooled arrays
<a href="https://www.nuget.org/packages/AndanteSoft.ArrayPoolCollection"></a>
<a href="LICENSE">
</a>
<a href="https://www.nuget.org/packages/AndanteSoft.ArrayPoolCollection">
</a>
Basic Usage
// By using the `using` statement, it will be automatically returned to the pool.
using var dict = new ArrayPoolDictionary<int, string>();
// Can be used in the same way as a Dictionary
dict.Add(123, "Alice");
Console.WriteLine(dict[123]); // "Alice"
Install
ArrayPoolCollection can be installed from NuGet AndanteSoft.ArrayPoolCollection
.
dotnet add package AndanteSoft.ArrayPoolCollection
ArrayPoolCollection requires .NET Standard 2.1 or .NET 9. (There are performance benefits to using .NET 9 where possible.)
If you want to use it with MemoryPack, install AndanteSoft.ArrayPoolCollection.MemoryPack
instead.
Unity
Supported version: 2021.2 or later. (API Compatibility Level: .NET Standard 2.1)
My test environment is 6000.1.0b1.
Use NuGetForUnity to install.
Features
It provides the following collections, which are mostly compatible with the default collections:
ArrayPoolWrapper<T>
:T[]
ArrayPoolList<T>
:List<T>
ArrayPoolDictionary<TKey, TValue>
:Dictionary<TKey, TValue>
ArrayPoolHashSet<T>
:HashSet<T>
ArrayPoolStack<T>
:Stack<T>
ArrayPoolQueue<T>
:Queue<T>
ArrayPoolPriorityQueue<TElement, TPriority>
:PriorityQueue<TElement, TPriority>
They use ArrayPool<T>
for their internal arrays, and by calling Dispose()
when destroyed, they do not generate GC garbage.
These implement almost all APIs available as of .NET 9.
Therefore, it can also be used to utilize
PriorityQueue
, which was not available in the current Unity environment.
Example of Dictionary usage:
using var dict = new ArrayPoolDictionary<string, string>(new Utf8BytesComparer())
{
{ "Alice", "Supernova" }
};
// You can use GetAlternateLookup in Unity.
// Unfortunately, it is not a `allows ref struct` constraint, so
// `ReadOnlySpan<byte>` cannot be taken as an argument.
Debug.Log(dict["Alice"]); // "Supernova"
Debug.Log(dict.GetAlternateLookup<byte[]>()[Encoding.UTF8.GetBytes("Alice")]); // "Supernova"
private class Utf8BytesComparer : IEqualityComparer<string>, IAlternateEqualityComparer<byte[], string>
{
public string Create(byte[] alternate)
{
return Encoding.UTF8.GetString(alternate);
}
public bool Equals(byte[] alternate, string other)
{
return Encoding.UTF8.GetBytes(other).SequenceEqual(alternate);
}
public bool Equals(string x, string y)
{
return x.Equals(y);
}
public int GetHashCode(byte[] alternate)
{
return Encoding.UTF8.GetString(alternate).GetHashCode();
}
public int GetHashCode(string obj)
{
return obj.GetHashCode();
}
}
In addition, it implements the following alternative collections, although they have some differences in specifications:
ArrayPoolBits
:BitArray
Reason: It's an old collection and the design is old. For example,
And
andXor
returnsvoid
ββto indicate that they are mutable. Also,BitArray
only implementsICollection
(non-generic!), whileArrayPoolBits
implementsIList<bool>
.
Also implement an object pool:
ObjectPool
By utilizing this and reusing instances of ArrayPool***
, GC garbage can be completely eliminated.
This is also available in the pool of GameObjects in Unity.
// Get a dictionary from the pool
var dict = ObjectPool<ArrayPoolDictionary<int, string>>.Shared.Rent();
// The contents of the rented dictionary are undefined, so clear it.
dict.Clear();
// Then use it just like a normal Dictionary.
dict.Add(123, "Alice");
dict.Add(456, "Barbara");
dict.Add(789, "Charlotte");
Debug.Log($"{dict[123]}"); // "Alice"
// Return it when you're done using it
ObjectPool<ArrayPoolDictionary<int, string>>.Shared.Return(dict);
Example of pooling GameObject
in Unity:
var root = new GameObject("root");
// Create GameObjectPool
using var gameObjectPool = new ObjectPool<GameObject>(PooledObjectCallback<GameObject>.Create(
// OnInstantiate - create prefab
() =>
{
var go = GameObject.CreatePrimitive(PrimitiveType.Cube);
go.transform.SetParent(root.transform, false);
return go;
},
// OnRent - set active
go => go.SetActive(true),
// OnReturn - set inactive
go => go.SetActive(false),
// OnDestroy - destroy
go => Destroy(go)
));
// Generate a specified number of pieces in advance
gameObjectPool.Prewarm(16);
for (int i = 0; i < 64; i++)
{
// Rent & Return
var go = gameObjectPool.Rent();
go.transform.position = UnityEngine.Random.insideUnitSphere * 10;
UniTask.Delay(1000).ContinueWith(() => gameObjectPool.Return(go)).Forget();
await UniTask.Delay(50);
}
await UniTask.Delay(1000);
It also includes an efficient implementation of IBufferWriter<T>
that utilizes a pool.
ArrayPoolBufferWriter<T>
: Suitable for small or fixed size buffers.ArrayPoolSegmentedBufferWriter<T>
: Suitable for objects of variable length and larger than megabytes.
For usage, see the With MemoryPack section.
With MemoryPack
Collections can be serialized using MemoryPack.
// Call this once at the beginning
ArrayPoolCollectionRegisterer.Register();
using var list = new ArrayPoolList<string>()
{
"Alice", "Barbara", "Charlotte",
};
// Create IBufferWriter<byte>
using var writer = new ArrayPoolBufferWriter<byte>();
// Serialize the list
MemoryPackSerializer.Serialize(writer, list);
// Deserialize the list
var deserialized = MemoryPackSerializer.Deserialize<ArrayPoolList<string>>(writer.WrittenSpan);
// "Alice, Barbara, Charlotte"
Debug.Log(string.Join(", ", deserialized));
Notes:
ArrayPoolPriorityQueue
do not implementIEnumerable<T>
, so serialization requires the[MemoryPackAllowSerialize]
attribute.Comparer
of Dictionary/HashSet is not usually serializable, so it is not saved. If you want to save it, you need to overwrite it when serializing.
using var ignoreCase = new ArrayPoolDictionary<string, int>(StringComparer.OrdinalIgnoreCase)
{
{ "Alice", 16 },
};
byte[] bytes = MemoryPackSerializer.Serialize(ignoreCase);
// ---
var deserialized = new ArrayPoolDictionary<string, int>(StringComparer.OrdinalIgnoreCase);
MemoryPackSerializer.Deserialize(bytes, ref deserialized);
Debug.Log($"{deserialized["alice"]}"); // 16
Fork
Build
dotnet build
Run tests
dotnet test
Run benchmarks
dotnet run -c Release --project ArrayPoolCollection.Benchmarks
Publish
dotnet pack
License
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. 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 is compatible. 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. |
.NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.1 is compatible. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.1
- System.Runtime.CompilerServices.Unsafe (>= 6.1.0)
-
net9.0
- No dependencies.
NuGet packages (1)
Showing the top 1 NuGet packages that depend on AndanteSoft.ArrayPoolCollection:
Package | Downloads |
---|---|
AndanteSoft.ArrayPoolCollection.MemoryPack
A low-allocation collection library using pooled arrays (with MemoryPack) |
GitHub repositories
This package is not used by any popular GitHub repositories.