using Implab.Parallels;
using System;
using System.Threading;
namespace Implab.Components {
///
/// The base class for creating object pools.
///
///
/// The objects pool is offers frequently requested objects to be reused, this gives
/// a gool speed improvement for the 'heavy' objects. To avoid memory overhead the pool uses
/// weak references allowing CG to do it's work. If there are no free objects in the pool
/// they are created on demand.
///
/// Implementors need to defined a method
///
/// The instances of this class are thred-safe.
///
public abstract class ObjectPool where T : class {
readonly AsyncQueue m_queue = new AsyncQueue();
readonly int m_size;
int m_count = 0;
protected ObjectPool() : this(Environment.ProcessorCount+1) {
}
protected ObjectPool(int size) {
Safe.ArgumentInRange(size > 0, nameof(size));
m_size = size;
}
///
/// Creates the instance if there are no free ones in the pool.
///
/// The new instance.
protected abstract T CreateInstance();
///
/// Cleanups the instance.
///
/// The instance to cleanup and prepare it for the next use.
protected virtual void CleanupInstance(T instance) {
}
///
/// Allocate free instance from the pool or reates a new one.
///
public T Allocate() {
WeakReference reference;
while (m_queue.TryDequeue(out reference)) {
Interlocked.Decrement(ref m_count);
object instance = reference.Target;
if (instance == null)
continue;
return (T)instance;
}
return CreateInstance();
}
///
/// Release the specified instance and returns it to the pool of free instances.
///
/// The instance to return to the pool.
/// Before the instance is returned to the pool the is called.
public void Release(T instance) {
if (m_count < m_size && instance != null) {
Interlocked.Increment(ref m_count);
CleanupInstance(instance);
m_queue.Enqueue(new WeakReference(instance));
}
}
}
}