#region CPL License /* Nuclex Framework Copyright (C) 2002-2012 Nuclex Development Labs This library is free software; you can redistribute it and/or modify it under the terms of the IBM Common Public License as published by the IBM Corporation; either version 1.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the IBM Common Public License for more details. You should have received a copy of the IBM Common Public License along with this library */ #endregion using System; using System.Collections.Generic; using System.Text; namespace Nuclex.Support.Collections { /// Pool that recycles objects in order to avoid garbage build-up /// Type of objects being pooled /// /// /// Use this class to recycle objects instead of letting them become garbage, /// creating new instances each time. The Pool class is designed to either be /// used on its own or as a building block for a static class that wraps it. /// /// /// Special care has to be taken to revert the entire state of a recycled /// object when it is returned to the pool. For example, events will need to /// have their subscriber lists emptied to avoid sending out events to the /// wrong subscribers and accumulating more and more subscribers each time /// they are reused. /// /// /// To simplify such cleanup, pooled objects can implement the IRecyclable /// interface. When an object is returned to the pool, the pool will /// automatically call its IRecyclable.Recycle() method. /// /// public class Pool { /// Default number of recyclable objects the pool will store public const int DefaultPoolSize = 64; /// Initializes a new pool using the default capacity /// Delegate that will be used to create new items /// Delegate that will be used to recycle items public Pool(Func createNewDelegate = null, Action recycleDelegate = null) : this(DefaultPoolSize, createNewDelegate, recycleDelegate) { } /// Initializes a new pool using a user-specified capacity /// Capacity of the pool /// Delegate that will be used to create new items /// Delegate that will be used to recycle items public Pool( int capacity, Func createNewDelegate = null, Action recycleDelegate = null ) { Capacity = capacity; if(createNewDelegate == null) { createNewDelegate = new Func(Activator.CreateInstance); } if(recycleDelegate == null) { recycleDelegate = new Action(callRecycleIfSupported); } this.createNewDelegate = createNewDelegate; this.recycleDelegate = recycleDelegate; } /// /// Returns a new or recycled instance of the types managed by the pool /// /// A new or recycled instance public TItem Get() { lock(this) { if(this.items.Count > 0) { return this.items.Dequeue(); } else { return this.createNewDelegate(); } } } /// /// Redeems an instance that is no longer used to be recycled by the pool /// /// The instance that will be redeemed public void Redeem(TItem item) { // Call Recycle() when the object is redeemed (instead of when it leaves // the pool again) in order to eliminate any references the object may hold // to other objects. this.recycleDelegate(item); lock(this) { if(this.items.Count < this.capacity) { this.items.Enqueue(item); } } } /// Number of objects the pool can retain /// /// Changing this value causes the pool to be emtpied. It is recommended that /// you only read the pool's capacity, never change it. /// public int Capacity { get { return this.capacity; } set { this.capacity = value; this.items = new Queue(value); } } /// /// Calls the Recycle() method on an objects if it implements /// the IRecyclable interface /// /// /// Object whose Recycle() method will be called if supported by the object /// private static void callRecycleIfSupported(TItem item) { IRecyclable recycleable = item as IRecyclable; if(recycleable != null) { recycleable.Recycle(); } } /// Objects being retained for recycling private Queue items; /// Capacity of the pool /// /// Required because the Queue class doesn't allow this value to be retrieved /// private int capacity; private Func createNewDelegate; private Action recycleDelegate; } } // namespace Nuclex.Support.Collections