/**
*
*/
package net.varkhan.base.containers.queue;
import net.varkhan.base.containers.Iterator;
import java.util.NoSuchElementException;
/**
* <b>A generic array-backed unbounded FIFO queue.</b>
* <p/>
* This class uses an extensible backing array to provide the semantics of a FIFO
* queue. Elements are added at the tail of the queue, and are removed from the
* head.
* <p/>
* When the number of elements reaches the size of the backing array, the array
* is expanded. It does not shrink when elements are removed, but can be made to
* fit the number of elements in the queue by calling the {@link #pack()} method.
* <p/>
*
* @author varkhan
* @date Mar 13, 2009
* @time 8:02:11 AM
*/
public class OpenBuffer<Type> implements Queue<Type> {
private static final int DEFAULT_CAPACITY=8;
/**
* The heap array growth factor
*/
private final float growthfactor;
/**
* The heap array.
*/
private Object[] heap;
/**
* The number of elements in this queue.
*/
private int size=0;
/**
* The starting point of the queue in the array.
*/
private int base=0;
/**********************************************************************************
** Constructors
**/
/**
* Creates a new empty queue with a given capacity
*
* @param capacity the initial capacity of this queue.
* @param growthfactor the multiplicative resizing factor for the queue storage array
*/
public OpenBuffer(int capacity, float growthfactor) {
if(growthfactor<1.0f) growthfactor=1.0f;
this.growthfactor=growthfactor;
this.heap=new Object[capacity];
}
/**
* Creates a new empty queue with a given capacity and using the natural order.
*
* @param capacity the initial capacity of this queue.
*/
public OpenBuffer(int capacity) {
this.growthfactor=1.5f;
this.heap=new Object[capacity];
}
/**
* Creates a new empty queue with a given capacity and using the natural order.
*/
public OpenBuffer() {
this.growthfactor=1.5f;
this.heap=new Object[DEFAULT_CAPACITY];
}
/**********************************************************************************
** Global information accessors
**/
/**
* Return the queue size
*
* @return the number of objects in the queue
*/
public long size() {
return size;
}
/**
* Indicates whether this container is empty.
*
* @return {@literal true} if this container contains no entry,
* {@literal false} otherwise
*/
public boolean isEmpty() {
return size<=0;
}
/**
* Removes all objects from the queue
*/
public final void clear() {
size=0;
base=0;
}
/**
* Resize the internal storage array(s) so that this object takes the minimal space possible
*/
public void pack() {
if(heap.length>size) {
int end=base+size;
if(end<=heap.length) {
Object[] newheap=new Object[size];
System.arraycopy(heap, base, newheap, 0, size);
heap=newheap;
}
else {
Object[] newheap=new Object[size];
System.arraycopy(heap, base, newheap, 0, heap.length-base);
System.arraycopy(heap, 0, newheap, heap.length-base, end-heap.length);
heap=newheap;
}
base=0;
}
}
/**********************************************************************************
** Queue mechanism
**/
/**
* Adds an object on the queue.
*
* @param obj the object to add
*
* @return {@literal true}
*/
public final boolean add(Type obj) {
int pos=base+size;
if(pos<heap.length) {
heap[pos]=obj;
size++;
}
else if(size<heap.length) {
heap[pos-heap.length]=obj;
size++;
}
else {
Object[] newheap=new Object[(int) ((size+1)*growthfactor)];
System.arraycopy(heap, base, newheap, 0, heap.length-base);
System.arraycopy(heap, 0, newheap, heap.length-base, pos-heap.length);
heap=newheap;
base=0;
heap[size++]=obj;
}
return true;
}
/**
* Removes and return the smallest object on the queue
*
* @return the smallest object on the queue
*/
public final Type poll() {
if(size==0) throw new NoSuchElementException();
@SuppressWarnings("unchecked")
final Type obj=(Type) heap[base];
heap[base]=null;
base++;
if(base>=heap.length) base=0;
size--;
return obj;
}
/**
* Returns, without removing it, the smallest object on the queue
*
* @return the smallest object on the queue
*/
@SuppressWarnings("unchecked")
public final Type peek() {
if(size==0) throw new NoSuchElementException();
return (Type) heap[base];
}
/**********************************************************************************
** Iterator operations
**/
/**
* Returns an element at a given position
*
* @param pos the position in the queue
*
* @return the element at position {@code pos}
*/
@SuppressWarnings("unchecked")
public Type get(int pos) {
if(pos>=size) throw new ArrayIndexOutOfBoundsException(pos);
pos+=base;
if(pos<heap.length) return (Type) heap[pos];
else return (Type) heap[pos-heap.length];
}
/**
* Returns an iterator over the elements of this queue
*
* @return an Iterator
*/
public Iterator<Type> iterator() {
return new Iterator<Type>() {
private int pos=0;
public boolean hasNext() {
return pos<size;
}
@SuppressWarnings("unchecked")
public Type next() {
if(base+pos<heap.length) return (Type) heap[base+(pos++)];
else return (Type) heap[base+(pos++)-heap.length];
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
/**
* Iterate over each element of the queue, and pass it as argument to a
* visitor's {@link Visitor#invoke(Object, Object)} method, until this method returns
* a negative count.
*
*
* @param vis the visitor
* @param par the control parameter
*
* @return the sum of all positive return values from the visitor
*/
@SuppressWarnings("unchecked")
public <Par> long visit(Visitor<Type,Par> vis, Par par) {
int pos=0;
long c=0;
while(pos<size) {
Type obj;
if(base+pos<heap.length) obj=(Type) heap[base+(pos++)];
else obj=(Type) heap[base+(pos++)-heap.length];
long r=vis.invoke(obj, par);
if(r<0) return c;
c+=r;
}
return c;
}
/**
* Returns a string representation of the queue
*
* @return the string representation of the array of values in the queue
*/
public String toString() {
return net.varkhan.base.containers.array.Arrays.toString(heap);
}
}