/* 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.bags; import java.util.Iterator; import xxl.core.cursors.Cursor; import xxl.core.cursors.filters.Filter; import xxl.core.cursors.sources.EmptyCursor; import xxl.core.functions.Function; import xxl.core.predicates.Predicate; /** * This class provides a skeletal implementation of the Bag interface, to * minimize the effort required to implement this interface. * * <p>To implement a bag, the programmer needs only to extend this class and * provide implementations for the cursor, insert and size methods. For * supporting the removal of elements, the cursor returned by the cursor method * must additionally implement its remove method.</p> * * <p>The documentation for each non-abstract method in this class describes * its implementation in detail. Each of these methods may be overridden if the * bag being implemented admits a more efficient implementation.</p> * * @param <E> the type of the elements this bag is able to store. * @see Cursor * @see Function * @see Iterator */ public abstract class AbstractBag<E> implements Bag<E> { /** * Sole constructor. (For invocation by subclass constructors, typically * implicit.) */ public AbstractBag() {} /** * Returns a cursor to iterate over the elements in this bag without any * predefined sequence. The cursor is specifying a <i>view</i> on the * elements of this bag so that closing the cursor takes no effect on the * bag (e.g., not closing the bag). The behavior of the cursor is * unspecified if this bag is modified while the cursor is in progress in * any way other than by calling the methods of the cursor. So, when the * implementation of this cursor cannot guarantee that the cursor is in a * valid state after modifing the underlying bag every method of the cursor * except <code>close()</code> should throw a * <code>ConcurrentModificationException</code>. * * @return a cursor to iterate over the elements in this bag without any * predefined sequence. */ public abstract Cursor<E> cursor(); /** * Adds the specified element to this bag. This method does not perform any * kind of <i>duplicate detection</i>. * * @param object element to be added to this bag. */ public abstract void insert(E object); /** * Returns the number of elements in this bag (its cardinality). If this * bag contains more than <code>Integer.MAX_VALUE</code> elements, returns * <code>Integer.MAX_VALUE</code>. * * @return the number of elements in this bag (its cardinality). */ public abstract int size(); /** * Removes all of the elements from this bag. The bag will be empty after * this call so that <code>size() == 0</code>. * * <p>This implementation creates a cursor by calling the cursor method and * iterates over it, removing each element using the * {@link Cursor#remove() Cursor.remove} operation. Most implementations * will probably choose to override this method for efficiency.</p> */ public void clear() { for (Iterator<E> cursor = cursor(); cursor.hasNext(); cursor.remove()) cursor.next(); } /** * Closes this bag and releases any system resources associated with it. * This operation is idempotent, i.e., multiple calls of this method take * the same effect as a single call. When needed, a closed bag can be * implicit reopened by a consecutive call to one of its methods. Because * of having an unspecified behavior when this bag is closed every cursor * iterating over the elements of this bag must be closed. * * <p><b>Note:</b> This method is very important for bags using external * resources like files or JDBC resources.</p> * * <p>This implementation is given by an empty body.</p> */ public void close() {} /** * Adds all of the elements in the specified iterator to this bag. This * method does not perform any kind of <i>duplicate detection.</i> The * behavior of this operation is unspecified if the specified iterator is * modified while the operation is in progress. * * <p>This implementation iterates over the specified iterator, and inserts * each object, in turn.</p> * * @param objects iterator whose elements are to be added to this bag. */ public void insertAll(Iterator<? extends E> objects) { while (objects.hasNext()) insert(objects.next()); } /** * Returns a cursor to iterate over all elements in this bag for which the * given predicate returns <code>true</code>. This method is very similar * to the cursor method except that its result is determined by a * predicate. This implementation filters the result of the cursor method * using the following code: * <code><pre> * return size() > 0 ? * (Cursor<E>)new Filter<E>(cursor(), predicate) : * new EmptyCursor<E>(); * </pre></code> * The default implementation of this method is not very interesting, * but the method is very import for some bags. When the data * structure that is internally used for storing the elements of this * bag is able to handle with queries, this method can be implemented * very efficient by passing the query to the data structure. For * example a range query on a bag that internally uses a R-tree to * store its elements will be more efficient when it is proceed on the * R-tree itself.<br> * Like the cursor returned by the cursor method, this cursor's * behavior is unspecified if this bag is modified while the cursor is * in progress in any way other than by calling the methods of the * cursor. * * @param predicate a predicate that determines whether an element of * this bag should be returned or not. * @return a cursor to iterate over all elements in this bag for which * the given predicate returns <tt>true</tt>. */ public Cursor<E> query(Predicate<? super E> predicate) { return size() > 0 ? (Cursor<E>)new Filter<E>(cursor(), predicate) : new EmptyCursor<E>(); } }