com.alicizax.unity.ui.exten.../Runtime/RecyclerView/ObjectPool/MixedObjectPool.cs

216 lines
5.9 KiB
C#
Raw Normal View History

2025-12-26 14:22:46 +08:00
namespace AlicizaX.UI
2025-05-28 19:37:38 +08:00
{
using System;
using System.Collections.Generic;
2025-12-26 14:22:46 +08:00
public class MixedObjectPool<T> : IMixedObjectPool<T> where T : class
2025-05-28 19:37:38 +08:00
{
private const int DEFAULT_MAX_SIZE_PER_TYPE = 10;
private readonly Dictionary<string, Stack<T>> entries;
private readonly Dictionary<string, int> typeSize;
private readonly Dictionary<string, int> activeCountByType;
private readonly Dictionary<string, int> peakActiveByType;
2025-05-28 19:37:38 +08:00
private readonly IMixedObjectFactory<T> factory;
private readonly int defaultMaxSizePerType;
private int hitCount;
private int missCount;
private int destroyCount;
2025-05-28 19:37:38 +08:00
public MixedObjectPool(IMixedObjectFactory<T> factory) : this(factory, DEFAULT_MAX_SIZE_PER_TYPE)
{
}
public MixedObjectPool(IMixedObjectFactory<T> factory, int defaultMaxSizePerType)
{
this.factory = factory;
this.defaultMaxSizePerType = defaultMaxSizePerType;
if (defaultMaxSizePerType <= 0)
{
throw new ArgumentException("The maxSize must be greater than 0.");
}
entries = new Dictionary<string, Stack<T>>(StringComparer.Ordinal);
typeSize = new Dictionary<string, int>(StringComparer.Ordinal);
activeCountByType = new Dictionary<string, int>(StringComparer.Ordinal);
peakActiveByType = new Dictionary<string, int>(StringComparer.Ordinal);
2025-05-28 19:37:38 +08:00
}
public T Allocate(string typeName)
{
Stack<T> stack = GetOrCreateStack(typeName);
if (stack.Count > 0)
2025-05-28 19:37:38 +08:00
{
T obj = stack.Pop();
hitCount++;
TrackAllocate(typeName);
2025-05-28 19:37:38 +08:00
return obj;
}
missCount++;
TrackAllocate(typeName);
2025-05-28 19:37:38 +08:00
return factory.Create(typeName);
}
public void Free(string typeName, T obj)
{
if (obj == null) return;
if (!factory.Validate(typeName, obj))
{
factory.Destroy(typeName, obj);
destroyCount++;
TrackFree(typeName);
2025-05-28 19:37:38 +08:00
return;
}
int maxSize = GetMaxSize(typeName);
Stack<T> stack = GetOrCreateStack(typeName);
factory.Reset(typeName, obj);
TrackFree(typeName);
if (stack.Count >= maxSize)
2025-05-28 19:37:38 +08:00
{
factory.Destroy(typeName, obj);
destroyCount++;
2025-05-28 19:37:38 +08:00
return;
}
stack.Push(obj);
2025-05-28 19:37:38 +08:00
}
public int GetMaxSize(string typeName)
{
if (typeSize.TryGetValue(typeName, out int size))
{
return size;
}
return defaultMaxSizePerType;
}
public void SetMaxSize(string typeName, int value)
{
typeSize[typeName] = value;
}
public void EnsureCapacity(string typeName, int value)
{
if (value <= 0)
{
throw new ArgumentOutOfRangeException(nameof(value));
}
int current = GetMaxSize(typeName);
if (value > current)
{
typeSize[typeName] = value;
}
2025-05-28 19:37:38 +08:00
}
public void Warm(string typeName, int count)
{
if (count <= 0)
{
return;
}
int maxSize = GetMaxSize(typeName);
if (count > maxSize)
{
count = maxSize;
}
Stack<T> stack = GetOrCreateStack(typeName);
while (stack.Count < count)
{
stack.Push(factory.Create(typeName));
}
}
public int GetActiveCount(string typeName)
{
return activeCountByType.TryGetValue(typeName, out int count) ? count : 0;
}
public int GetPeakActiveCount(string typeName)
{
return peakActiveByType.TryGetValue(typeName, out int count) ? count : 0;
}
public int HitCount => hitCount;
public int MissCount => missCount;
public int DestroyCount => destroyCount;
2025-05-28 19:37:38 +08:00
protected virtual void Clear()
{
foreach (var kv in entries)
{
string typeName = kv.Key;
Stack<T> stack = kv.Value;
2025-05-28 19:37:38 +08:00
if (stack == null || stack.Count <= 0) continue;
2025-05-28 19:37:38 +08:00
while (stack.Count > 0)
{
factory.Destroy(typeName, stack.Pop());
destroyCount++;
}
2025-05-28 19:37:38 +08:00
}
entries.Clear();
typeSize.Clear();
activeCountByType.Clear();
peakActiveByType.Clear();
2025-05-28 19:37:38 +08:00
}
public void Dispose()
{
Clear();
GC.SuppressFinalize(this);
}
private Stack<T> GetOrCreateStack(string typeName)
{
if (!entries.TryGetValue(typeName, out Stack<T> stack))
{
stack = new Stack<T>(GetMaxSize(typeName));
entries[typeName] = stack;
}
return stack;
}
private void TrackAllocate(string typeName)
{
int active = GetActiveCount(typeName) + 1;
activeCountByType[typeName] = active;
if (active > GetPeakActiveCount(typeName))
{
peakActiveByType[typeName] = active;
}
}
private void TrackFree(string typeName)
{
int active = GetActiveCount(typeName);
if (active > 0)
{
activeCountByType[typeName] = active - 1;
}
int recommendedMax = GetPeakActiveCount(typeName) + 1;
if (recommendedMax > GetMaxSize(typeName))
{
typeSize[typeName] = recommendedMax;
}
}
2025-05-28 19:37:38 +08:00
}
}