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
}
}
}
}