/*******************************************************************************
* Copyright (c) 2009 Centrum Wiskunde en Informatica (CWI)
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Arnold Lankamp - interfaces and implementation
*******************************************************************************/
package org.rascalmpl.value.util;
/**
* A simple (fast) queue.
*
* @author Arnold Lankamp
*
* @param <T> The value type.
*/
public final class RotatingQueue<T>{
private final static int DEFAULT_CAPACITY = 16;
private final static int DEFAULT_CAPACITY_MASK = DEFAULT_CAPACITY - 1;
private T[] queue;
private int capacity;
private int capacityMask;
private int nextPutIndex;
private int getIndex;
/**
* Constructor.
*/
public RotatingQueue(){
super();
capacity = DEFAULT_CAPACITY;
capacityMask = DEFAULT_CAPACITY_MASK;
queue = (T[]) new Object[capacity];
nextPutIndex = 1;
getIndex = 0;
}
private void ensureCapacity(){
if(nextPutIndex == getIndex){
int size = capacity;
capacity <<= 1;
capacityMask = capacity - 1;
T[] newQueue = (T[]) new Object[capacity];
if(getIndex == 0){
System.arraycopy(queue, 0, newQueue, 0, queue.length);
nextPutIndex = size;
}else{
int numElemsTillEnd = size - getIndex;
System.arraycopy(queue, getIndex, newQueue, 0, numElemsTillEnd);
System.arraycopy(queue, 0, newQueue, numElemsTillEnd, getIndex);
getIndex = 0;
nextPutIndex = size;
}
queue = newQueue;
}
}
/**
* Enqueues the given element.
*
* @param element
* The element to enqueue.
*/
public void put(T element){
ensureCapacity();
queue[nextPutIndex] = element;
nextPutIndex = (nextPutIndex + 1) & capacityMask;
}
/**
* Check if the queue contains any elements.
*
* @return True if the queue contains any elements; false otherwise.
*/
public boolean isEmpty(){
return (nextPutIndex == ((getIndex + 1) & capacityMask));
}
/**
* Returns and removes the next element from the queue.
*
* @return The next element from the queue; null if the queue was empty.
*/
public T get(){
if(isEmpty()) return null;
getIndex = (getIndex + 1) & capacityMask;
T element = queue[getIndex];
queue[getIndex] = null;
return element;
}
}