using System;
using System.Collections.Generic;
using UnityEngine.Events;
namespace UnityEngine.Rendering
{
///
/// Generic object pool.
///
/// Type of the object pool.
public class ObjectPool where T : new()
{
readonly Stack m_Stack = new Stack();
readonly UnityAction m_ActionOnGet;
readonly UnityAction m_ActionOnRelease;
readonly bool m_CollectionCheck = true;
///
/// Number of objects in the pool.
///
public int countAll { get; private set; }
///
/// Number of active objects in the pool.
///
public int countActive { get { return countAll - countInactive; } }
///
/// Number of inactive objects in the pool.
///
public int countInactive { get { return m_Stack.Count; } }
///
/// Constructor.
///
/// Action on get.
/// Action on release.
/// True if collection integrity should be checked.
public ObjectPool(UnityAction actionOnGet, UnityAction actionOnRelease, bool collectionCheck = true)
{
m_ActionOnGet = actionOnGet;
m_ActionOnRelease = actionOnRelease;
m_CollectionCheck = collectionCheck;
}
///
/// Get an object from the pool.
///
/// A new object from the pool.
public T Get()
{
T element;
if (m_Stack.Count == 0)
{
element = new T();
countAll++;
}
else
{
element = m_Stack.Pop();
}
if (m_ActionOnGet != null)
m_ActionOnGet(element);
return element;
}
///
/// Pooled object.
///
public struct PooledObject : IDisposable
{
readonly T m_ToReturn;
readonly ObjectPool m_Pool;
internal PooledObject(T value, ObjectPool pool)
{
m_ToReturn = value;
m_Pool = pool;
}
///
/// Disposable pattern implementation.
///
void IDisposable.Dispose() => m_Pool.Release(m_ToReturn);
}
///
/// Get et new PooledObject.
///
/// Output new typed object.
/// New PooledObject
public PooledObject Get(out T v) => new PooledObject(v = Get(), this);
///
/// Release an object to the pool.
///
/// Object to release.
public void Release(T element)
{
#if UNITY_EDITOR // keep heavy checks in editor
if (m_CollectionCheck && m_Stack.Count > 0)
{
if (m_Stack.Contains(element))
Debug.LogError("Internal error. Trying to destroy object that is already released to pool.");
}
#endif
if (m_ActionOnRelease != null)
m_ActionOnRelease(element);
m_Stack.Push(element);
}
}
///
/// Generic pool.
///
/// Type of the objects in the pull.
public static class GenericPool
where T : new()
{
// Object pool to avoid allocations.
static readonly ObjectPool s_Pool = new ObjectPool(null, null);
///
/// Get a new object.
///
/// A new object from the pool.
public static T Get() => s_Pool.Get();
///
/// Get a new PooledObject
///
/// Output typed object.
/// A new PooledObject.
public static ObjectPool.PooledObject Get(out T value) => s_Pool.Get(out value);
///
/// Release an object to the pool.
///
/// Object to release.
public static void Release(T toRelease) => s_Pool.Release(toRelease);
}
///
/// Generic pool without collection checks.
/// This class is an alternative for the GenericPool for object that allocate memory when they are being compared.
/// It is the case for the CullingResult class from Unity, and because of this in HDRP HDCullingResults generates garbage whenever we use ==, .Equals or ReferenceEquals.
/// This pool doesn't do any of these comparison because we don't check if the stack already contains the element before releasing it.
///
/// Type of the objects in the pull.
public static class UnsafeGenericPool
where T : new()
{
// Object pool to avoid allocations.
static readonly ObjectPool s_Pool = new ObjectPool(null, null, false);
///
/// Get a new object.
///
/// A new object from the pool.
public static T Get() => s_Pool.Get();
///
/// Get a new PooledObject
///
/// Output typed object.
/// A new PooledObject.
public static ObjectPool.PooledObject Get(out T value) => s_Pool.Get(out value);
///
/// Release an object to the pool.
///
/// Object to release.
public static void Release(T toRelease) => s_Pool.Release(toRelease);
}
///
/// List Pool.
///
/// Type of the objects in the pooled lists.
public static class ListPool
{
// Object pool to avoid allocations.
static readonly ObjectPool> s_Pool = new ObjectPool>(null, l => l.Clear());
///
/// Get a new List
///
/// A new List
public static List Get() => s_Pool.Get();
///
/// Get a new list PooledObject.
///
/// Output typed List.
/// A new List PooledObject.
public static ObjectPool>.PooledObject Get(out List value) => s_Pool.Get(out value);
///
/// Release an object to the pool.
///
/// List to release.
public static void Release(List toRelease) => s_Pool.Release(toRelease);
}
///
/// HashSet Pool.
///
/// Type of the objects in the pooled hashsets.
public static class HashSetPool
{
// Object pool to avoid allocations.
static readonly ObjectPool> s_Pool = new ObjectPool>(null, l => l.Clear());
///
/// Get a new HashSet
///
/// A new HashSet
public static HashSet Get() => s_Pool.Get();
///
/// Get a new list PooledObject.
///
/// Output typed HashSet.
/// A new HashSet PooledObject.
public static ObjectPool>.PooledObject Get(out HashSet value) => s_Pool.Get(out value);
///
/// Release an object to the pool.
///
/// hashSet to release.
public static void Release(HashSet toRelease) => s_Pool.Release(toRelease);
}
///
/// Dictionary Pool.
///
/// Key type.
/// Value type.
public static class DictionaryPool
{
// Object pool to avoid allocations.
static readonly ObjectPool> s_Pool
= new ObjectPool>(null, l => l.Clear());
///
/// Get a new Dictionary
///
/// A new Dictionary
public static Dictionary Get() => s_Pool.Get();
///
/// Get a new dictionary PooledObject.
///
/// Output typed Dictionary.
/// A new Dictionary PooledObject.
public static ObjectPool>.PooledObject Get(out Dictionary value)
=> s_Pool.Get(out value);
///
/// Release an object to the pool.
///
/// Dictionary to release.
public static void Release(Dictionary toRelease) => s_Pool.Release(toRelease);
}
}