< Summary

Information
Class: Hertzole.ScriptableValues.ScriptablePool[T]
Assembly: Hertzole.ScriptableValues
File(s): File 1: ./Packages/se.hertzole.scriptable-values/Runtime/Pools/ScriptablePool.Bindings.cs
File 2: ./Packages/se.hertzole.scriptable-values/Runtime/Pools/ScriptablePool.cs
Tag: 52_28197466029
Line coverage
100%
Covered lines: 114
Uncovered lines: 0
Coverable lines: 114
Total lines: 377
Line coverage: 100%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
File 1: GetViewHashCode()0%110100%
File 2: ScriptablePool()0%110100%
File 2: Get()0%550100%
File 2: Release(...)0%220100%
File 2: Clear()0%330100%
File 2: UpdateCounts()0%110100%
File 2: OnGetInternal(...)0%220100%
File 2: OnReturnInternal(...)0%220100%
File 2: DestroyObjectInternal(...)0%220100%
File 2: OnGet(...)0%110100%
File 2: OnReturn(...)0%110100%
File 2: OnPreStart()0%110100%
File 2: OnDisabled()0%110100%
File 2: WarnIfLeftOverSubscribers()0%110100%
File 2: ClearSubscribers(...)0%220100%

File(s)

./Packages/se.hertzole.scriptable-values/Runtime/Pools/ScriptablePool.Bindings.cs

#LineLine coverage
 1#if SCRIPTABLE_VALUES_RUNTIME_BINDING && SCRIPTABLE_VALUES_UITOOLKIT
 2namespace Hertzole.ScriptableValues
 3{
 4    partial class ScriptablePool<T>
 5    {
 6        /// <inheritdoc />
 7        protected override long GetViewHashCode()
 2248        {
 9            unchecked
 22410            {
 22411                long hashCode = 17;
 12
 22413                hashCode = hashCode * 23 + base.GetViewHashCode();
 22414                hashCode = hashCode * 23 + CountAll.GetHashCode();
 22415                hashCode = hashCode * 23 + CountActive.GetHashCode();
 22416                hashCode = hashCode * 23 + CountInactive.GetHashCode();
 17
 22418                return hashCode;
 19            }
 22420        }
 21    }
 22}
 23#endif

./Packages/se.hertzole.scriptable-values/Runtime/Pools/ScriptablePool.cs

