using System;
using System.Collections.Generic;
namespace Developpez.Dotnet.ComponentModel
{
///
/// Gestionnaire d'un pool d'objet générique
///
/// Type des objets à placer dans le gestionnaire
public class ParameterizedGenericPool
{
///
/// Conteneur contenant l'objet du pool
///
public class GenericPoolItem : IDisposable
{
LinkedListNode node = null;
///
/// Node utilisée pour rattacher l'objet au pool
///
public virtual LinkedListNode Node
{
get
{
if (node == null)
node = new LinkedListNode(this);
return node;
}
set { node = value; }
}
///
/// Objet placé dans le Pool
///
public virtual T Value { get; protected set; }
///
/// Gestionnaire parent
///
public virtual ParameterizedGenericPool Parent{get;protected set;}
///
/// Initialise une nouvelle instance de conteneur
///
/// Element à placer
/// Gestionnaire parent
public GenericPoolItem(T newItem, ParameterizedGenericPool parent)
{
Value = newItem;
Parent = parent;
Node = null;
}
///
/// Repasse l'objet d'un état "libéré" à une état "non libéré"
///
public virtual void UnDispose()
{
disposed = false;
}
bool disposed = false;
///
/// Destructeur
///
~GenericPoolItem()
{
if (Environment.HasShutdownStarted)
return;
if (Parent.CanAddItem && Parent.AppendItemToPool(Node))
{
GC.ReRegisterForFinalize(this);
}
}
///
/// Passe l'objet à un état "libéré" et le replace dans le pool d'objets
///
public void Dispose()
{
if (!disposed)
{
disposed = true;
if (Parent.AppendItemToPool(this))
{
GC.SuppressFinalize(this);
}
}
}
}
///
/// Méthode servant à la création d'un nouvel objet dans le pool
///
/// Objet crée
public delegate T CreateNewItemMethod();
///
/// Pool d'objets
///
protected virtual LinkedList Pool { get; private set; }
///
/// Nombre d'objets actuellement présents dans le pool
///
public virtual int PoolCount
{
get
{
return Pool.Count;
}
}
///
/// Rajoute un objet dans le pool
///
/// Objet à rajouter
/// true si l'opération a réussit, false sinon
protected virtual bool AppendItemToPool(GenericPoolItem item)
{
lock (Pool)
{
if (CanAddItem)
{
Pool.AddFirst(item);
return true;
}
else
{
return false;
}
}
}
///
/// Indique si l'état actuel du gestionnaire permet d'y rajouter un objet.
/// (S'il y a déjà un nombre maximal d'éléments dans le pool, aucun ajout ne sera possible)
///
public virtual bool CanAddItem
{
get
{
if (Pool.Count >= MaxCachedItemCount)
return false;
else
return true;
}
}
///
/// Rajoute un objet dans le pool
///
/// Objet à rajouter
/// true si l'opération a réussit, false sinon
protected virtual bool AppendItemToPool(LinkedListNode item)
{
lock (Pool)
{
if (CanAddItem)
{
Pool.AddFirst(item);
return true;
}
else
return false;
}
}
///
/// Renvoie un objet du pool
///
/// Un objet du pool, ou null si aucun objet n'est disponible dans le pool
protected virtual GenericPoolItem GetItemFromPool()
{
lock (Pool)
{
if (Pool.Count <= 0)
return null;
else
{
GenericPoolItem res = Pool.Last.Value;
Pool.RemoveLast();
res.UnDispose();
return res;
}
}
}
///
/// Nombre d'objets initialement présents dans le pool
///
public virtual int BaseCachedItemCount { get; protected set; }
///
/// Nombre d'objets maximum dans le pool
///
public virtual int MaxCachedItemCount { get; protected set; }
///
/// Function servant à créer de nouveaux objets pour le pool
///
protected virtual CreateNewItemMethod NewItemAllocator { get; set; }
///
/// Crée une nouvel instance du gestionnaire de pool générique
///
/// Objets alloués au démarrage
/// Nombre maximum d'objets avant que ceux-ci ne soient relachés
/// allocateur
public ParameterizedGenericPool(int basePooledItemCount, int maxPooledItemCount, CreateNewItemMethod newItemAllocator)
{
if (newItemAllocator == null)
throw new ArgumentNullException("newItemAllocator");
if (basePooledItemCount < 1)
throw new ArgumentOutOfRangeException("basePooledItemCount");
if (maxPooledItemCount < basePooledItemCount)
throw new ArgumentOutOfRangeException("maxPooledItemCount");
MaxCachedItemCount = maxPooledItemCount;
BaseCachedItemCount = basePooledItemCount;
NewItemAllocator = newItemAllocator;
Pool = new LinkedList.GenericPoolItem>();
GenericPoolItem myItem;
LinkedListNode newNode;
for (int i = 0; i < basePooledItemCount; i++)
{
newNode = new LinkedListNode(
myItem = new GenericPoolItem(NewItemAllocator.Invoke(), this));
myItem.Node = newNode;
Pool.AddFirst(newNode);
}
}
///
/// Obtient un objet à partir du pool, ou en crée un nouveau si aucun n'est disponible
///
/// Un objet du pool, ou un nouvel objet si aucun n'est disponible
public virtual GenericPoolItem ObtainItem()
{
return ObtainItem(true);
}
///
/// Obtient un objet dans le pool
///
/// Si le pool est vide et que canCreateNew vaut true, un nouvel
/// objet est crée. Sinon, null est renvoyé
/// Objet du pool, ou null si aucun objet n'est disponible et canCreateNew vaut false
public virtual GenericPoolItem ObtainItem(bool canCreateNew)
{
GenericPoolItem item = GetItemFromPool();
if (item != null || !canCreateNew)
{
return item;
}
else
{
item = InternalNewItem();
return item;
}
}
///
/// Crée un nouvel objet pour le pool
///
/// Nouvel objet crée
protected virtual GenericPoolItem InternalNewItem()
{
return new GenericPoolItem(NewItemAllocator.Invoke(), this);
}
}
///
/// Gestionnaire d'un pool d'objet générique. Les objets doivent avoir
/// un constructeur sans paramètre.
/// Si aucun constructeur sans paramètre n'est possible, utilisez la classe
///
/// Type d'objet à gérer
public class GenericPool : ParameterizedGenericPool where T : new()
{
///
/// Crée une nouvel instance du gestionnaire de pool générique.
/// Par défaut 1 objet est présent dans le pool et 10 au maximum peuvent être gérés
///
public GenericPool()
: this(1, 10)
{
}
///
/// Crée une nouvel instance du gestionnaire de pool générique
///
/// Objets alloués au démarrage
/// Nombre maximum d'objets avant que ceux-ci ne soient relachés
public GenericPool(int startObjectCount, int maxObjectCount)
: base(startObjectCount, maxObjectCount, new ParameterizedGenericPool.CreateNewItemMethod(delegate
{
return new T();
}))
{
}
}
}