/*******************************************************************************
 * This file is part of TERMINAL RECALL
 * Copyright (c) 2012-2014 Chuck Ritola
 * Part of the jTRFP.org project
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl.html
 * 
 * Contributors:
 *     chuck - initial API and implementation
 ******************************************************************************/
package org.jtrfp.trcl.pool;

import java.util.NoSuchElementException;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;

public class IndexPool{
	private final Queue<Integer> 	freeIndices	= new LinkedBlockingQueue<Integer>();
	private volatile int 		maxCapacity	= 1;
	private volatile int 		highestIndex	= -1;
	private GrowthBehavior 		growthBehavior	= new GrowthBehavior()
		{public int grow(int index){return index*2;}};//Default is to double each time.
	
	public IndexPool(){
	}
		
    public int pop() {
	try {
	    return freeIndices.remove();
	} catch (NoSuchElementException e) {
	    synchronized (this) {
		if (highestIndex + 1 < maxCapacity)
		    return availablePop();
		else return growthPop();
	    }//end sync(this)
	}//end catch{no element}
    }// end pop()
	
	private int availablePop()
	    {return (++highestIndex);}
	
	private int growthPop(){
	    maxCapacity = growthBehavior.grow(maxCapacity);
	    return pop();//Try again.
	}//end grothPop()
	
	public int free(int index){
	    	if(freeIndices.contains(index)){
		    throw new RuntimeException("Double-release of resources: "+index);
		}
		    freeIndices.add(index);return index;}
	
	public static interface GrowthBehavior
		{int grow(int previousMaxCapacity);}
	public void setGrowthBehavior(GrowthBehavior gb){growthBehavior=gb;}

	public synchronized int popConsecutive(int numNewItems) {
	    //TODO This should use the freed pool instead of always allocating new
	    if(highestIndex+numNewItems<maxCapacity)
		{final int result = highestIndex+1; highestIndex+=numNewItems;
		return result;}
	    else//Need to allocate a new block of indices
		{maxCapacity = growthBehavior.grow(maxCapacity);
		return popConsecutive(numNewItems);//Try again.
		}
	}//end popConsecutive(...)

	/**
	 * @return the maxCapacity
	 */
	public int getMaxCapacity() {
	    return maxCapacity;
	}
}//end IndexPool

@@ -660,16 +660,35 @@
 va.util.
+concurrent.Blocking
 Queue;%0Ai
@@ -775,16 +775,24 @@
 e final 
+Blocking
 Queue%3CIn
@@ -798,17 +798,16 @@
 nteger%3E 
-%09
 freeIndi
@@ -809,17 +809,16 @@
 eIndices
-%09
 = new Li
@@ -1082,164 +1082,826 @@
 e.%0A%09
-%0A%09public IndexPool()%7B%0A%09%7D%0A%09%09%0A    public int pop() %7B%0A%09try %7B%0A%09    return freeIndices.remove();%0A%09%7D catch (NoSuchElementException e) %7B%0A%09    synchronized (this) %7B
+private int hardLimit=Integer.MAX_VALUE;//Basically no hard limit by default%0A%09%0A%09public IndexPool()%7B%0A%09%7D%0A%09%0A    public int pop()%7B%0A%09try%7Breturn pop(false);%7D%0A%09catch(OutOfIndicesException e)%7B%0A%09    e.printStackTrace();%0A%09    assert false;%0A%09    return -1;%0A%09    %7D//Shouldn't happen.%0A    %7D//end pop()%0A    %0A    public int popOrException() throws OutOfIndicesException%7B%0A%09return pop(true);%0A    %7D%0A    %0A    private int pop(boolean throwException) throws OutOfIndicesException %7B%0A%09try %7B%0A%09    return freeIndices.remove();%0A%09%7D catch (NoSuchElementException e) %7B%0A%09    synchronized (this) %7B%0A%09%09if (highestIndex + 1 %3E= hardLimit)%0A%09%09    if(throwException)throw new OutOfIndicesException();%0A%09%09    else try%7Breturn freeIndices.take();%7D%0A%09%09%09catch(InterruptedException ex)%7B%0A%09%09%09    ex.printStackTrace(); %0A%09%09%09    assert false;%0A%09%09%09    return -1;%0A%09%09%09    %7D
 %0A%09%09i
@@ -3140,16 +3140,327 @@
 ity;%0A%09%7D%0A
+%09%0A%09public static class OutOfIndicesException extends Exception%7B%7D%0A%09/**%0A%09 * @return the hardLimit%0A%09 */%0A%09public int getHardLimit() %7B%0A%09    return hardLimit;%0A%09%7D%0A%0A%09/**%0A%09 * @param hardLimit the hardLimit to set%0A%09 */%0A%09public IndexPool setHardLimit(int hardLimit) %7B%0A%09    this.hardLimit = hardLimit;%0A%09    return this;%0A%09%7D%0A
 %7D//end I

Add support for value ceilings and out-of-indices exception throws ni IndexPool.