/* XXL: The eXtensible and fleXible Library for data processing Copyright (C) 2000-2011 Prof. Dr. Bernhard Seeger Head of the Database Research Group Department of Mathematics and Computer Science University of Marburg Germany This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; If not, see <http://www.gnu.org/licenses/>. http://code.google.com/p/xxl/ */ package xxl.core.collections.queues; import xxl.core.util.ArrayResizer; /** * This class provides a resizable-array implementation of the Queue * interface with a FIFO (<i>first in, first out</i>) strategy. It * implements the <tt>peek</tt> method. * In addition to implementing the Queue interface, this class provides methods * to directly access the array that is internally used to store the data.<p> * * Each ArrayQueue instance has a capacity. The capacity is the size of * the array used to store the elements in the queue. It is always at * least as large as the queue size. When elements are inserted into an * ArrayQueue, its capacity may grow automatically. The details of the * growth policy are specified by the ArrayResizer.<p> * * The array is used as a circular storage for the queue to avoid the * shift of the whole queue when the first element is removed. Therefore a * field is needed to store the index of the first element in the array.<p> * * Example usage (1). * <pre> * // create a new array * * Integer[] array = new Integer[] { * new Integer(1), * new Integer(2), * new Integer(3), * new Integer(4), * new Integer(5) * }; * * // create a new array queue with the given array * * ArrayQueue<Integer> queue = new ArrayQueue<Integer>(array); * * // open the queue * * queue.open(); * * // print all elements of the queue * * while (!queue.isEmpty()) * System.out.println(queue.dequeue()); * * System.out.println(); * * // close the open queue after use * * queue.close(); * </pre> * * Example usage (2). * <pre> * // create a new array queue with the first three elements of the given array * * queue = new ArrayQueue<Integer>(3, array); * * // open the queue * * queue.open(); * * // print all elements of the queue * * while (!queue.isEmpty()) * System.out.println(queue.dequeue()); * * System.out.println(); * * // close the open queue after use * * queue.close(); * </pre> * * Example usage (3). * <pre> * // create a new iterator containing the elements of the given array * * Cursor<Integer> cursor = new ArrayCursor<Integer>(array); * * // create a new empty array queue * * queue = new ArrayQueue<Integer>(); * * // open the queue * * queue.open(); * * for (; cursor.hasNext(); queue.enqueue(cursor.next())); * * // print all elements of the queue * * while (!queue.isEmpty()) * System.out.println(queue.dequeue()); * * System.out.println(); * * // close the open queue and cursor after use * * queue.close(); * cursor.close(); * </pre> * * Example usage (4). * <pre> * // create a new empty queue with a growth policy managed by new ArrayResizer(0.5, 0.6, 0.4) * * queue = new ArrayQueue<Integer>(0.5, 0.6, 0.4); * * // open the queue * * queue.open(); * * // insert and remove 20 elements and print after each operation the size of the queue and * // the internally used array * * System.out.println("queue.size()="+queue.size()+" & " * +"queue.array.length="+queue.array.length); * for (int i = 1; i < 21; i++) { * queue.enqueue(new Integer(i)); * System.out.println("queue.size()="+queue.size()+" & " * +"queue.array.length="+queue.array.length); * } * while (!queue.isEmpty()) { * queue.dequeue(); * System.out.println("queue.size()="+queue.size()+" & " * +"queue.array.length="+queue.array.length); * } * * System.out.println(); * * // close the open queue after use * * queue.close(); * </pre> * * @param <E> the type of the elements of this queue. * @see xxl.core.collections.queues.Queue * @see xxl.core.collections.queues.AbstractQueue * @see xxl.core.collections.queues.FIFOQueue * @see xxl.core.util.ArrayResizer */ public class ArrayQueue<E> extends AbstractQueue<E> implements FIFOQueue<E> { /** * An ArrayResizer managing the growth policy for the internally used * array. The ArrayResizer decides before an insertion or after an * removal of an element whether the array has to be resized or not. * * @see ArrayResizer */ protected ArrayResizer resizer; /** * The array is internally used to store the elements of the queue. * Before an insertion and after the removal of an element this array * is automatically resized by an ArrayResizer. */ protected Object[] array; /** * An <tt>int</tt> field storing the index of the first element of the * queue in the array. */ protected int first = 0; /** * Constructs a queue containing the elements of the specified array * with a growth polity that depends on the specified <tt>double</tt> * parameters. The field <tt>array</tt> is set to the specified array, * the field <tt>size</tt> is set to the specified size and the field * <tt>resizer</tt> (growth policy) is initialized by the constructor * <code>ArrayResizer(fmin, fover, funder)</code>. * * @param size the number of elements of the specified array which * should be used to initialize the internally used array. * @param array the object array that is used to initialize the * internally used array. * @param fmin a control parameter for the growth policy. * @param fover a control parameter for the growth policy. * @param funder a control parameter for the growth policy. * @throws IllegalArgumentException if the specified size argument is * negative, or if it is greater than the length of the * specified array. * @see ArrayResizer#ArrayResizer(double, double, double) */ public ArrayQueue(int size, E[] array, double fmin, double fover, double funder) throws IllegalArgumentException { if (array.length < size || size < 0) throw new IllegalArgumentException(); this.array = array; this.size = size; this.resizer = new ArrayResizer(fmin, fover, funder) { public void copy(Object source, Object target, int size) { copy(source, first, target, 0, size); } }; } /** * Constructs a queue containing the elements of the specified array * with a growth polity that depends on the specified <tt>double</tt> * parameters. This constructor is equivalent to the call of * <code>ArrayQueue(array.length, array, fmin, fover, funder)</code>. * * @param array the object array that is used to initialize the * internally used array. * @param fmin a control parameter for the growth policy. * @param fover a control parameter for the growth policy. * @param funder a control parameter for the growth policy. */ public ArrayQueue(E[] array, double fmin, double fover, double funder) { this(array.length, array, fmin, fover, funder); } /** * Constructs an empty queue with a growth policy that depends on the * specified <tt>double</tt> parameters. This constructor is equivalent * to the call of * <code>ArrayQueue(0, new Object[0], fmin, fover, funder)</code>. * * @param fmin a control parameter for the growth policy. * @param fover a control parameter for the growth policy. * @param funder a control parameter for the growth policy. */ public ArrayQueue(double fmin, double fover, double funder) { this.array = new Object[0]; this.size = 0; this.resizer = new ArrayResizer(fmin, fover, funder) { public void copy(Object source, Object target, int size) { copy(source, first, target, 0, size); } }; } /** * Constructs a queue containing the elements of the specified array * with a growth policy that depends on the specified <tt>double</tt> * parameters. The field <tt>array</tt> is set to the specified array, * the field <tt>size</tt> is set to the specified size and the field * <tt>resizer</tt> (growth policy) is initialized by the constructor * <code>ArrayResizer(fmin, f)</code>. * * @param size the number of elements of the specified array which * should be used to initialize the internally used array. * @param array the object array that is used to initialize the * internally used array. * @param fmin a control parameter for the growth policy. * @param f a control parameter for the growth policy. * @throws IllegalArgumentException if the specified size argument is * negative, or if it is greater than the length of the * specified array. * @see ArrayResizer#ArrayResizer(double, double) */ public ArrayQueue(int size, E[] array, double fmin, double f) throws IllegalArgumentException { if (array.length < size || size < 0) throw new IllegalArgumentException(); this.array = array; this.size = size; this.resizer = new ArrayResizer(fmin, f) { public void copy(Object source, Object target, int size) { copy(source, first, target, 0, size); } }; } /** * Constructs a queue containing the elements of the specified array * with a growth policy that depends on the specified <tt>double</tt> * parameters. This constructor is equivalent to the call of * <code>ArrayQueue(array.length, array, fmin, f)</code>. * * @param array the object array that is used to initialize the * internally used array. * @param fmin a control parameter for the growth policy. * @param f a control parameter for the growth policy. */ public ArrayQueue(E[] array, double fmin, double f) { this(array.length, array, fmin, f); } /** * Constructs an empty queue with a growth policy that depends on the * specified <tt>double</tt> parameters. This constructor is * equivalent to the call of * <code>ArrayQueue(0, new Object[0], fmin, f)</code>. * * @param fmin a control parameter for the growth policy. * @param f a control parameter for the growth policy. */ public ArrayQueue(double fmin, double f) { this.array = new Object[0]; this.size = 0; this.resizer = new ArrayResizer(fmin, f) { public void copy(Object source, Object target, int size) { copy(source, first, target, 0, size); } }; } /** * Constructs a queue containing the elements of the specified array * with a growth policy that depends on the specified <tt>double</tt> * parameter. The field <tt>array</tt> is set to the specified array, * the field <tt>size</tt> is set to the specified size and the field * <tt>resizer</tt> (growth policy) is initialized by the constructor * <code>ArrayResizer(fmin)</code>. * * @param size the number of elements of the specified array which * should be used to initialize the internally used array. * @param array the object array that is used to initialize the * internally used array. * @param fmin a control parameter for the growth policy. * @throws IllegalArgumentException if the specified size argument is * negative, or if it is greater than the length of the * specified array. * @see ArrayResizer#ArrayResizer(double) */ public ArrayQueue(int size, E[] array, double fmin) throws IllegalArgumentException { if (array.length < size || size < 0) throw new IllegalArgumentException(); this.array = array; this.size = size; this.resizer = new ArrayResizer(fmin) { public void copy(Object source, Object target, int size) { copy(source, first, target, 0, size); } }; } /** * Constructs a queue containing the elements of the specified array * with a growth policy that depends on the specified <tt>double</tt> * parameter. This constructor is equivalent to the call of * <code>ArrayQueue(array.length, array, fmin)</code>. * * @param array the object array that is used to initialize the * internally used array. * @param fmin a control parameter for the growth policy. */ public ArrayQueue(E[] array, double fmin) { this(array.length, array, fmin); } /** * Constructs an empty queue with a growth policy that depends on the * specified <tt>double</tt> parameter. This constructor is equivalent * to the call of <code>ArrayQueue(0, new Object[0], fmin)</code>. * * @param fmin a control parameter for the growth policy. */ public ArrayQueue(double fmin) { this.array = new Object[0]; this.size = 0; this.resizer = new ArrayResizer(fmin) { public void copy(Object source, Object target, int size) { copy(source, first, target, 0, size); } }; } /** * Constructs a queue containing the elements of the specified array. * The field <tt>array</tt> is set to the specified array, the field * <tt>size</tt> is set to the specified size and the field * <tt>resizer</tt> (growth policy) is initialized by the void * constructor <code>ArrayResizer()</code>. * * @param size the number of elements of the specified array which * should be used to initialize the internally used array. * @param array the object array that is used to initialize the * internally used array. * @throws IllegalArgumentException if the specified size argument is * negative, or if it is greater than the length of the * specified array. * @see ArrayResizer#ArrayResizer() */ public ArrayQueue(int size, E[] array) throws IllegalArgumentException { if (array.length < size || size < 0) throw new IllegalArgumentException(); this.array = array; this.size = size; this.resizer = new ArrayResizer() { public void copy(Object source, Object target, int size) { copy(source, first, target, 0, size); } }; } /** * Constructs a queue containing the elements of the specified array. * This constructor is equivalent to the call of * <code>ArrayQueue(array.length, array)</code>. * * @param array the object array that is used to initialize the * internally used array. */ public ArrayQueue(E[] array) { this(array.length, array); } /** * Constructs an empty queue. This constructor is equivalent to the * call of <code>ArrayQueue(0, new Object[0])</code>. */ public ArrayQueue() { this.array = new Object[0]; this.size = 0; this.resizer = new ArrayResizer() { public void copy(Object source, Object target, int size) { copy(source, first, target, 0, size); } }; } /** * Appends the specified element to the <i>end</i> of this queue. * Before the element is inserted the internally used array may be * resized automatically depending on its growth policy. * * @param object element to be appended to the <i>end</i> of this * queue. */ protected void enqueueObject(E object) { if (array != (array = resizer.resize(array, size+1))) first = 0; array[(first+size)%array.length] = object; } /** * Returns the <i>next</i> element in the queue <i>without</i> removing it. * The <i>next</i> element is the value of the component of the * internally used array which is pointed by the index <tt>first</tt>. * * @return the <i>next</i> element in the queue. */ protected E peekObject() { return (E)array[first]; } /** * Returns the <i>next</i> element in the queue (and <i>removes</i> it). * The <i>next</i> element is the value of the component of the internally * used array which is pointed by the index <tt>first</tt>. * * @return the <i>next</i> element in the queue. */ protected E dequeueObject() { Object object = array[first]; first = (first+1)%array.length; if (array != (array = resizer.resize(array, size-1))) first = 0; return (E)object; } /** * Removes all elements from this queue. The queue will be * empty after this call returns so that <tt>size() == 0</tt>.<br> * The internally used array will be replaced by an empty array and * the fields <tt>size</tt> and <tt>first</tt> will be set to 0. */ public void clear () { array = new Object[0]; size = 0; first = 0; } }