/* 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 java.util.Iterator;
import java.util.List;
import xxl.core.functions.AbstractFunction;
import xxl.core.functions.Function;
import xxl.core.predicates.AbstractPredicate;
import xxl.core.predicates.Predicate;
/**
* Decorates an arbitrary queue by adding boundary conditions. <br>
* These conditions are represented as a user-defined, unary predicate
* which is applied to next element to be inserted into the underlying queue.
* If an insert operation detects an overflow, i.e., the predicate returns
* <tt>false</tt>, the method <code>handleOverflow()</code> is called.
* The default implementation
* throws an {@link java.lang.IndexOutOfBoundsException IndexOutOfBoundsException},
* but overwriting this method offers the possibility to handle an overflow of
* the underlying queue differently.
* If the predicate returns <tt>false</tt>, the element will be inserted
* into the underlying queue. <br>
*
* For the construction of a bounded buffer, this class has
* proven to be useful.
* <p>
* This class is used in ThreadedIterator.
* <p>
*
* Example usage (1).
* <pre>
* // create a new bounded queue using an ArrayQueue
*
* Queue<Integer> queue = new BoundedQueue<Integer>(new ArrayQueue<Integer>(), 100);
*
* // open the queue
*
* queue.open();
*
* try {
* Iterator<Integer> iterator = new xxl.core.cursors.sources.Enumerator(200);
* for (; iterator.hasNext(); queue.enqueue(iterator.next()));
* }
* catch (IndexOutOfBoundsException e) {}
*
* int count = queue.size();
* System.out.println("The queue contained "+count+
* " elements (100 is correct!)");
*
* // close the queue
*
* queue.close();
*</pre>
*
* @param <E> the type of the elements of this queue.
* @see xxl.core.collections.queues.Queue
* @see xxl.core.collections.queues.DecoratorQueue
*/
public class BoundedQueue<E> extends DecoratorQueue<E> {
/**
* A factory method to create a new bounded queue (see contract for
* {@link Queue#FACTORY_METHOD FACTORY_METHOD} in interface
* Queue). It may be invoked with a <i>parameter list</i>
* (for further details see Function) of object arrays, an iterator or
* without any parameters. A <i>parameter list</i> of object
* arrays will be used to initialize the internally used array with
* the object array at index 0 and an iterator will be used to insert
* the contained elements into the new ArrayQueue.
*
* @see Function
*/
public static final Function<Object, BoundedQueue<Object>> FACTORY_METHOD = new AbstractFunction<Object, BoundedQueue<Object>>() {
@Override
public BoundedQueue<Object> invoke() {
return new BoundedQueue<Object>(
Queue.FACTORY_METHOD.invoke(),
1024
);
}
@Override
public BoundedQueue<Object> invoke(Object iterator) {
BoundedQueue<Object> queue = new BoundedQueue<Object>(
Queue.FACTORY_METHOD.invoke(),
1024
);
for (Iterator<?> i = (Iterator<?>)iterator; i.hasNext(); queue.enqueue(i.next()));
return queue;
}
@Override
public BoundedQueue<Object> invoke(List<? extends Object> list) {
return new BoundedQueue<Object>(
(Queue<Object>)list.get(0),
(Predicate<Object>)list.get(1)
);
}
};
/**
* Predicate that evaluates if a further element can be inserted.
* Unary predicate that gets the next element to be inserted
* as parameter. If <tt>false</tt> is returned, an overflow
* must be handled, so the method <code>handleOverflow()</code>
* is called. Otherwise (<tt>true</tt> is returned), the element
* specified as argument will be inserted into the queue.
*/
protected Predicate<? super E> predicate;
/**
* Constructs a BoundedQueue. The queue to become bounded must be passed
* as the first argument. The second argument is a predicate evaluating
* the next element and determining if an overflow must be handled.
*
* @param queue the queue that becomes bounded.
* @param predicate the predicate evaluating the next element and
* determining if an overflow must be handled, i.e. handleOverflow()
* will be called, if the predicate returns <tt>false</tt>.
*/
public BoundedQueue(Queue<E> queue, Predicate<? super E> predicate) {
super(queue);
this.predicate = predicate;
}
/**
* Constructs a BoundedQueue. The queue to become bounded must be passed as
* the first argument. The second argument defines the size of the queue.
*
* @param queue the queue that becomes bounded.
* @param maxSize the size of the queue. If more elements become
* inserted method handleOverflow() is called.
*/
public BoundedQueue(final Queue<E> queue, final int maxSize) {
this(
queue,
new AbstractPredicate<E>() {
@Override
public boolean invoke(E object) {
return queue.size() < maxSize;
}
}
);
}
/**
* Appends the specified element to the <i>end</i> of this queue. The
* <i>end</i> of the queue is given by its <i>strategy</i>.
*
* @param object element to be appended to the <i>end</i> of this
* queue.
* @throws IllegalStateException if the queue is already closed when this
* method is called.
* @throws IndexOutOfBoundsException if the overflow cannot be handled.
*/
@Override
public void enqueue(E object) throws IllegalStateException, IndexOutOfBoundsException {
if (predicate.invoke(object))
super.enqueue(object);
else
handleOverflow();
}
/**
* If an insert operation detects an overflow, i.e., the maximum number
* of objects has been inserted into the queue, and a further element
* is to be inserted this method is called. The default implementation
* throws an {@link java.lang.IndexOutOfBoundsException IndexOutOfBoundsException},
* but overwriting this method offers the possibility to handle an overflow in
* the queue differently.
*
* @throws IndexOutOfBoundsException if the overflow cannot be handled.
*/
public void handleOverflow() throws IndexOutOfBoundsException {
throw new IndexOutOfBoundsException("The maximum number of elements has been reached. "+
"No further elements can be inserted.");
}
}