WALA/com.ibm.wala.core/src/com/ibm/wala/util/collections/FifoQueue.java

184 lines
5.9 KiB
Java

/*******************************************************************************
* Copyright (c) 2002 - 2006 IBM Corporation.
* 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 com.ibm.wala.util.collections;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
/**
* FIFO work queue management of Objects that prevents an object from being
* added to the queue if it is already enqueued and has not yet been popped.
*
* @author Marco Pistoia
*/
public class FifoQueue<T> {
/**
* The work queue. Items are references to Object instances.
*/
List<T> qItems = new LinkedList<T>();
/**
* Set representing items currently enqueue. This is used to keep an item from
* having more than one entry in the queue.
*/
Set<T> inQueue = HashSetFactory.make();
/**
* Creates a FIFO queue with no elements enqueued.
*/
public FifoQueue() {
}
/**
* Creates a new FIFO queue containing the argument to this constructor.
*
* @param element
* is the element to add to the queue.
*/
public FifoQueue(T element) {
push(element);
}
/**
* Creates a new FIFO queue containing the elements of the specified
* Collection. The order the elements are inserted into the queue is
* unspecified.
*
* @param collection
* is the Collection of Object instances to be enqueue.
*/
public FifoQueue(Collection<T> collection) {
push(collection.iterator());
}
/**
* Return the current number of enqueued Objects, the number of Objects that
* were pushed into the queue and have not been popped.
*
* @return the current queue size.
* @see #isEmpty
*/
public int size() {
return qItems.size();
}
/**
* Returns whether or not this queue is empty (no enqueued elements).
*
* @return <code>true</code> when there are no enqueued objects.
* <code>false</code> if there are objects remaining in the queue.
* @see #size
*/
public boolean isEmpty() {
return qItems.isEmpty();
}
/**
* Indicate whether the specified element is currently in the queue.
*
* @param element
* determine whether this object is in the queue.
* @return <code>true</code> if <code>element</code> is in the queue.
* Otherwise <code>false</code> if not currently in the queue.
*/
public boolean contains(T element) {
return inQueue.contains(element);
}
/**
* Insert an Object at the tail end of the queue if it is not already in the
* queue. If the Object is already in the queue, the queue remains unmodified.
* <p>
* This method determines whether an element is already in the queue using the
* element's <code>equals()</code> method. If the element's class does not
* implement <code>equals()</code>, the default implementation assumes they
* are equal only if it is the same object.
*
* @param element
* is the Object to be added to the queue if not already present in
* the queue.
*/
public void push(T element) {
// if element is not in inQueue, then add() returns true.
if (inQueue.add(element)) {
qItems.add(element);
}
}
/**
* Insert all of the elements in the specified Iterator at the tail end of the
* queue if not already present in the queue. Any element in the Iterator
* already in the queue is ignored.
* <p>
* This method determines whether an element is already in the queue using the
* element's <code>equals()</code> method. If the element's class does not
* implement <code>equals()</code>, the default implementation assumes they
* are equal if it is the same object.
*
* @param elements
* an Iterator of Objects to be added to the queue if not already
* queued.
*/
public void push(Iterator<? extends T> elements) {
while (elements.hasNext()) {
T element = elements.next();
// if element is not in inQueue, then add() returns true.
if (inQueue.add(element)) {
qItems.add(element);
}
}
}
/**
* Remove the next Object from the queue and return it to the caller. Throws
* <code>IllegalStateException</code> if the queue is empty when this method
* is called.
*
* @return the next Object in the queue.
*/
public T pop() {
// While there are work queue elements, remove the next element &
// indicate that it is no longer in the work queue.
// Throw a IllegalStateException when there is a queue underflow.
if (isEmpty())
throw new IllegalStateException("Unexpected empty queue during pop");
// get & remove the top of the queue.
T element = qItems.get(0);
qItems.remove(0);
// remove element from the elements that are 'inQueue'
inQueue.remove(element);
return element;
}
/**
* Returns the next Object in the queue, but leaves it in the queue. Throws
* <code>IllegalStateException</code> if the queue is empty when this method
* is called.
*
* @return the next Object in the queue.
*/
public T peek() {
// While there are work queue elements, return the next element.
// Throw a IllegalStateException if there is a queue underflow.
if (isEmpty())
throw new IllegalStateException("Unexpected empty queue during peek");
// get & remove the top of the queue.
return qItems.get(0);
}
}