/* 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;
/**
* This class provides a wrapper for a queue that performes a simple
* <i>duplicate elimination</i>. When inserting a row duplicate elements,
* this class' <tt>enqueue</tt> method only inserts the first element and ignors
* the rest. Every time the insertion of duplicate elements is separated
* by another element's insertion, the duplicate elements are not detected
* by the <tt>enqueue</tt> method. This duplicate elimination is very important for
* some operations like sorting etc. For example it can be used to
* integrate an early duplicate elimination into a physical sort operation
* instead of proceeding it on the sorted data. One example is the
* <tt>SortMerge</tt> cursor of this library. The destinct queue can be used to
* eliminate duplicates while merging the runs.<p>
*
* Usage example (1).
* <pre>
* // create a new queue
*
* Queue<Integer> q1 = new ListQueue<Integer>();
*
* // open the queue
*
* q1.open();
*
* // create an iteration over 10000 random Integers (between 0 and
* // 100)
*
* Cursor<Integer> cursor = new DiscreteRandomNumber(new JavaDiscreteRandomWrapper(100), 10000);
*
* // insert all elements of the given cursor
*
* for (; cursor.hasNext(); q1.enqueue(cursor.next()));
*
* // print the size of the queue after insertion
*
* System.out.println("Size q1:\t" + q1.size());
*
* // reset the cursor, so that it can be used again
*
* cursor.reset();
*
* // create a new distinct queue
*
* Queue<Integer> q2 = new DistinctQueue<Integer>(new ListQueue<Integer>());
*
* // opent the queue
*
* q2.open();
*
* // insert all elements of the given cursor
*
* for (; cursor.hasNext(); q2.enqueue(cursor.next()));
*
* // print the size of the distinct queue after insertion
*
* System.out.println("Size q2:\t" + q2.size());
*
* // close the open queues and the cursor after use
*
* q1.close();
* q2.close();
* cursor.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 DistinctQueue<E> extends DecoratorQueue<E> {
/**
* A factory method to create a new DistinctQueue (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 queues, an iterator or without any
* parameters. A <i>parameter list</i> of queues will be used
* to initialize the wrapped queue with the queue at index 0 and an
* iterator will be used to insert the contained elements into the
* new DistinctQueue.
*
* @see Function
*/
public static final Function<Object, DistinctQueue<Object>> FACTORY_METHOD = new AbstractFunction<Object, DistinctQueue<Object>>() {
@Override
public DistinctQueue<Object> invoke() {
return new DistinctQueue<Object>(
Queue.FACTORY_METHOD.invoke()
);
}
@Override
public DistinctQueue<Object> invoke(Object iterator) {
DistinctQueue<Object> queue = new DistinctQueue<Object>(
Queue.FACTORY_METHOD.invoke()
);
for (Iterator<?> i = (Iterator<?>)iterator; i.hasNext(); queue.enqueue(i.next()));
return queue;
}
@Override
public DistinctQueue<Object> invoke(List<? extends Object> list) {
return new DistinctQueue<Object>(
(Queue<Object>)list.get(0)
);
}
};
/**
* The field <tt>last</tt> is used to store the object that is
* inserted into the queue at last. When another element should be
* inserted into the queue, it is compared with <tt>last</tt>. When
* the elements are not equal, it is inserted into the queue and
* <tt>last</tt> is set to it.
*/
protected E last = null;
/**
* Constructs a new DistintQueue that decorates the specified queue.
*
* @param queue the queue to be decorated.
*/
public DistinctQueue(Queue<E> queue) {
super(queue);
}
/**
* 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>.<br>
* This method performs a simple <i>duplicate elimination</i>. When
* inserting a row duplicate elements, it only inserts the first
* element and ignores the rest. Every time the insertion of duplicate
* elements is separated by another element's insertion, the duplicate
* elements are not detected by this method.
*
* @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.
*/
@Override
public void enqueue(E object) throws IllegalStateException {
if (queue.size() == 0 || !object.equals(last))
super.enqueue(last = object);
}
}