/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2004-2008, Open Source Geospatial Foundation (OSGeo) * * 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; * version 2.1 of the License. * * 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. */ package org.geotools.resources; import java.util.AbstractSet; import java.util.Iterator; /** * An immutable set built from an iterator, which will be filled only when needed. This * implementation do <strong>not</strong> check if all elements in the iterator are really * unique; we assume that it was already verified by {@link javax.imageio.spi.ServiceRegistry}. * This set is constructed by {@link org.geotools.referencing.FactoryFinder}. * * @since 2.0 * * @source $URL$ * @version $Id$ * @author Martin Desruisseaux (IRD) */ public final class LazySet<E> extends AbstractSet<E> { /** * The iterator to use for filling this set. */ private final Iterator<? extends E> iterator; /** * The elements in this set. This array will grown as needed. */ private E[] elements; /** * The current size of this set. This size will increases as long as there is some elements * remaining in the iterator. This is <strong>not</strong> the size returned by {@link #size()}. */ private int size; /** * Construct a set to be filled using the specified iterator. * Iteration in the given iterator will occurs only when needed. */ @SuppressWarnings("unchecked") public LazySet(final Iterator<? extends E> iterator) { this.iterator = iterator; elements = (E[]) new Object[4]; } /** * Add the next element from the iterator to this set. This method doesn't check * if more element were available; the check must have been done before to invoke * this method. */ private void addNext() { if (size >= elements.length) { elements = XArray.resize(elements, size*2); } elements[size++] = iterator.next(); } /** * Returns an iterator over the elements contained in this set. * This is not the same iterator than the one given to the constructor. */ public Iterator<E> iterator() { return new Iter(); } /** * Returns the number of elements in this set. Invoking this method * force the set to immediately iterates through all remaining elements. */ public int size() { while (iterator.hasNext()) { addNext(); } return size; } /** * Tests if this set has no elements. */ @Override public boolean isEmpty() { return size==0 && !iterator.hasNext(); } /** * Returns {@code true} if an element exists at the given index. * The element is not loaded immediately. * * <strong>NOTE: This method is for use by iterators only.</strong> * It is not suited for more general usage since it doesn't check * for negative index and for skipped elements. */ final boolean exists(final int index) { return index<size || iterator.hasNext(); } /** * Returns the element at the specified position in this set. */ public E get(final int index) { while (index >= size) { if (!iterator.hasNext()) { throw new IndexOutOfBoundsException(String.valueOf(index)); } addNext(); } return elements[index]; } /** * The iterator implementation for the {@linkplain LazySet lazy set}. */ private final class Iter implements Iterator<E> { /** Index of the next element to be returned. */ private int cursor; /** Check if there is more elements. */ public boolean hasNext() { return exists(cursor); } /** Returns the next element. */ public E next() { return get(cursor++); } /** Always throws an exception, since {@link LazySet} are immutable. */ public void remove() { throw new UnsupportedOperationException(); } } }