using System; using System.Collections.Generic; namespace NobleMuffins.LimbHacker.Guts { public class CollectionPool where TCollection: class, ICollection { private readonly object key = new object (); private readonly int poolSize; private readonly TCollection[] poolTable; private readonly bool[] useTable; private readonly Func instantiateWithCapacity; private readonly Func getCapacity; public CollectionPool (int poolSize, Func getCapacity, Func instantiateWithCapacity) { this.poolSize = poolSize; this.getCapacity = getCapacity; this.instantiateWithCapacity = instantiateWithCapacity; poolTable = new TCollection[poolSize]; useTable = new bool[poolSize]; } public DisposableBundle Get (int desiredCapacity) { TCollection o = null; lock (key) { for(int i = 0; i < poolSize; i++) { if(!useTable[i] && !object.ReferenceEquals(poolTable[i], null) && getCapacity(poolTable[i]) >= desiredCapacity) { o = poolTable[i]; o.Clear(); useTable[i] = true; break; } } } if(o == null) { o = instantiateWithCapacity(desiredCapacity); } return new DisposableBundle(o, Release); } public IDisposable Get(int desiredCapacity, out TCollection collection) { var bundle = Get(desiredCapacity); collection = bundle.Object; return bundle; } private void Release (TCollection o) { lock(key) { var foundPlace = false; //First try to find its place, if it's already in the pool table. for(int i = 0; i < poolSize; i++) { if(object.ReferenceEquals(poolTable[i], o)) { useTable[i] = false; foundPlace = true; break; } } //If that failed, than try to find an empty slot. if(foundPlace == false) { for(int i = 0; i < poolSize; i++) { if(object.ReferenceEquals(poolTable[i], null)) { poolTable[i] = o; useTable[i] = false; foundPlace = true; break; } } } //If that failed, than try to find a smaller collection that isn't in use and replace it. if(foundPlace == false) { for(int i = 0; i < poolSize; i++) { if(!useTable[i] && !object.ReferenceEquals(poolTable[i], null) && poolTable[i].Count < o.Count) { poolTable[i] = o; break; } } } } } } }