< Summary

Class:GDX.Collections.Pooling.SimpleListManagedPool
Assembly:GDX
File(s):./Packages/com.dotbunny.gdx/GDX/Collections/Pooling/SimpleListManagedPool.cs
Covered lines:78
Uncovered lines:108
Coverable lines:186
Total lines:433
Line coverage:41.9% (78 of 186)
Covered branches:0
Total branches:0
Covered methods:6
Total methods:14
Method coverage:42.8% (6 of 14)

Coverage History

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
SimpleListManagedPool(...)0%3.123076%
CreateItem()0%110100%
ForceRemove(...)0%30500%
Get(...)0%55.3915043.59%
GetBaseObject()0%2100%
GetKey()0%110100%
HasMinimumPooledItems()0%2100%
IsAllowedManagedTearDown()0%2100%
IsManaged(...)0%30500%
IsPooled(...)0%12300%
Return(...)0%7.686064%
ReturnAll(...)0%42600%
TearDown()0%770100%
Finalize()0%2100%

File(s)

./Packages/com.dotbunny.gdx/GDX/Collections/Pooling/SimpleListManagedPool.cs

#LineLine coverage
 1// Copyright (c) 2020-2024 dotBunny Inc.
 2// dotBunny licenses this file to you under the BSL-1.0 license.
 3// See the LICENSE file in the project root for more information.
 4
 5using System;
 6using GDX.Collections.Generic;
 7using UnityEngine;
 8
 9namespace GDX.Collections.Pooling
 10{
 11    /// <summary>
 12    ///     A <see cref="object" /> <see cref="SimpleList{T}" /> backed pool implementation.
 13    /// </summary>
 14    public sealed class SimpleListManagedPool : IManagedPool
 15    {
 16        /// <summary>
 17        ///     The <see cref="Flags" /> index used to determine if the <see cref="SimpleListManagedPool" /> is able to 
 18        ///     more items as necessary.
 19        /// </summary>
 20        const int k_AllowCreateMoreFlag = 0;
 21
 22        /// <summary>
 23        ///     The <see cref="Flags" /> index used to if <see cref="TearDown" /> can be called by a manager.
 24        /// </summary>
 25        const int k_AllowManagedTeardownFlag = 1;
 26
 27        /// <summary>
 28        ///     The <see cref="Flags" /> index used to determine if items should be reused when the pool is starved.
 29        /// </summary>
 30        const int k_AllowReuseFlag = 2;
 31
 32        /// <summary>
 33        ///     The <see cref="Flags" /> index used to determine if the pool should create items during its constructor.
 34        /// </summary>
 35        const int k_PrewarmPoolFlag = 3;
 36
 37        /// <summary>
 38        ///     The object which the pool is based off of, used as a model when creating new items.
 39        /// </summary>
 40        public readonly object BaseObject;
 41
 42        /// <summary>
 43        ///     The object which serves as a container for all objects of the pool.
 44        /// </summary>
 45        /// <remarks>Used more by implementations of pools, then this base class.</remarks>
 46        public readonly object ContainerObject;
 47
 48        /// <summary>
 49        ///     A defined function to create items for the pool.
 50        /// </summary>
 51        readonly Func<SimpleListManagedPool, object> m_CreateItemFunc;
 52
 53        /// <summary>
 54        ///     The absolutely unique identifier for this pool.
 55        /// </summary>
 56        readonly uint m_Key;
 57
 58        /// <summary>
 59        ///     The Maximum number of objects to be managed by the pool.
 60        /// </summary>
 61        readonly int m_MaximumObjects;
 62
 63        /// <summary>
 64        ///     The minimum number of objects to be managed by the pool.
 65        /// </summary>
 66        readonly int m_MinimumObjects;
 67
 68        /// <summary>
 69        ///     An <c>event</c> invoked when an item is destroyed by the <see cref="SimpleListManagedPool" />.
 70        /// </summary>
 71        public Action<object> destroyedItem;
 72
 73        /// <summary>
 74        ///     A <see cref="BitArray8" /> used to store pool based flags, as well as provide additional spots for imple
 75        /// </summary>
 76        /// <remarks>
 77        ///     Index 0-3 (<see cref="k_AllowCreateMoreFlag" />, <see cref="k_AllowManagedTeardownFlag" />,
 78        ///     <see cref="k_AllowReuseFlag" />, and <see cref="k_PrewarmPoolFlag" />) are used by the
 79        ///     <see cref="SimpleListManagedPool" /> itself, leaving 4-7 for additional use.
 80        /// </remarks>
 81        public BitArray8 Flags;
 82
 83        /// <summary>
 84        ///     A cached count of the number of items contained in <see cref="InItems" />.
 85        /// </summary>
 86        public int InCachedCount;
 87
 88        /// <summary>
 89        ///     A collection of items that are currently contained in the pool for use when spawning items upon request.
 90        /// </summary>
 91        public SimpleList<object> InItems;
 92
 93        /// <summary>
 94        ///     A collection of items that are currently considered out of the pool, that have been spawned.
 95        /// </summary>
 96        SimpleList<object> m_OutItems;
 97
 98        /// <summary>
 99        ///     A cached count of the number of items contained in <see cref="m_OutItems" />.
 100        /// </summary>
 101        public int OutCachedCount;
 102
 103        /// <summary>
 104        ///     An <c>event</c> invoked when an item is returned to the <see cref="SimpleListManagedPool" />.
 105        /// </summary>
 106        public Action<SimpleListManagedPool, object> returnedItem;
 107
 108        /// <summary>
 109        ///     An <c>event</c> invoked when an item is spawned from the <see cref="SimpleListManagedPool" />.
 110        /// </summary>
 111        public Action<SimpleListManagedPool, object> spawnedItem;
 112
 113        /// <summary>
 114        ///     An <c>event</c> invoked when a pool is tearing down, before the items are pooled.
 115        /// </summary>
 116        public Action<SimpleListManagedPool> tearingDown;
 117
 118        /// <summary>
 119        ///     Create a <see cref="SimpleListManagedPool" />.
 120        /// </summary>
 121        /// <param name="baseObject">The object which going to be cloned.</param>
 122        /// <param name="createItemFunc">The function used to create new items for the pool.</param>
 123        /// <param name="minimumObjects">The minimum number of objects to be managed by the pool.</param>
 124        /// <param name="maximumObjects">The maximum number of objects to be managed by the pool.</param>
 125        /// <param name="containerObject">A reference to an object which should be used as the container for created ite
 126        /// <param name="prewarmPool">Should this pool create its items during the constructor?</param>
 127        /// <param name="allowCreateMore">Can more items be created as needed when starved for items?</param>
 128        /// <param name="allowReuseWhenCapped">Should we reuse oldest items when starving for items?</param>
 129        /// <param name="allowManagedTearDown">Does the pool allow a managed tear down event call?</param>
 14130        public SimpleListManagedPool(
 131            object baseObject,
 132            Func<SimpleListManagedPool, object> createItemFunc,
 133            int minimumObjects = 10,
 134            int maximumObjects = 50,
 135            object containerObject = null,
 136            bool prewarmPool = true,
 137            bool allowCreateMore = true,
 138            bool allowReuseWhenCapped = false,
 139            bool allowManagedTearDown = false)
 14140        {
 141            // Get pool ID ticket
 14142            m_Key = ManagedPools.GetNextPoolKey();
 143
 14144            BaseObject = baseObject;
 14145            m_CreateItemFunc = createItemFunc;
 14146            m_MinimumObjects = minimumObjects;
 14147            m_MaximumObjects = maximumObjects;
 148
 14149            Flags[k_AllowCreateMoreFlag] = allowCreateMore;
 14150            Flags[k_AllowManagedTeardownFlag] = allowManagedTearDown;
 14151            Flags[k_AllowReuseFlag] = allowReuseWhenCapped;
 14152            Flags[k_PrewarmPoolFlag] = prewarmPool;
 153
 14154            ContainerObject = containerObject;
 155
 14156            ManagedPools.Register(this);
 157
 14158            InItems = new SimpleList<object>(maximumObjects);
 14159            m_OutItems = new SimpleList<object>(maximumObjects);
 160
 14161            if (!prewarmPool)
 14162            {
 14163                return;
 164            }
 165
 0166            for (int i = 0; i < minimumObjects; i++)
 0167            {
 0168                CreateItem();
 0169            }
 14170        }
 171
 172        /// <inheritdoc />
 173        public void CreateItem()
 12174        {
 175            // ReSharper disable once Unity.PerformanceCriticalCodeInvocation, Unity.ExpensiveCode
 12176            m_CreateItemFunc(this);
 12177        }
 178
 179        /// <inheritdoc />
 180        public void ForceRemove(object item)
 0181        {
 0182            int outCount = m_OutItems.Count;
 0183            for (int i = 0; i < outCount; i++)
 0184            {
 0185                if (m_OutItems.Array[i] != item)
 0186                {
 0187                    continue;
 188                }
 189
 0190                m_OutItems.RemoveAtSwapBack(i);
 0191                OutCachedCount--;
 0192                break;
 193            }
 194
 0195            int inCount = InItems.Count;
 0196            for (int i = 0; i < inCount; i++)
 0197            {
 0198                if (InItems.Array[i] != item)
 0199                {
 0200                    continue;
 201                }
 202
 0203                InItems.RemoveAtSwapBack(i);
 0204                InCachedCount--;
 0205                break;
 206            }
 0207        }
 208
 209        /// <inheritdoc />
 210        public object Get(bool triggerOnSpawnedFromPool = true)
 12211        {
 212            // Are we empty, but have refills?
 12213            if ((InCachedCount == 0 && OutCachedCount < m_MaximumObjects) ||
 214                (InCachedCount == 0 && Flags[k_AllowCreateMoreFlag]))
 12215            {
 12216                CreateItem();
 12217            }
 218
 12219            if (InCachedCount > 0)
 12220            {
 12221                int targetIndex = InCachedCount - 1;
 222
 223                // Make sure we don't pull badness
 12224                object returnItem = InItems.Array[targetIndex];
 12225                if (returnItem == null)
 0226                {
 0227                    Debug.LogWarning(
 228                        $"[ListObjectPool->Get] A null object was pulled from a pool ({m_Key.ToString()}).");
 0229                    InCachedCount--;
 0230                    return null;
 231                }
 232
 233                // Handle counters
 12234                m_OutItems.AddUnchecked(returnItem);
 12235                OutCachedCount++;
 12236                InItems.RemoveAt(targetIndex);
 12237                InCachedCount--;
 238
 12239                if (triggerOnSpawnedFromPool)
 0240                {
 0241                    spawnedItem?.Invoke(this, returnItem);
 0242                }
 243
 12244                return returnItem;
 245            }
 246
 0247            if (Flags[k_AllowReuseFlag])
 0248            {
 0249                object returnItem = m_OutItems.Array[0];
 0250                if (returnItem == null)
 0251                {
 0252                    Debug.LogWarning(
 253                        $"[ListObjectPool->Get] A null object was returned to the object pool ({m_Key.ToString()}).");
 0254                    return null;
 255                }
 256
 0257                returnedItem?.Invoke(this, returnItem);
 0258                if (triggerOnSpawnedFromPool)
 0259                {
 0260                    spawnedItem?.Invoke(this, returnItem);
 0261                }
 262
 0263                return returnItem;
 264            }
 265
 0266            Debug.LogWarning(
 267                $"[ListObjectPool->Get] Hit maximum object cap of {m_MaximumObjects.ToString()} for object pool ({m_Key.
 0268            return null;
 12269        }
 270
 271        /// <inheritdoc />
 272        public object GetBaseObject()
 0273        {
 0274            return BaseObject;
 0275        }
 276
 277        /// <inheritdoc />
 278        public uint GetKey()
 29279        {
 29280            return m_Key;
 29281        }
 282
 283        /// <inheritdoc />
 284        public bool HasMinimumPooledItems()
 0285        {
 0286            return InCachedCount >= m_MinimumObjects;
 0287        }
 288
 289        /// <inheritdoc />
 290        public bool IsAllowedManagedTearDown()
 0291        {
 0292            return Flags[k_AllowManagedTeardownFlag];
 0293        }
 294
 295        /// <inheritdoc />
 296        public bool IsManaged(object item)
 0297        {
 0298            int outCount = m_OutItems.Count;
 0299            for (int i = 0; i < outCount; i++)
 0300            {
 0301                if (m_OutItems.Array[i] == item)
 0302                {
 0303                    return true;
 304                }
 0305            }
 306
 0307            int inCount = InItems.Count;
 0308            for (int i = 0; i < inCount; i++)
 0309            {
 0310                if (InItems.Array[i] == item)
 0311                {
 0312                    return true;
 313                }
 0314            }
 315
 0316            return false;
 0317        }
 318
 319        /// <inheritdoc />
 320        public bool IsPooled(object item)
 0321        {
 0322            int inCount = InItems.Count;
 0323            for (int i = 0; i < inCount; i++)
 0324            {
 0325                if (InItems.Array[i] == item)
 0326                {
 0327                    return true;
 328                }
 0329            }
 330
 0331            return false;
 0332        }
 333
 334        /// <inheritdoc />
 335        public void Return(object item)
 12336        {
 337            // Do we have the interface call?
 12338            returnedItem?.Invoke(this, item);
 339
 12340            int outCount = m_OutItems.Count;
 24341            for (int i = 0; i < outCount; i++)
 12342            {
 12343                if (m_OutItems.Array[i] != item)
 0344                {
 0345                    continue;
 346                }
 347
 12348                m_OutItems.RemoveAtSwapBack(i);
 12349                OutCachedCount--;
 12350                break;
 351            }
 352
 12353            int inCount = InItems.Count;
 24354            for (int i = 0; i < inCount; i++)
 0355            {
 0356                if (InItems.Array[i] == item)
 0357                {
 0358                    return;
 359                }
 0360            }
 361
 12362            InItems.AddUnchecked(item);
 12363            InCachedCount++;
 12364        }
 365
 366        /// <inheritdoc />
 367        public void ReturnAll(bool shouldShrink = true)
 0368        {
 0369            for (int i = OutCachedCount - 1; i >= 0; i--)
 0370            {
 0371                Return(m_OutItems.Array[i]);
 0372            }
 373
 0374            if (shouldShrink && InCachedCount <= m_MaximumObjects)
 0375            {
 0376                return;
 377            }
 378
 0379            int removeCount = InCachedCount - m_MaximumObjects;
 0380            for (int i = 0; i < removeCount; i++)
 0381            {
 382                // Trigger specific logic, like Object.Destroy
 0383                destroyedItem?.Invoke(InItems.Array[i]);
 384
 385                // Dereferencing
 0386                InItems.RemoveAt(i);
 0387                InCachedCount--;
 0388            }
 0389        }
 390
 391        /// <inheritdoc />
 392        public void TearDown()
 14393        {
 14394            tearingDown?.Invoke(this);
 395
 396            // Return all items to the pool
 52397            for (int i = OutCachedCount - 1; i >= 0; i--)
 12398            {
 12399                if (m_OutItems.Array[i] != null)
 12400                {
 12401                    Return(m_OutItems.Array[i]);
 12402                }
 12403            }
 404
 14405            m_OutItems.Clear();
 14406            OutCachedCount = 0;
 407
 408            // Wipe internals
 52409            for (int i = InCachedCount - 1; i >= 0; i--)
 12410            {
 12411                if (InItems.Array[i] != null)
 12412                {
 12413                    destroyedItem?.Invoke(InItems.Array[i]);
 12414                }
 12415            }
 416
 14417            InItems.Clear();
 14418            InCachedCount = 0;
 419
 420            // Unregister
 14421            ManagedPools.Unregister(this);
 14422        }
 423
 424        /// <summary>
 425        ///     The <see cref="SimpleListManagedPool" /> destructor which unregisters itself from <see cref="ManagedPool
 426        /// </summary>
 427        ~SimpleListManagedPool()
 0428        {
 429            // Unregister
 0430            ManagedPools.Unregister(this);
 0431        }
 432    }
 433}

Coverage by test methods















Methods/Properties

SimpleListManagedPool(System.Object, System.Func[SimpleListManagedPool,Object], System.Int32, System.Int32, System.Object, System.Boolean, System.Boolean, System.Boolean, System.Boolean)
CreateItem()
ForceRemove(System.Object)
Get(System.Boolean)
GetBaseObject()
GetKey()
HasMinimumPooledItems()
IsAllowedManagedTearDown()
IsManaged(System.Object)
IsPooled(System.Object)
Return(System.Object)
ReturnAll(System.Boolean)
TearDown()
Finalize()