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); } }