using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading; namespace Hazel { /// /// A fairly simple object pool for items that will be created a lot. /// /// The type that is pooled. /// public sealed class ObjectPool where T : IRecyclable { private int numberCreated; public int NumberCreated { get { return numberCreated; } } public int NumberInUse { get { return this.inuse.Count; } } public int NumberNotInUse { get { return this.pool.Count; } } public int Size { get { return this.NumberInUse + this.NumberNotInUse; } } #if HAZEL_BAG private readonly ConcurrentBag pool = new ConcurrentBag(); #else private readonly List pool = new List(); #endif // Unavailable objects private readonly ConcurrentDictionary inuse = new ConcurrentDictionary(); /// /// The generator for creating new objects. /// /// private readonly Func objectFactory; /// /// Internal constructor for our ObjectPool. /// internal ObjectPool(Func objectFactory) { this.objectFactory = objectFactory; } /// /// Returns a pooled object of type T, if none are available another is created. /// /// An instance of T. internal T GetObject() { #if HAZEL_BAG if (!pool.TryTake(out T item)) { Interlocked.Increment(ref numberCreated); item = objectFactory.Invoke(); } #else T item; lock (this.pool) { if (this.pool.Count > 0) { var idx = this.pool.Count - 1; item = this.pool[idx]; this.pool.RemoveAt(idx); } else { Interlocked.Increment(ref numberCreated); item = objectFactory.Invoke(); } } #endif if (!inuse.TryAdd(item, true)) { throw new Exception("Duplicate pull " + typeof(T).Name); } return item; } /// /// Returns an object to the pool. /// /// The item to return. internal void PutObject(T item) { if (inuse.TryRemove(item, out bool b)) { #if HAZEL_BAG pool.Add(item); #else lock (this.pool) { pool.Add(item); } #endif } else { #if DEBUG throw new Exception("Duplicate add " + typeof(T).Name); #endif } } } }