< Summary

Line coverage
0%
Covered lines: 0
Uncovered lines: 37
Coverable lines: 37
Total lines: 116
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 10
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)100%110%
.ctor(...)100%110%
CreateInstance()100%110%
Allocate()0%660%
Free(...)0%440%

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/ObjectPool`1.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Threading;
 5
 6namespace System.Reflection.Internal
 7{
 8    /// <summary>
 9    /// Generic implementation of object pooling pattern with predefined pool size limit. The main
 10    /// purpose is that limited number of frequently used objects can be kept in the pool for
 11    /// further recycling.
 12    ///
 13    /// Notes:
 14    /// 1) it is not the goal to keep all returned objects. Pool is not meant for storage. If there
 15    ///    is no space in the pool, extra returned objects will be dropped.
 16    ///
 17    /// 2) it is implied that if object was obtained from a pool, the caller will return it back in
 18    ///    a relatively short time. Keeping checked out objects for long durations is ok, but
 19    ///    reduces usefulness of pooling. Just new up your own.
 20    ///
 21    /// Not returning objects to the pool in not detrimental to the pool's work, but is a bad practice.
 22    /// Rationale:
 23    ///    If there is no intent for reusing the object, do not use pool - just use "new".
 24    /// </summary>
 25    internal sealed class ObjectPool<T> where T : class
 26    {
 27        private struct Element
 28        {
 29            internal T? Value;
 30        }
 31
 32        // storage for the pool objects.
 33        private readonly Element[] _items;
 34
 35        // factory is stored for the lifetime of the pool. We will call this only when pool needs to
 36        // expand. compared to "new T()", Func gives more flexibility to implementers and faster
 37        // than "new T()".
 38        private readonly Func<T> _factory;
 39
 40
 41        internal ObjectPool(Func<T> factory)
 042            : this(factory, Environment.ProcessorCount * 2)
 043        { }
 44
 045        internal ObjectPool(Func<T> factory, int size)
 046        {
 047            _factory = factory;
 048            _items = new Element[size];
 049        }
 50
 51        private T CreateInstance()
 052        {
 053            var inst = _factory();
 054            return inst;
 055        }
 56
 57        /// <summary>
 58        /// Produces an instance.
 59        /// </summary>
 60        /// <remarks>
 61        /// Search strategy is a simple linear probing which is chosen for it cache-friendliness.
 62        /// Note that Free will try to store recycled objects close to the start thus statistically
 63        /// reducing how far we will typically search.
 64        /// </remarks>
 65        internal T Allocate()
 066        {
 067            var items = _items;
 68            T? inst;
 69
 070            for (int i = 0; i < items.Length; i++)
 071            {
 72                // Note that the read is optimistically not synchronized. That is intentional.
 73                // We will interlock only when we have a candidate. in a worst case we may miss some
 74                // recently returned objects. Not a big deal.
 075                inst = items[i].Value;
 076                if (inst != null)
 077                {
 078                    if (inst == Interlocked.CompareExchange(ref items[i].Value, null, inst))
 079                    {
 080                        goto gotInstance;
 81                    }
 082                }
 083            }
 84
 085            inst = CreateInstance();
 086        gotInstance:
 87
 088            return inst;
 089        }
 90
 91        /// <summary>
 92        /// Returns objects to the pool.
 93        /// </summary>
 94        /// <remarks>
 95        /// Search strategy is a simple linear probing which is chosen for it cache-friendliness.
 96        /// Note that Free will try to store recycled objects close to the start thus statistically
 97        /// reducing how far we will typically search in Allocate.
 98        /// </remarks>
 99        internal void Free(T obj)
 0100        {
 0101            var items = _items;
 0102            for (int i = 0; i < items.Length; i++)
 0103            {
 0104                if (items[i].Value == null)
 0105                {
 106                    // Intentionally not using interlocked here.
 107                    // In a worst case scenario two objects may be stored into same slot.
 108                    // It is very unlikely to happen and will only mean that one of the objects will get collected.
 0109                    items[i].Value = obj;
 0110                    break;
 111                }
 0112            }
 0113        }
 114    }
 115}
 116