public class LIFOPool<T> : IPool<T>, IFreeness where T : class
{
#region NestedTypes
internal struct LIFOEntry
{
public bool Idle;
public DateTime LastUpdate;
public T Value;
}
#endregion
#region StaticMembers
public const int DefaultMaxSize = 100;
public const int DefaultMinSize = 2;
public static readonly bool IsSubOfIDisposable;
static LIFOPool()
{
IsSubOfIDisposable = typeof(T).IsSubclassOf(typeof(IDisposable));
}
#endregion
#region Fields
private WeakEvent<EventHandler> eventFull;
private LookupItem<T> lookupItem;
private ReleaseItem<T> releaseItem;
private double lifeTime;
private int minSize, maxSize, offset, freeTimeout;
private GCHandle[] weakHandle;
private LIFOEntry[] container;
private ReaderWriterLockSlim locker;
#endregion
#region Properties
public event EventHandler Full
{
add
{
if (eventFull == null)
{
Interlocked.CompareExchange<WeakEvent<EventHandler>>(ref eventFull, new WeakEvent<EventHandler>(), null);
}
eventFull.Add(value);
}
remove
{
if (eventFull != null)
{
eventFull.Remove(value);
}
}
}
public double LifeTime
{
set { Interlocked.Exchange(ref lifeTime, value); }
get { return lifeTime; }
}
int IFreeness.Capacity
{
get { return maxSize; }
}
public int MinSize
{
get { return minSize; }
}
public int MaxSize
{
get { return maxSize; }
}
public int Size
{
get { return offset + 1; }
}
public bool IsFull
{
get { return offset + 1 == maxSize; }
}
public int FreeTimeout
{
set { Interlocked.Exchange(ref freeTimeout, value); }
get { return freeTimeout; }
}
#endregion
#region Constructor
public LIFOPool(LookupItem<T> createDelegate, ReleaseItem<T> releaseDelegate)
: this(DefaultMinSize, DefaultMaxSize, createDelegate, releaseDelegate)
{
}
public LIFOPool(int min, int max, LookupItem<T> lookupDelegate, ReleaseItem<T> releaseDelegate)
{
if (lookupDelegate ="color: #000000;">== null)
{
throw new ArgumentNullException("Lookup delegate can't be null.");
}
T t1 = lookupDelegate(), t2 = lookupDelegate();
if (object.ReferenceEquals(t1, t2))
{
throw new ArgumentException("Lookup delegate can't return the same reference object.");
}
lookupItem = lookupDelegate;
releaseItem = releaseDelegate;
lifeTime = Freer.DefaultLifeTime / 2D;
minSize = min;
maxSize = max;
freeTimeout = 2000;
weakHandle = new GCHandle[maxSize / 10];
GCHandle emptyHandle = GCHandle.Alloc(null, GCHandleType.Weak);
for (int i = 0; i < weakHandle.Length; i++)
{
weakHandle[i] = emptyHandle;
}
container = new LIFOEntry[maxSize];
container[0].Idle = container[1].Idle = true;
container[0].LastUpdate = container[1].LastUpdate = DateTime.Now;
container[0].Value = t1;
container[1].Value = t2;
offset++;
locker = new ReaderWriterLockSlim();
}
#endregion
#region Methods
public void Store(T item)
{
if (releaseItem != null)
{
releaseItem(item);
}
locker.EnterUpgradeableReadLock();
try
{
int index = -1;
for (int i = offset; i > 0; i--)
{
if (container[i].Value.Equals(item))
{
locker.EnterWriteLock();
try
{
container[i].Idle = true;
}
finally
{
locker.ExitWriteLock();
}
index = i;
break;
}
}
if (index == -1)
{
locker.EnterWriteLock();
try
{
if (offset + 1 == maxSize && (eventFull == null || !eventFull.Raise(this, EventArgs.Empty)))
{
throw new PoolFullException();
}
container[offset].Idle = true;
container[offset].LastUpdate = DateTime.Now;
container[offset++].Value = item;
}
finally
{
locker.ExitWriteLock();
}
}
}
finally
{
locker.ExitUpgradeableReadLock();
}
}
public T Retrieve()
{
T item = null;
locker.EnterReadLock();
try
{
for (int i = 0; i < weakHandle.Length; i++)
{
if (weakHandle[i].Target != null)
{
weakHandle[i].Target = null;
item = (T)weakHandle[i].Target;
break;
}
}
}
finally
{
locker.ExitReadLock();
}
if (item == null)
{
locker.EnterUpgradeableReadLock();
try
{
if (offset + 1 == maxSize && (eventFull == null || !eventFull.Raise(this, EventArgs.Empty)))
{
throw new PoolFullException();
}
for (int i = offset; i > 0; i--)
{
if (container[i].Idle)
{
locker.EnterWriteLock();
try
{
container[i].Idle = false;
container[i].LastUpdate = DateTime.Now;
}
finally
{
locker.ExitWriteLock();
}
item = container[i].Value;
break;
}
}
if (item == null)
{
locker.EnterWriteLock();
try
{
container[offset].Idle = false;
container[offset].LastUpdate = DateTime.Now;
item = container[offset++].Value = lookupItem();
}
finally
{
locker.ExitWriteLock();
}
}
}
finally
{
locker.ExitUpgradeableReadLock();
}
}
return item;
}
public int Free()
{
int freed = 0;
if (lifeTime != Timeout.Infinite && offset > minSize - 1)
{
List<T> list = null;
if (locker.TryEnterWriteLock(freeTimeout))
{
try
{
LIFOEntry entry;
for (int i = 0; i <= offset; i++)
{
entry = container[i];
if (entry.LastUpdate.AddSeconds(lifeTime).CompareTo(DateTime.Now) <= 0)
{
if (IsSubOfIDisposable && entry.Idle)
{
if (list == null)
{
list = new List<T>();
}
list.Add(container[i].Value);
}
int j = i;
while (j < offset)
{
entry = container[j];
int nextJ = ++j;
container[j] = container[nextJ];
container[nextJ] = entry;
}
for (j = 0; j < weakHandle.Length; j++)
{
if (weakHandle[i].Target == null)
{
weakHandle[i].Target = container[offset].Value;
container[offset].Value = null;
break;
}
}
freed++;
if (offset-- <= minSize)
{
break;
}
}
}
}
finally
{
locker.ExitWriteLock();
}
}
if (list != null)
{
list.ForEach(item => ((IDisposable)item).Dispose());
}
}
return freed;
}
#endregion
}