/*******************************************************************************
* Copyright (c) 2000, 2006 IBM Corporation and others.
* 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.core.internal.utils;
import java.util.Collections;
import java.util.Iterator;
/**
* A Queue of objects.
*/
public class Queue {
protected Object[] elements;
protected int head;
protected int tail;
protected boolean reuse;
public Queue() {
this(20, false);
}
/**
* The parameter reuse indicates what do you want to happen with the object reference when you
* remove it from the queue. If reuse is false the queue no longer holds a reference to the
* object when it is removed. If reuse is true you can use the method getNextAvailableObject to
* get an used object, set its new values and add it again to the queue.
*/
public Queue(int size, boolean reuse) {
elements= new Object[size];
head= tail= 0;
this.reuse= reuse;
}
public void add(Object element) {
int newTail= increment(tail);
if (newTail == head) {
grow();
newTail= tail + 1;
}
elements[tail]= element;
tail= newTail;
}
/**
* This method does not affect the queue itself. It is only a helper to decrement an index in
* the queue.
*/
public int decrement(int index) {
return (index == 0) ? (elements.length - 1) : index - 1;
}
public Object elementAt(int index) {
return elements[index];
}
public Iterator iterator() {
/**/
if (isEmpty())
return Collections.EMPTY_LIST.iterator();
/* if head < tail we can use the same array */
if (head <= tail)
return new ArrayIterator(elements, head, tail - 1);
/* otherwise we need to create a new array */
Object[] newElements= new Object[size()];
int end= (elements.length - head);
System.arraycopy(elements, head, newElements, 0, end);
System.arraycopy(elements, 0, newElements, end, tail);
return new ArrayIterator(newElements);
}
/**
* Returns an object that has been removed from the queue, if any. The intention is to support
* reuse of objects that have already been processed and removed from the queue. Returns null if
* there are no available objects.
*/
public Object getNextAvailableObject() {
int index= tail;
while (index != head) {
if (elements[index] != null) {
Object result= elements[index];
elements[index]= null;
return result;
}
index= increment(index);
}
return null;
}
protected void grow() {
int newSize= (int)(elements.length * 1.5);
Object[] newElements= new Object[newSize];
if (tail >= head)
System.arraycopy(elements, head, newElements, head, size());
else {
int newHead= newSize - (elements.length - head);
System.arraycopy(elements, 0, newElements, 0, tail + 1);
System.arraycopy(elements, head, newElements, newHead, (newSize - newHead));
head= newHead;
}
elements= newElements;
}
/**
* This method does not affect the queue itself. It is only a helper to increment an index in
* the queue.
*/
public int increment(int index) {
return (index == (elements.length - 1)) ? 0 : index + 1;
}
public int indexOf(Object target) {
if (tail >= head) {
for (int i= head; i < tail; i++)
if (target.equals(elements[i]))
return i;
} else {
for (int i= head; i < elements.length; i++)
if (target.equals(elements[i]))
return i;
for (int i= 0; i < tail; i++)
if (target.equals(elements[i]))
return i;
}
return -1;
}
public boolean isEmpty() {
return tail == head;
}
public Object peek() {
return elements[head];
}
public Object peekTail() {
return elements[decrement(tail)];
}
public Object remove() {
if (isEmpty())
return null;
Object result= peek();
if (!reuse)
elements[head]= null;
head= increment(head);
return result;
}
public Object removeTail() {
Object result= peekTail();
tail= decrement(tail);
if (!reuse)
elements[tail]= null;
return result;
}
public void reset() {
tail= head= 0;
}
public int size() {
return tail > head ? (tail - head) : ((elements.length - head) + tail);
}
public String toString() {
StringBuffer sb= new StringBuffer();
sb.append('[');
int count= 0;
if (!isEmpty()) {
Iterator it= iterator();
//only print a fixed number of elements to prevent debugger from choking
while (count < 100) {
sb.append(it.next());
if (it.hasNext())
sb.append(',').append(' ');
else
break;
}
}
if (count < size())
sb.append('.').append('.').append('.');
sb.append(']');
return sb.toString();
}
}