// Animancer // Copyright 2020 Kybernetik // //#define ANIMANCER_LOG_OBJECT_POOLING using System.Collections.Generic; using UnityEngine; namespace Animancer { /// <summary>Convenience methods for accessing <see cref="ObjectPool{T}"/>.</summary> public static class ObjectPool { /************************************************************************************************************************/ /// <summary> /// Calls <see cref="ObjectPool{T}.Acquire"/> to get a spare item if there are any, or create a new one. /// </summary> public static T Acquire<T>() where T : class, new() { return ObjectPool<T>.Acquire(); } /// <summary> /// Calls <see cref="ObjectPool{T}.Acquire"/> to get a spare item if there are any, or create a new one. /// </summary> public static void Acquire<T>(out T item) where T : class, new() { item = ObjectPool<T>.Acquire(); } /************************************************************************************************************************/ /// <summary> /// Calls <see cref="ObjectPool{T}.Release"/> to add the `item` to the list of spares so it can be reused. /// </summary> public static void Release<T>(T item) where T : class, new() { ObjectPool<T>.Release(item); } /// <summary> /// Calls <see cref="ObjectPool{T}.Release"/> to add the `item` to the list of spares so it can be reused. /// </summary> public static void Release<T>(ref T item) where T : class, new() { if (item != null) { ObjectPool<T>.Release(item); item = null; } } /************************************************************************************************************************/ /// <summary> /// Calls <see cref="ObjectPool{T}.Acquire"/> to get a spare <see cref="List{T}"/> if /// there are any or create a new one. /// </summary> public static List<T> AcquireList<T>() { var list = ObjectPool<List<T>>.Acquire(); Debug.Assert(list.Count == 0, "A pooled collection is not empty. Collections must not be modified after being released to the pool."); return list; } /// <summary> /// Calls <see cref="ObjectPool{T}.Release"/> to clear the `list` and mark it as a spare /// so it can be later returned by <see cref="AcquireList"/>. /// </summary> public static void Release<T>(List<T> list) { list.Clear(); ObjectPool<List<T>>.Release(list); } /************************************************************************************************************************/ /// <summary> /// Calls <see cref="ObjectPool{T}.Acquire"/> to get a spare <see cref="HashSet{T}"/> if /// there are any or create a new one. /// </summary> public static HashSet<T> AcquireSet<T>() { var set = ObjectPool<HashSet<T>>.Acquire(); Debug.Assert(set.Count == 0, "A pooled collection is not empty. Collections must not be modified after being released to the pool."); return set; } /// <summary> /// Calls <see cref="ObjectPool{T}.Release"/> to clear the `set` and mark it as a spare /// so it can be later returned by <see cref="AcquireSet"/>. /// </summary> public static void Release<T>(HashSet<T> set) { set.Clear(); ObjectPool<HashSet<T>>.Release(set); } /************************************************************************************************************************/ } /// <summary>A simple object pooling system.</summary> public static class ObjectPool<T> where T : class, new() { /************************************************************************************************************************/ private static readonly List<T> Items = new List<T>(); /************************************************************************************************************************/ /// <summary>The number of spare items currently in the pool.</summary> public static int Count { get { return Items.Count; } } /************************************************************************************************************************/ /// <summary>The <see cref="List{T}.Capacity"/> of the internal list of spare items.</summary> public static int Capacity { get { return Items.Capacity; } set { if (Items.Count > value) Items.RemoveRange(value, Items.Count - value); Items.Capacity = value; } } /************************************************************************************************************************/ /// <summary>Returns a spare item if there are any, or creates a new one.</summary> public static T Acquire() { var count = Items.Count; if (count == 0) { return new T(); } else { count--; var item = Items[count]; Items.RemoveAt(count); return item; } } /************************************************************************************************************************/ /// <summary>Adds the `item` to the list of spares so it can be reused.</summary> public static void Release(T item) { Items.Add(item); } /************************************************************************************************************************/ } }