using System; using System.Collections.Concurrent; using GameKit.Dependencies.Utilities.Types; using System.Collections.Generic; using System.Runtime.CompilerServices; using UnityEngine; // ReSharper disable ThreadStaticFieldHasInitializesr namespace GameKit.Dependencies.Utilities { /// /// Implement to use type with Caches. /// public interface IResettable { /// /// Resets values when being placed in a cache. /// void ResetState(); /// /// Initializes values after being retrieved from a cache. /// void InitializeState(); } #region Resettable caches. /// /// Caches collections of multiple generics. /// public static class ResettableCollectionCaches where T1 : IResettable, new() where T2 : IResettable, new() { /// /// Thread lock object. /// private static object _lock = new(); static ResettableCollectionCaches() { if (_lock == null) _lock = new(); } // /// // /// Forces _lock to initialize on the Unity main thread. // /// // [RuntimeInitializeOnLoadMethod] // private static void InitializeLockObject() => _lock = new(); /// /// Retrieves a collection. /// /// public static Dictionary RetrieveDictionary() => CollectionCaches.RetrieveDictionary(); /// /// Stores a collection and sets the original reference to default. /// Method will not execute if value is null. /// /// Value to store. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void StoreAndDefault(ref Dictionary value) { lock (_lock) { Store(value); value = default; } } /// /// Stores a collection. /// /// Value to store. public static void Store(Dictionary value) { lock (_lock) { if (value == null) return; foreach (KeyValuePair kvp in value) { ResettableObjectCaches.Store(kvp.Key); ResettableObjectCaches.Store(kvp.Value); } value.Clear(); CollectionCaches.Store(value); } } } /// /// Caches collections of multiple generics. /// public static class ResettableT1CollectionCaches where T1 : IResettable, new() { /// /// Thread lock object. /// private static object _lock = new(); static ResettableT1CollectionCaches() { if (_lock == null) _lock = new(); } // /// // /// Forces _lock to initialize on the Unity main thread. // /// // [RuntimeInitializeOnLoadMethod] // private static void InitializeLockObject() => _lock = new(); /// /// Retrieves a collection. /// /// public static Dictionary RetrieveDictionary() => CollectionCaches.RetrieveDictionary(); /// /// Stores a collection and sets the original reference to default. /// Method will not execute if value is null. /// /// Value to store. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void StoreAndDefault(ref Dictionary value) { lock (_lock) { Store(value); value = default; } } /// /// Stores a collection. /// /// Value to store. public static void Store(Dictionary value) { lock (_lock) { if (value == null) return; foreach (T1 item in value.Keys) ResettableObjectCaches.Store(item); value.Clear(); CollectionCaches.Store(value); } } } /// /// Caches collections of multiple generics. /// public static class ResettableT2CollectionCaches where T2 : IResettable, new() { /// /// Thread lock object. /// private static object _lock = new(); static ResettableT2CollectionCaches() { if (_lock == null) _lock = new(); } // /// // /// Forces _lock to initialize on the Unity main thread. // /// // [RuntimeInitializeOnLoadMethod] // private static void InitializeLockObject() => _lock = new(); /// /// Retrieves a collection. /// /// public static Dictionary RetrieveDictionary() => CollectionCaches.RetrieveDictionary(); /// /// Stores a collection and sets the original reference to default. /// Method will not execute if value is null. /// /// Value to store. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void StoreAndDefault(ref Dictionary value) { lock (_lock) { Store(value); value = default; } } /// /// Stores a collection. /// /// Value to store. public static void Store(Dictionary value) { lock (_lock) { if (value == null) return; foreach (T2 item in value.Values) ResettableObjectCaches.Store(item); value.Clear(); CollectionCaches.Store(value); } } } /// /// Caches collections of a single generic. /// public static class ResettableCollectionCaches where T : IResettable, new() { /// /// Cache for ResettableRingBuffer. /// private static readonly Stack> _resettableRingBufferCache = new(); /// /// Maximum number of entries allowed for the cache. /// private const int MAXIMUM_CACHE_COUNT = 50; /// /// Thread lock object. /// private static object _lock = new(); static ResettableCollectionCaches() { if (_lock == null) _lock = new(); } // /// // /// Forces _lock to initialize on the Unity main thread. // /// // [RuntimeInitializeOnLoadMethod] // private static void InitializeLockObject() => _lock = new(); /// /// Retrieves a collection. /// public static ResettableRingBuffer RetrieveRingBuffer() { lock (_lock) { ResettableRingBuffer result; if (!_resettableRingBufferCache.TryPop(out result)) result = new(); return result; } } /// /// Retrieves a collection. /// /// public static T[] RetrieveArray() => CollectionCaches.RetrieveArray(); /// /// Retrieves a collection. /// /// public static List RetrieveList() => CollectionCaches.RetrieveList(); /// /// Retrieves a collection. /// /// public static SortedSet RetrieveSortedSet() => CollectionCaches.RetrieveSortedSet(); /// /// Retrieves a collection. /// /// public static HashSet RetrieveHashSet() => CollectionCaches.RetrieveHashSet(); /// /// Retrieves a collection. /// /// public static Queue RetrieveQueue() => CollectionCaches.RetrieveQueue(); /// /// Retrieves a collection. /// /// public static BasicQueue RetrieveBasicQueue() => CollectionCaches.RetrieveBasicQueue(); /// /// Stores a collection and sets the original reference to default. /// Method will not execute if value is null. /// /// Value to store. /// Number of entries in the array from the beginning. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void StoreAndDefault(ref ResettableRingBuffer value) { lock (_lock) { Store(value); value = default; } } /// /// Stores a collection. /// /// Value to store. /// Number of entries in the array from the beginning. public static void Store(ResettableRingBuffer value) { lock (_lock) { if (value == null) return; value.ResetState(); if (_resettableRingBufferCache.Count < MAXIMUM_CACHE_COUNT) _resettableRingBufferCache.Push(value); } } /// /// Stores a collection and sets the original reference to default. /// Method will not execute if value is null. /// /// Value to store. /// Number of entries in the array from the beginning. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void StoreAndDefault(ref T[] value, int count) { lock (_lock) { Store(value, count); value = default; } } /// /// Stores a collection. /// /// Value to store. /// Number of entries in the array from the beginning. public static void Store(T[] value, int count) { lock (_lock) { if (value == null) return; for (int i = 0; i < count; i++) ResettableObjectCaches.Store(value[i]); CollectionCaches.Store(value, count); } } /// /// Stores a collection and sets the original reference to default. /// Method will not execute if value is null. /// /// Value to store. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void StoreAndDefault(ref List value) { lock (_lock) { Store(value); value = default; } } /// /// Stores a collection. /// /// Value to store. public static void Store(List value) { lock (_lock) { if (value == null) return; for (int i = 0; i < value.Count; i++) ResettableObjectCaches.Store(value[i]); value.Clear(); CollectionCaches.Store(value); } } /// /// Stores a collection and sets the original reference to default. /// Method will not execute if value is null. /// /// Value to store. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void StoreAndDefault(ref SortedSet value) { lock (_lock) { Store(value); value = default; } } /// /// Stores a collection. /// /// Value to store. public static void Store(SortedSet value) { lock (_lock) { if (value == null) return; foreach (T item in value) ResettableObjectCaches.Store(item); value.Clear(); CollectionCaches.Store(value); } } /// /// Stores a collection and sets the original reference to default. /// Method will not execute if value is null. /// /// Value to store. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void StoreAndDefault(ref HashSet value) { lock (_lock) { Store(value); value = default; } } /// /// Stores a collection. /// /// Value to store. public static void Store(HashSet value) { lock (_lock) { if (value == null) return; foreach (T item in value) ResettableObjectCaches.Store(item); value.Clear(); CollectionCaches.Store(value); } } /// /// Stores a collection and sets the original reference to default. /// Method will not execute if value is null. /// /// Value to store. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void StoreAndDefault(ref Queue value) { lock (_lock) { Store(value); value = default; } } /// /// Stores a collection. /// /// Value to store. public static void Store(Queue value) { lock (_lock) { if (value == null) return; foreach (T item in value) ResettableObjectCaches.Store(item); value.Clear(); CollectionCaches.Store(value); } } /// /// Stores a collection and sets the original reference to default. /// Method will not execute if value is null. /// /// Value to store. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void StoreAndDefault(ref BasicQueue value) { lock (_lock) { Store(value); value = default; } } /// /// Stores a collection. /// /// Value to store. public static void Store(BasicQueue value) { lock (_lock) { if (value == null) return; while (value.TryDequeue(out T result)) ResettableObjectCaches.Store(result); value.Clear(); CollectionCaches.Store(value); } } } /// /// Caches objects of a single generic. /// public static class ResettableObjectCaches where T : IResettable, new() { /// /// Thread lock object. /// private static object _lock = new(); static ResettableObjectCaches() { if (_lock == null) _lock = new(); } // /// // /// Forces _lock to initialize on the Unity main thread. // /// // [RuntimeInitializeOnLoadMethod] // private static void InitializeLockObject() => _lock = new(); /// /// Retrieves an instance of T. /// public static T Retrieve() { lock (_lock) { T result = ObjectCaches.Retrieve(); result.InitializeState(); return result; } } /// /// Stores an instance of T and sets the original reference to default. /// Method will not execute if value is null. /// /// Value to store. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void StoreAndDefault(ref T value) { lock (_lock) { Store(value); value = default; } } /// /// Stores an instance of T. /// /// Value to store. public static void Store(T value) { lock (_lock) { if (value == null) return; value.ResetState(); ObjectCaches.Store(value); } } } #endregion #region NonResettable caches. /// /// Caches collections of multiple generics. /// public static class CollectionCaches { /// /// Cache for dictionaries. /// private static readonly Stack> _dictionaryCache = new(); /// /// Maximum number of entries allowed for the cache. /// private const int MAXIMUM_CACHE_COUNT = 50; /// /// Thread lock object. /// private static object _lock = new(); static CollectionCaches() { if (_lock == null) _lock = new(); } // /// // /// Forces _lock to initialize on the Unity main thread. // /// // [RuntimeInitializeOnLoadMethod] // private static void InitializeLockObject() => _lock = new(); /// /// Retrieves a collection. /// /// public static Dictionary RetrieveDictionary() { lock (_lock) { Dictionary result; if (!_dictionaryCache.TryPop(out result)) result = new(); return result; } } /// /// Stores a collection and sets the original reference to default. /// Method will not execute if value is null. /// /// Value to store. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void StoreAndDefault(ref Dictionary value) { lock (_lock) { Store(value); value = default; } } /// /// Stores a collection. /// /// Value to store. public static void Store(Dictionary value) { lock (_lock) { if (value == null) return; value.Clear(); if (_dictionaryCache.Count < MAXIMUM_CACHE_COUNT) _dictionaryCache.Push(value); } } } /// /// Caches collections of a single generic. /// public static partial class CollectionCaches { /// /// Cache for arrays. /// private static readonly Stack _arrayCache = new(); /// /// Cache for lists. /// private static readonly Stack> _listCache = new(); /// /// Cache for sortedset. /// private static readonly Stack> _sortedSetCache = new(); /// /// Cache for queues. /// private static readonly Stack> _queueCache = new(); /// /// Cache for queues. /// private static readonly Stack> _basicQueueCache = new(); /// /// Cache for hashset. /// private static readonly Stack> _hashSetCache = new(); /// /// Maximum number of entries allowed for the cache. /// private const int MAXIMUM_CACHE_COUNT = 50; /// /// Thread lock object. /// private static object _lock = new(); static CollectionCaches() { if (_lock == null) _lock = new(); } // /// // /// Forces _lock to initialize on the Unity main thread. // /// // [RuntimeInitializeOnLoadMethod] // private static void InitializeLockObject() => _lock = new(); /// /// Retrieves a collection. /// /// public static T[] RetrieveArray() { lock (_lock) { T[] result; if (!_arrayCache.TryPop(out result)) result = new T[0]; return result; } } /// /// Retrieves a collection. /// /// public static List RetrieveList() { lock (_lock) { List result; if (!_listCache.TryPop(out result)) result = new(); return result; } } /// /// Retrieves a collection. /// /// public static SortedSet RetrieveSortedSet() { lock (_lock) { SortedSet result; if (!_sortedSetCache.TryPop(out result)) result = new(); return result; } } /// /// Retrieves a collection. /// /// public static Queue RetrieveQueue() { lock (_lock) { Queue result; if (!_queueCache.TryPop(out result)) result = new(); return result; } } /// /// Retrieves a collection. /// /// public static BasicQueue RetrieveBasicQueue() { lock (_lock) { BasicQueue result; if (!_basicQueueCache.TryPop(out result)) result = new(); return result; } } /// /// Retrieves a collection adding one entry. /// /// public static Queue RetrieveQueue(T entry) { lock (_lock) { Queue result; if (!_queueCache.TryPop(out result)) result = new(); result.Enqueue(entry); return result; } } /// /// Retrieves a collection adding one entry. /// /// public static List RetrieveList(T entry) { lock (_lock) { List result; if (!_listCache.TryPop(out result)) result = new(); result.Add(entry); return result; } } /// /// Retrieves a HashSet. /// /// public static HashSet RetrieveHashSet() { lock (_lock) { HashSet result; if (!_hashSetCache.TryPop(out result)) result = new(); return result; } } /// /// Retrieves a collection adding one entry. /// /// public static HashSet RetrieveHashSet(T entry) { lock (_lock) { HashSet result; if (!_hashSetCache.TryPop(out result)) return new(); result.Add(entry); return result; } } /// /// Stores a collection and sets the original reference to default. /// Method will not execute if value is null. /// /// Value to store. /// Number of entries in the array set default, from the beginning. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void StoreAndDefault(ref T[] value, int count) { lock (_lock) { Store(value, count); value = default; } } /// /// Stores a collection. /// /// Value to store. /// Number of entries in the array from the beginning. public static void Store(T[] value, int count) { lock (_lock) { if (value == null) return; for (int i = 0; i < count; i++) value[i] = default; if (_arrayCache.Count < MAXIMUM_CACHE_COUNT) _arrayCache.Push(value); } } /// /// Stores a collection and sets the original reference to default. /// Method will not execute if value is null. /// /// Value to store. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void StoreAndDefault(ref List value) { lock (_lock) { Store(value); value = default; } } /// /// Stores a collection. /// /// Value to store. public static void Store(List value) { lock (_lock) { if (value == null) return; value.Clear(); if (_listCache.Count < MAXIMUM_CACHE_COUNT) _listCache.Push(value); } } /// /// Stores a collection and sets the original reference to default. /// Method will not execute if value is null. /// /// Value to store. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void StoreAndDefault(ref SortedSet value) { lock (_lock) { Store(value); value = default; } } /// /// Stores a collection. /// /// Value to store. public static void Store(SortedSet value) { lock (_lock) { if (value == null) return; value.Clear(); if (_sortedSetCache.Count < MAXIMUM_CACHE_COUNT) _sortedSetCache.Push(value); } } /// /// Stores a collection and sets the original reference to default. /// Method will not execute if value is null. /// /// Value to store. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void StoreAndDefault(ref Queue value) { lock (_lock) { Store(value); value = default; } } /// /// Stores a collection. /// /// Value to store. public static void Store(Queue value) { lock (_lock) { if (value == null) return; value.Clear(); if (_queueCache.Count < MAXIMUM_CACHE_COUNT) _queueCache.Push(value); } } /// /// Stores a collection and sets the original reference to default. /// Method will not execute if value is null. /// /// Value to store. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void StoreAndDefault(ref BasicQueue value) { lock (_lock) { Store(value); value = default; } } /// /// Stores a collection. /// /// Value to store. public static void Store(BasicQueue value) { lock (_lock) { if (value == null) return; value.Clear(); if (_basicQueueCache.Count < MAXIMUM_CACHE_COUNT) _basicQueueCache.Push(value); } } /// /// Stores a collection and sets the original reference to default. /// Method will not execute if value is null. /// /// Value to store. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void StoreAndDefault(ref HashSet value) { lock (_lock) { Store(value); value = default; } } /// /// Stores a collection. /// /// Value to store. public static void Store(HashSet value) { lock (_lock) { if (value == null) return; value.Clear(); if (_hashSetCache.Count < MAXIMUM_CACHE_COUNT) _hashSetCache.Push(value); } } } /// /// Caches objects of a single generic. /// public static class ObjectCaches where T : new() { /// /// Stack to use. /// private static readonly Stack _stack = new(); /// /// Maximum number of entries allowed for the cache. /// private const int MAXIMUM_CACHE_COUNT = 50; /// /// Thread lock object. /// private static object _lock = new(); static ObjectCaches() { /* Initializes lock if not already -- this covers * the rare chance a thread other than Unity accesses * this class first. */ if (_lock == null) _lock = new(); } // /// // /// Forces _lock to initialize on the Unity main thread. // /// // [RuntimeInitializeOnLoadMethod] // private static void InitializeLockObject() => _lock = new(); /// /// Returns a value from the stack or creates an instance when the stack is empty. /// /// public static T Retrieve() { lock (_lock) { T result; if (!_stack.TryPop(out result)) result = new(); // Activator.CreateInstance(); return result; } } /// /// Stores an instance of T and sets the original reference to default. /// Method will not execute if value is null. /// /// Value to store. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void StoreAndDefault(ref T value) { lock (_lock) { Store(value); value = default; } } /// /// Stores a value to the stack. /// /// public static void Store(T value) { lock (_lock) { if (value == null) return; if (_stack.Count < MAXIMUM_CACHE_COUNT) _stack.Push(value); } } } #endregion }