Files
crtr/Assets/Cryville/Common/Buffers/ListPool.cs
2022-09-30 17:32:21 +08:00

72 lines
2.4 KiB
C#

using System.Collections.Generic;
namespace Cryville.Common.Buffers {
/// <summary>
/// A resource pool that allows reusing instances of lists of type <typeparamref name="T" />.
/// </summary>
/// <typeparam name="T">The item type of the lists in the pool.</typeparam>
public class ListPool<T> {
private class Bucket : ObjectPool<List<T>> {
readonly int _size;
public Bucket(int size, int capacity) : base(capacity) {
_size = size;
}
protected override List<T> Construct() {
return new List<T>(_size);
}
}
Bucket[] _buckets;
/// <summary>
/// Creates an instance of the <see cref="ListPool{T}" /> class with the default maximum list size and bucket capacity.
/// </summary>
public ListPool() : this(0x40000000, 256) { }
/// <summary>
/// Creates an instance of the <see cref="ListPool{T}" /> class.
/// </summary>
/// <param name="maxSize">The maximum size of the lists in the pool.</param>
/// <param name="capacityPerBucket">The capacity of each bucket. The pool groups lists of similar sizes into buckets for faster access.</param>
public ListPool(int maxSize, int capacityPerBucket) {
if (maxSize < 16) maxSize = 16;
int num = GetID(maxSize) + 1;
_buckets = new Bucket[num];
for (int i = 0; i < num; i++) {
_buckets[i] = new Bucket(GetSize(i), capacityPerBucket);
}
}
/// <summary>
/// Rents a list of the specified size from the pool. The size of the list must not be changed when it is rented.
/// </summary>
/// <param name="size">The size of the list.</param>
/// <returns>A <see cref="List{T}" /> of the specified size.</returns>
public List<T> Rent(int size) {
int len2 = size;
if (len2 < 16) len2 = 16;
var list = _buckets[GetID(len2)].Rent();
if (list.Count < size)
for (int i = list.Count; i < size; i++) list.Add(default(T));
else if (list.Count > size)
list.RemoveRange(size, list.Count - size);
return list;
}
/// <summary>
/// Returns a rented list to the pool.
/// </summary>
/// <param name="list">The list to return.</param>
public void Return(List<T> list) {
int len2 = list.Capacity;
if (len2 < 16) len2 = 16;
_buckets[GetID(len2)].Return(list);
}
static int GetID(int size) {
size -= 1;
size >>= 4;
int num = 0;
for (; size != 0; size >>= 1) num++;
return num;
}
static int GetSize(int id) {
return 0x10 << id;
}
}
}