package org.andengine.util.adt.pool; import java.util.ArrayList; import java.util.Collections; import org.andengine.BuildConfig; import org.andengine.util.debug.Debug; /** * (c) 2010 Nicolas Gramlich * (c) 2011 Zynga Inc. * * @author Valentin Milea * @author Nicolas Gramlich * * @since 22:19:55 - 31.08.2010 */ public abstract class GenericPool<T> { // =========================================================== // Constants // =========================================================== // =========================================================== // Fields // =========================================================== private final ArrayList<T> mAvailableItems; private final int mGrowth; private final int mAvailableItemCountMaximum; private int mUnrecycledItemCount; // =========================================================== // Constructors // =========================================================== public GenericPool() { this(0); } public GenericPool(final int pInitialSize) { this(pInitialSize, 1); } public GenericPool(final int pInitialSize, final int pGrowth) { this(pInitialSize, pGrowth, Integer.MAX_VALUE); } public GenericPool(final int pInitialSize, final int pGrowth, final int pAvailableItemsMaximum) { if(pGrowth <= 0) { throw new IllegalArgumentException("pGrowth must be greater than 0!"); } if(pAvailableItemsMaximum < 0) { throw new IllegalArgumentException("pAvailableItemsMaximum must be at least 0!"); } this.mGrowth = pGrowth; this.mAvailableItemCountMaximum = pAvailableItemsMaximum; this.mAvailableItems = new ArrayList<T>(pInitialSize); if(pInitialSize > 0) { this.batchAllocatePoolItems(pInitialSize); } } // =========================================================== // Getter & Setter // =========================================================== public synchronized int getUnrecycledItemCount() { return this.mUnrecycledItemCount; } public synchronized int getAvailableItemCount() { return this.mAvailableItems.size(); } public int getAvailableItemCountMaximum() { return this.mAvailableItemCountMaximum; } // =========================================================== // Methods for/from SuperClass/Interfaces // =========================================================== protected abstract T onAllocatePoolItem(); // =========================================================== // Methods // =========================================================== /** * @param pItem every item passes this method just before it gets recycled. */ protected void onHandleRecycleItem(final T pItem) { } protected T onHandleAllocatePoolItem() { return this.onAllocatePoolItem(); } /** * @param pItem every item that was just obtained from the pool, passes this method. */ protected void onHandleObtainItem(final T pItem) { } public synchronized void batchAllocatePoolItems(final int pCount) { final ArrayList<T> availableItems = this.mAvailableItems; int allocationCount = this.mAvailableItemCountMaximum - availableItems.size(); if(pCount < allocationCount) { allocationCount = pCount; } for(int i = allocationCount - 1; i >= 0; i--) { availableItems.add(this.onHandleAllocatePoolItem()); } } public synchronized T obtainPoolItem() { final T item; if(this.mAvailableItems.size() > 0) { item = this.mAvailableItems.remove(this.mAvailableItems.size() - 1); } else { if(this.mGrowth == 1 || this.mAvailableItemCountMaximum == 0) { item = this.onHandleAllocatePoolItem(); } else { this.batchAllocatePoolItems(this.mGrowth); item = this.mAvailableItems.remove(this.mAvailableItems.size() - 1); } if(BuildConfig.DEBUG) { Debug.v(this.getClass().getName() + "<" + item.getClass().getSimpleName() +"> was exhausted, with " + this.mUnrecycledItemCount + " item not yet recycled. Allocated " + this.mGrowth + " more."); } } this.onHandleObtainItem(item); this.mUnrecycledItemCount++; return item; } public synchronized void recyclePoolItem(final T pItem) { if(pItem == null) { throw new IllegalArgumentException("Cannot recycle null item!"); } this.onHandleRecycleItem(pItem); if(this.mAvailableItems.size() < this.mAvailableItemCountMaximum) { this.mAvailableItems.add(pItem); } this.mUnrecycledItemCount--; if(this.mUnrecycledItemCount < 0) { Debug.e("More items recycled than obtained!"); } } public synchronized void shufflePoolItems() { Collections.shuffle(this.mAvailableItems); } // =========================================================== // Inner and Anonymous Classes // =========================================================== }