#LineLine coverage
 1#nullable enable
 2
 3using System;
 4using System.Collections.Generic;
 5using System.ComponentModel;
 6using System.Diagnostics.CodeAnalysis;
 7using Hertzole.ScriptableValues.Helpers;
 8using UnityEngine;
 9using UnityEngine.Assertions;
 10#if SCRIPTABLE_VALUES_PROPERTIES
 11using Unity.Properties;
 12#endif
 13
 14namespace Hertzole.ScriptableValues
 15{
 16    /// <summary>
 17    ///     Base class for all <see cref="ScriptablePool{T}" />.
 18    /// </summary>
 19    /// <remarks>You should probably inherit from <see cref="ScriptablePool{T}" /> instead.</remarks>
 20#if UNITY_EDITOR
 21    [HelpURL(Documentation.SCRIPTABLE_POOL_URL)]
 22#endif
 23    public abstract class ScriptablePool : RuntimeScriptableObject
 24    {
 25        public static readonly PropertyChangingEventArgs countAllChangingEventArgs = new PropertyChangingEventArgs(nameo
 26        public static readonly PropertyChangedEventArgs countAllChangedEventArgs = new PropertyChangedEventArgs(nameof(C
 27
 28        public static readonly PropertyChangingEventArgs countActiveChangingEventArgs = new PropertyChangingEventArgs(na
 29        public static readonly PropertyChangedEventArgs countActiveChangedEventArgs = new PropertyChangedEventArgs(nameo
 30
 31        public static readonly PropertyChangingEventArgs countInactiveChangingEventArgs = new PropertyChangingEventArgs(
 32        public static readonly PropertyChangedEventArgs countInactiveChangedEventArgs = new PropertyChangedEventArgs(nam
 33
 34        /// <summary>
 35        ///     How many total objects that the pool is keeping track of.
 36        /// </summary>
 37#if SCRIPTABLE_VALUES_PROPERTIES
 38#if SCRIPTABLE_VALUES_PROPERTIES_SUPPORTS_READONLY
 39        [CreateProperty(ReadOnly = true)]
 40#else
 41        [CreateProperty]
 42#endif // SCRIPTABLE_VALUES_PROPERTIES_SUPPORTS_READONLY
 43#endif // SCRIPTABLE_VALUES_PROPERTIES
 44        public abstract int CountAll { get; protected set; }
 45
 46        /// <summary>
 47        ///     How many objects that are currently active.
 48        /// </summary>
 49#if SCRIPTABLE_VALUES_PROPERTIES
 50#if SCRIPTABLE_VALUES_PROPERTIES_SUPPORTS_READONLY
 51        [CreateProperty(ReadOnly = true)]
 52#else
 53        [CreateProperty]
 54#endif // SCRIPTABLE_VALUES_PROPERTIES_SUPPORTS_READONLY
 55#endif // SCRIPTABLE_VALUES_PROPERTIES
 56        public abstract int CountActive { get; protected set; }
 57
 58        /// <summary>
 59        ///     How many objects that are currently inactive.
 60        /// </summary>
 61#if SCRIPTABLE_VALUES_PROPERTIES
 62#if SCRIPTABLE_VALUES_PROPERTIES_SUPPORTS_READONLY
 63        [CreateProperty(ReadOnly = true)]
 64#else
 65        [CreateProperty]
 66#endif // SCRIPTABLE_VALUES_PROPERTIES_SUPPORTS_READONLY
 67#endif // SCRIPTABLE_VALUES_PROPERTIES
 68        public abstract int CountInactive { get; protected set; }
 69    }
 70
 71    /// <summary>
 72    ///     A <see cref="UnityEngine.ScriptableObject" /> that holds a pool of values.
 73    /// </summary>
 74    /// <typeparam name="T">The type of to pool. Must be a class.</typeparam>
 75    public abstract partial class ScriptablePool<T> : ScriptablePool, IPoolCallbacks<T> where T : class
 76    {
 85877        internal readonly List<T> activeObjects = new List<T>();
 85878        internal readonly Stack<T> pool = new Stack<T>();
 79
 80        private int countAll;
 81        private int countActive;
 82        private int countInactive;
 83
 84        /// <inheritdoc />
 85        public sealed override int CountAll
 86        {
 1158087            get { return countAll; }
 88            protected set
 283889            {
 283890                Assert.AreEqual(activeObjects.Count + pool.Count, value,
 91                    $"CountAll should be equal to the sum of active and inactive objects but was {value} instead.");
 92
 283893                SetField(ref countAll, value, countAllChangingEventArgs, countAllChangedEventArgs);
 283894            }
 95        }
 96
 97        /// <inheritdoc />
 98        public sealed override int CountActive
 99        {
 1248100            get { return countActive; }
 101            protected set
 2838102            {
 2838103                Assert.AreEqual(activeObjects.Count, value, $"CountActive should be equal to the number of active object
 2838104                SetField(ref countActive, value, countActiveChangingEventArgs, countActiveChangedEventArgs);
 2838105            }
 106        }
 107
 108        /// <inheritdoc />
 109        public sealed override int CountInactive
 110        {
 1248111            get { return countInactive; }
 112            protected set
 2838113            {
 2838114                Assert.AreEqual(pool.Count, value, $"CountInactive should be equal to the number of inactive objects but
 2838115                SetField(ref countInactive, value, countInactiveChangingEventArgs, countInactiveChangedEventArgs);
 2838116            }
 117        }
 118
 119#if UNITY_EDITOR
 120        internal const int ORDER = ScriptableList<object>.ORDER + 50;
 121#endif
 122
 123        public event PoolChangedArgs<T>? OnPoolChanged;
 124
 125        /// <summary>
 126        ///     Gets an object from the pool.
 127        /// </summary>
 128        /// <returns>The newly acquired object from the pool.</returns>
 129        public T Get()
 738130        {
 738131            T? item = null;
 132            // Objects may be destroyed when switching scenes, so we need to check if they are null.
 133            // If the returned object is null, just keep going until we find one that isn't.
 134            // If it's still null, we'll create a new one.
 1488135            while (EqualityHelper.IsNull(item))
 750136            {
 750137                if (pool.Count > 0)
 48138                {
 48139                    item = pool.Pop();
 48140                }
 141                else
 702142                {
 702143                    item = CreateObject();
 702144                    OnPoolChanged?.Invoke(PoolAction.CreatedObject, item);
 702145                }
 750146            }
 147
 738148            Assert.IsNotNull(item);
 149
 738150            activeObjects.Add(item);
 151
 738152            OnPoolChanged?.Invoke(PoolAction.RentedObject, item);
 738153            OnGetInternal(item);
 154
 738155            UpdateCounts();
 156
 738157            AddStackTrace();
 158
 738159            return item;
 738160        }
 161
 162        /// <summary>
 163        ///     Returns an object to the pool.
 164        /// </summary>
 165        /// <param name="item">The item to return.</param>
 166        public void Release(T item)
 378167        {
 378168            Guard.IsNotNull(item, nameof(item));
 169
 354170            activeObjects.Remove(item);
 171
 354172            OnReturnInternal(item);
 354173            OnPoolChanged?.Invoke(PoolAction.ReleasedObject, item);
 174
 354175            pool.Push(item);
 176
 354177            UpdateCounts();
 178
 354179            AddStackTrace();
 354180        }
 181
 182        /// <summary>
 183        ///     Clears the pool. All objects, both active and inactive, will be destroyed.
 184        /// </summary>
 185        public void Clear()
 1722186        {
 187            // Destroy all active objects.
 188            // Go in reverse order so that we don't mess up the list.
 4212189            for (int i = activeObjects.Count - 1; i >= 0; i--)
 384190            {
 384191                T item = activeObjects[i];
 192
 384193                DestroyObjectInternal(item);
 384194                activeObjects.RemoveAt(i);
 384195            }
 196
 197            // Destroy all inactive objects.
 2028198            while (pool.TryPop(out T item))
 306199            {
 306200                DestroyObjectInternal(item);
 306201            }
 202
 1722203            UpdateCounts();
 204
 205            // Make sure that the pool is empty.
 1722206            Assert.AreEqual(0, CountAll, $"CountAll should be 0 after clearing the pool but was {CountAll}.");
 207
 1722208            AddStackTrace();
 1722209        }
 210
 211        private void UpdateCounts()
 2814212        {
 2814213            CountAll = activeObjects.Count + pool.Count;
 2814214            CountActive = activeObjects.Count;
 2814215            CountInactive = pool.Count;
 2814216        }
 217
 218        /// <summary>
 219        ///     Internal method for getting objects.
 220        /// </summary>
 221        /// <param name="item">The object that was just received from the pool.</param>
 222        internal virtual void OnGetInternal(T item)
 342223        {
 224            // If the item implements IPoolable, call OnUnpooled.
 342225            if (item is IPoolable poolable)
 342226            {
 342227                poolable.OnUnpooled();
 342228            }
 229
 230            // Call the OnGet method.
 342231            OnGet(item);
 342232        }
 233
 234        internal virtual void OnReturnInternal(T item)
 162235        {
 236            // If the item implements IPoolable, call OmPooled.
 162237            if (item is IPoolable poolable)
 162238            {
 162239                poolable.OnPooled();
 162240            }
 241
 242            // Call the OnReturn method.
 162243            OnReturn(item);
 162244        }
 245
 246        internal virtual void DestroyObjectInternal(T item)
 690247        {
 690248            OnPoolChanged?.Invoke(PoolAction.DestroyedObject, item);
 690249            DestroyObject(item);
 690250        }
 251
 252        /// <summary>
 253        ///     Called when a new object needs to be created.
 254        /// </summary>
 255        /// <returns></returns>
 256        protected abstract T CreateObject();
 257
 258        /// <summary>
 259        ///     Called when an object needs to be destroyed.
 260        /// </summary>
 261        /// <param name="item">The object to be destroyed.</param>
 262        protected abstract void DestroyObject(T item);
 263
 264        /// <summary>
 265        ///     Called when an object is retrieved from the pool.
 266        /// </summary>
 267        /// <param name="item">The object that was retrieved from the pool.</param>
 684268        protected virtual void OnGet(T item) { }
 269
 270        /// <summary>
 271        ///     Called when an object is returned to the pool.
 272        /// </summary>
 273        /// <param name="item">The object that was returned to the pool.</param>
 324274        protected virtual void OnReturn(T item) { }
 275
 276        protected override void OnPreStart()
 852277        {
 278            // Remove any subscribers that are left over from play mode.
 279            // Don't warn if there are any subscribers left over because we already do that in OnExitPlayMode.
 852280            ClearSubscribers();
 852281        }
 282
 283        /// <inheritdoc />
 284        protected override void OnDisabled()
 852285        {
 852286            WarnIfLeftOverSubscribers();
 287
 852288            Clear();
 852289        }
 290
 291        /// <summary>
 292        ///     Warns if there are any left-over subscribers to the events.
 293        /// </summary>
 294        /// <remarks>This will only be called in the Unity editor and builds with the DEBUG flag.</remarks>
 295        protected override void WarnIfLeftOverSubscribers()
 858296        {
 858297            base.WarnIfLeftOverSubscribers();
 858298            EventHelper.WarnIfLeftOverSubscribers(OnPoolChanged, nameof(OnPoolChanged), this);
 858299        }
 300
 301        /// <summary>
 302        ///     Removes any subscribers from the event.
 303        /// </summary>
 304        /// <param name="warnIfLeftOver">
 305        ///     If true, a warning will be printed in the console if there are any subscribers.
 306        ///     The warning will only be printed in the editor and debug builds.
 307        /// </param>
 308        public void ClearSubscribers(bool warnIfLeftOver = false)
 858309        {
 310#if DEBUG
 858311            if (warnIfLeftOver)
 6312            {
 6313                WarnIfLeftOverSubscribers();
 6314            }
 315#endif
 316
 858317            OnPoolChanged = null;
 858318        }
 319
 320        #region Obsolete
 321#if UNITY_EDITOR
 322        /// <summary>
 323        ///     Called when an object is created.
 324        /// </summary>
 325        [Obsolete("Use 'OnPoolChanged' instead. This will be removed in build.", true)]
 326#pragma warning disable CS0067 // Event is never used
 327        public event Action<T>? OnCreateObject;
 328        /// <summary>
 329        ///     Called when an object is destroyed.
 330        /// </summary>
 331        [Obsolete("Use 'OnPoolChanged' instead. This will be removed in build.", true)]
 332        public event Action<T>? OnDestroyObject;
 333        /// <summary>
 334        ///     Called when an object is retrieved.
 335        /// </summary>
 336        [Obsolete("Use 'OnPoolChanged' instead. This will be removed in build.", true)]
 337        public event Action<T>? OnGetObject;
 338        /// <summary>
 339        ///     Called when an object is put back into the pool.
 340        /// </summary>
 341        [Obsolete("Use 'OnPoolChanged' instead. This will be removed in build.", true)]
 342        public event Action<T>? OnReturnObject;
 343#pragma warning restore CS0067 // Event is never used
 344
 345        [Obsolete("Use 'Release' instead. This will be removed in build.", true)]
 346        [ExcludeFromCodeCoverage]
 347        public void Return(T item)
 348        {
 349            throw new NotSupportedException("'Return' is obsolete. Use 'Release' instead.");
 350        }
 351#endif
 352        #endregion
 353    }
 354}