< Summary

Class:GDX.Collections.Pooling.SimpleListManagedPool
Assembly:GDX
File(s):D:/BuildAgent/work/GDX-Documentation/Projects/GDX_Development/Packages/com.dotbunny.gdx/GDX/Collections/Pooling/SimpleListManagedPool.cs
Covered lines:81
Uncovered lines:105
Coverable lines:186
Total lines:428
Line coverage:43.5% (81 of 186)
Covered branches:0
Total branches:0
Covered methods:7
Total methods:14
Method coverage:50% (7 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%110100%

File(s)

D:/BuildAgent/work/GDX-Documentation/Projects/GDX_Development/Packages/com.dotbunny.gdx/GDX/Collections/Pooling/SimpleListManagedPool.cs

#LineLine coverage
 1// Copyright (c) 2020-2022 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;
 7
 8namespace GDX.Collections.Pooling
 9{
 10    /// <summary>
 11    ///     A <see cref="object" /> <see cref="SimpleList{T}" /> backed pool implementation.
 12    /// </summary>
 13    public sealed class SimpleListManagedPool : IManagedPool
 14    {
 15        /// <summary>
 16        ///     The <see cref="Flags" /> index used to determine if the <see cref="SimpleListManagedPool" /> is able to 
 17        ///     more items as necessary.
 18        /// </summary>
 19        const int k_AllowCreateMoreFlag = 0;
 20
 21        /// <summary>
 22        ///     The <see cref="Flags" /> index used to if <see cref="TearDown" /> can be called by a manager.
 23        /// </summary>
 24        const int k_AllowManagedTeardownFlag = 1;
 25
 26        /// <summary>
 27        ///     The <see cref="Flags" /> index used to determine if items should be reused when the pool is starved.
 28        /// </summary>
 29        const int k_AllowReuseFlag = 2;
 30
 31        /// <summary>
 32        ///     The <see cref="Flags" /> index used to determine if the pool should create items during its constructor.
 33        /// </summary>
 34        const int k_PrewarmPoolFlag = 3;
 35
 36        /// <summary>
 37        ///     A defined function to create items for the pool.
 38        /// </summary>
 39        readonly Func<SimpleListManagedPool, object> m_CreateItemFunc;
 40
 41        /// <summary>
 42        ///     The absolutely unique identifier for this pool.
 43        /// </summary>
 44        readonly uint m_Key;
 45
 46        /// <summary>
 47        ///     The Maximum number of objects to be managed by the pool.
 48        /// </summary>
 49        readonly int m_MaximumObjects;
 50
 51        /// <summary>
 52        ///     The minimum number of objects to be managed by the pool.
 53        /// </summary>
 54        readonly int m_MinimumObjects;
 55
 56        /// <summary>
 57        ///     A collection of items that are currently considered out of the pool, that have been spawned.
 58        /// </summary>
 59        SimpleList<object> m_OutItems;
 60
 61        /// <summary>
 62        ///     A cached count of the number of items contained in <see cref="InItems" />.
 63        /// </summary>
 64        public int InCachedCount;
 65
 66        /// <summary>
 67        ///     A cached count of the number of items contained in <see cref="m_OutItems" />.
 68        /// </summary>
 69        public int OutCachedCount;
 70
 71        /// <summary>
 72        ///     The object which the pool is based off of, used as a model when creating new items.
 73        /// </summary>
 74        public readonly object BaseObject;
 75
 76        /// <summary>
 77        ///     The object which serves as a container for all objects of the pool.
 78        /// </summary>
 79        /// <remarks>Used more by implementations of pools, then this base class.</remarks>
 80        public readonly object ContainerObject;
 81
 82        /// <summary>
 83        ///     A collection of items that are currently contained in the pool for use when spawning items upon request.
 84        /// </summary>
 85        public SimpleList<object> InItems;
 86
 87        /// <summary>
 88        ///     A <see cref="BitArray8" /> used to store pool based flags, as well as provide additional spots for imple
 89        /// </summary>
 90        /// <remarks>
 91        ///     Index 0-3 (<see cref="k_AllowCreateMoreFlag" />, <see cref="k_AllowManagedTeardownFlag" />,
 92        ///     <see cref="k_AllowReuseFlag" />, and <see cref="k_PrewarmPoolFlag" />) are used by the
 93        ///     <see cref="SimpleListManagedPool" /> itself, leaving 4-7 for additional use.
 94        /// </remarks>
 95        public BitArray8 Flags;
 96
 97        /// <summary>
 98        ///     A <c>delegate</c> call made when an item is destroyed by the <see cref="SimpleListManagedPool" />.
 99        /// </summary>
 100        public Action<object> OnDestroyItem;
 101
 102        /// <summary>
 103        ///     A <c>delegate</c> call made when an item is returned to the <see cref="SimpleListManagedPool" />.
 104        /// </summary>
 105        public Action<SimpleListManagedPool, object> OnReturnedToPool;
 106
 107        /// <summary>
 108        ///     A <c>delegate</c> call made when an item is spawned from the <see cref="SimpleListManagedPool" />.
 109        /// </summary>
 110        public Action<SimpleListManagedPool, object> OnSpawnedFromPool;
 111
 112        /// <summary>
 113        ///     A <c>delegate</c> call made when a pool is tearing down, before the items are pooled.
 114        /// </summary>
 115        public Action<SimpleListManagedPool> OnTearDown;
 116
 117        /// <summary>
 118        ///     Create a <see cref="SimpleListManagedPool" />.
 119        /// </summary>
 120        /// <param name="baseObject">The object which going to be cloned.</param>
 121        /// <param name="createItemFunc">The function used to create new items for the pool.</param>
 122        /// <param name="minimumObjects">The minimum number of objects to be managed by the pool.</param>
 123        /// <param name="maximumObjects">The maximum number of objects to be managed by the pool.</param>
 124        /// <param name="containerObject">A reference to an object which should be used as the container for created ite
 125        /// <param name="prewarmPool">Should this pool create its items during the constructor?</param>
 126        /// <param name="allowCreateMore">Can more items be created as needed when starved for items?</param>
 127        /// <param name="allowReuseWhenCapped">Should we reuse oldest items when starving for items?</param>
 128        /// <param name="allowManagedTearDown">Does the pool allow a managed tear down event call?</param>
 14129        public SimpleListManagedPool(
 130            object baseObject,
 131            Func<SimpleListManagedPool, object> createItemFunc,
 132            int minimumObjects = 10,
 133            int maximumObjects = 50,
 134            object containerObject = null,
 135            bool prewarmPool = true,
 136            bool allowCreateMore = true,
 137            bool allowReuseWhenCapped = false,
 138            bool allowManagedTearDown = false)
 14139        {
 140            // Get pool ID ticket
 14141            m_Key = ManagedPools.GetNextPoolKey();
 142
 14143            BaseObject = baseObject;
 14144            m_CreateItemFunc = createItemFunc;
 14145            m_MinimumObjects = minimumObjects;
 14146            m_MaximumObjects = maximumObjects;
 147
 14148            Flags[k_AllowCreateMoreFlag] = allowCreateMore;
 14149            Flags[k_AllowManagedTeardownFlag] = allowManagedTearDown;
 14150            Flags[k_AllowReuseFlag] = allowReuseWhenCapped;
 14151            Flags[k_PrewarmPoolFlag] = prewarmPool;
 152
 14153            ContainerObject = containerObject;
 154
 14155            ManagedPools.Register(this);
 156
 14157            InItems = new SimpleList<object>(maximumObjects);
 14158            m_OutItems = new SimpleList<object>(maximumObjects);
 159
 14160            if (!prewarmPool)
 14161            {
 14162                return;
 163            }
 164
 0165            for (int i = 0; i < minimumObjects; i++)
 0166            {
 0167                CreateItem();
 0168            }
 14169        }
 170
 171        /// <inheritdoc />
 172        public void CreateItem()
 12173        {
 174            // ReSharper disable once Unity.PerformanceCriticalCodeInvocation, Unity.ExpensiveCode
 12175            m_CreateItemFunc(this);
 12176        }
 177
 178        /// <inheritdoc />
 179        public void ForceRemove(object item)
 0180        {
 0181            int outCount = m_OutItems.Count;
 0182            for (int i = 0; i < outCount; i++)
 0183            {
 0184                if (m_OutItems.Array[i] != item)
 0185                {
 0186                    continue;
 187                }
 0188                m_OutItems.RemoveAtSwapBack(i);
 0189                OutCachedCount--;
 0190                break;
 191            }
 192
 0193            int inCount = InItems.Count;
 0194            for (int i = 0; i < inCount; i++)
 0195            {
 0196                if (InItems.Array[i] != item)
 0197                {
 0198                    continue;
 199                }
 200
 0201                InItems.RemoveAtSwapBack(i);
 0202                InCachedCount--;
 0203                break;
 204            }
 0205        }
 206
 207        /// <inheritdoc />
 208        public object Get(bool triggerOnSpawnedFromPool = true)
 12209        {
 210            // Are we empty, but have refills?
 12211            if (InCachedCount == 0 && OutCachedCount < m_MaximumObjects || InCachedCount == 0 && Flags[k_AllowCreateMore
 12212            {
 12213                CreateItem();
 12214            }
 215
 12216            if (InCachedCount > 0)
 12217            {
 12218                int targetIndex = InCachedCount - 1;
 219
 220                // Make sure we don't pull badness
 12221                object returnItem = InItems.Array[targetIndex];
 12222                if (returnItem == null)
 0223                {
 0224                    Trace.Output(Trace.TraceLevel.Warning,
 225                        $"[ListObjectPool->Get] A null object was pulled from a pool ({m_Key.ToString()}).");
 0226                    InCachedCount--;
 0227                    return null;
 228                }
 229
 230                // Handle counters
 12231                m_OutItems.AddUnchecked(returnItem);
 12232                OutCachedCount++;
 12233                InItems.RemoveAt(targetIndex);
 12234                InCachedCount--;
 235
 12236                if (triggerOnSpawnedFromPool)
 0237                {
 0238                    OnSpawnedFromPool?.Invoke(this, returnItem);
 0239                }
 240
 12241                return returnItem;
 242            }
 243
 0244            if (Flags[k_AllowReuseFlag])
 0245            {
 0246                object returnItem = m_OutItems.Array[0];
 0247                if (returnItem == null)
 0248                {
 0249                    Trace.Output(Trace.TraceLevel.Warning,
 250                        $"[ListObjectPool->Get] A null object was returned to the object pool ({m_Key.ToString()}).");
 0251                    return null;
 252                }
 253
 0254                OnReturnedToPool?.Invoke(this, returnItem);
 0255                if (triggerOnSpawnedFromPool)
 0256                {
 0257                    OnSpawnedFromPool?.Invoke(this, returnItem);
 0258                }
 259
 0260                return returnItem;
 261            }
 262
 0263            Trace.Output(Trace.TraceLevel.Warning,
 264                $"[ListObjectPool->Get] Hit maximum object cap of {m_MaximumObjects.ToString()} for object pool ({m_Key.
 0265            return null;
 12266        }
 267
 268        /// <inheritdoc />
 269        public object GetBaseObject()
 0270        {
 0271            return BaseObject;
 0272        }
 273
 274        /// <inheritdoc />
 275        public uint GetKey()
 43276        {
 43277            return m_Key;
 43278        }
 279
 280        /// <inheritdoc />
 281        public bool HasMinimumPooledItems()
 0282        {
 0283            return InCachedCount >= m_MinimumObjects;
 0284        }
 285
 286        /// <inheritdoc />
 287        public bool IsAllowedManagedTearDown()
 0288        {
 0289            return Flags[k_AllowManagedTeardownFlag];
 0290        }
 291
 292        /// <inheritdoc />
 293        public bool IsManaged(object item)
 0294        {
 0295            int outCount = m_OutItems.Count;
 0296            for (int i = 0; i < outCount; i++)
 0297            {
 0298                if (m_OutItems.Array[i] == item)
 0299                {
 0300                    return true;
 301                }
 0302            }
 0303            int inCount = InItems.Count;
 0304            for (int i = 0; i < inCount; i++)
 0305            {
 0306                if (InItems.Array[i] == item)
 0307                {
 0308                    return true;
 309                }
 0310            }
 311
 0312            return false;
 0313        }
 314
 315        /// <inheritdoc />
 316        public bool IsPooled(object item)
 0317        {
 0318            int inCount = InItems.Count;
 0319            for (int i = 0; i < inCount; i++)
 0320            {
 0321                if (InItems.Array[i] == item)
 0322                {
 0323                    return true;
 324                }
 0325            }
 0326            return false;
 0327        }
 328
 329        /// <inheritdoc />
 330        public void Return(object item)
 12331        {
 332            // Do we have the interface call?
 12333            OnReturnedToPool?.Invoke(this, item);
 334
 12335            int outCount = m_OutItems.Count;
 24336            for (int i = 0; i < outCount; i++)
 12337            {
 12338                if (m_OutItems.Array[i] != item)
 0339                {
 0340                    continue;
 341                }
 342
 12343                m_OutItems.RemoveAtSwapBack(i);
 12344                OutCachedCount--;
 12345                break;
 346            }
 347
 12348            int inCount = InItems.Count;
 24349            for (int i = 0; i < inCount; i++)
 0350            {
 0351                if (InItems.Array[i] == item)
 0352                {
 0353                    return;
 354                }
 0355            }
 356
 12357            InItems.AddUnchecked(item);
 12358            InCachedCount++;
 12359        }
 360
 361        /// <inheritdoc />
 362        public void ReturnAll(bool shouldShrink = true)
 0363        {
 0364            for (int i = OutCachedCount - 1; i >= 0; i--)
 0365            {
 0366                Return(m_OutItems.Array[i]);
 0367            }
 368
 0369            if (shouldShrink && InCachedCount <= m_MaximumObjects)
 0370            {
 0371                return;
 372            }
 373
 0374            int removeCount = InCachedCount - m_MaximumObjects;
 0375            for (int i = 0; i < removeCount; i++)
 0376            {
 377                // Trigger specific logic, like Object.Destroy
 0378                OnDestroyItem?.Invoke(InItems.Array[i]);
 379
 380                // Dereferencing
 0381                InItems.RemoveAt(i);
 0382                InCachedCount--;
 0383            }
 0384        }
 385
 386        /// <inheritdoc />
 387        public void TearDown()
 14388        {
 14389            OnTearDown?.Invoke(this);
 390
 391            // Return all items to the pool
 52392            for (int i = OutCachedCount - 1; i >= 0; i--)
 12393            {
 12394                if (m_OutItems.Array[i] != null)
 12395                {
 12396                    Return(m_OutItems.Array[i]);
 397
 12398                }
 12399            }
 400
 14401            m_OutItems.Clear();
 14402            OutCachedCount = 0;
 403
 404            // Wipe internals
 52405            for (int i = InCachedCount - 1; i >= 0; i--)
 12406            {
 12407                if (InItems.Array[i] != null)
 12408                {
 12409                    OnDestroyItem?.Invoke(InItems.Array[i]);
 12410                }
 12411            }
 14412            InItems.Clear();
 14413            InCachedCount = 0;
 414
 415            // Unregister
 14416            ManagedPools.Unregister(this);
 14417        }
 418
 419        /// <summary>
 420        ///     The <see cref="SimpleListManagedPool" /> destructor which unregisters itself from <see cref="ManagedPool
 421        /// </summary>
 422        ~SimpleListManagedPool()
 28423        {
 424            // Unregister
 14425            ManagedPools.Unregister(this);
 28426        }
 427    }
 428}