/* * Geotoolkit.org - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2004-2012, Open Source Geospatial Foundation (OSGeo) * (C) 2009-2012, Geomatys * * 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.geotoolkit.util.collection; import java.io.Serializable; import java.util.AbstractSet; import java.util.Iterator; import java.util.Set; import org.geotoolkit.lang.Decorator; import org.apache.sis.util.collection.CheckedContainer; /** * A set whose values are derived from an other set. The values are derived only when * requested, which make it possible to backup potentially large sets. Implementations * need only to overrides {@link #baseToDerived} and {@link #derivedToBase} methods. * This set do not supports {@code null} value, since {@code null} is used * when no mapping from {@linkplain #base} to {@code this} exists. * This class is serializable if the underlying {@linkplain #base} set is serializable * too. * <p> * This class is <strong>not</strong> thread-safe. Synchronizations (if wanted) are user's * responsibility. * * @param <B> The type of elements in the backing set. * @param <E> The type of elements in this set. * * @author Martin Desruisseaux (IRD) * @version 3.00 * * @since 2.0 * @module * * @deprecated Replaced by {@link org.apache.sis.util.ObjectConverters#derivedMap}. */ @Deprecated @Decorator(Set.class) public abstract class DerivedSet<B,E> extends AbstractSet<E> implements CheckedContainer<E>, Serializable { /** * Serial number for inter-operability with different versions. */ private static final long serialVersionUID = -4662336508586424581L; /** * The base set whose values are derived from. * * @see #baseToDerived * @see #derivedToBase */ protected final Set<B> base; /** * The derived type. */ private final Class<E> derivedType; /** * Creates a new derived set from the specified base set. * * @param base The base set. * @param derivedType The type of elements in this derived set. * * @since 2.5 */ public DerivedSet(final Set<B> base, final Class<E> derivedType) { this.base = base; this.derivedType = derivedType; } /** * Returns the derived element type. * * @since 2.5 */ @Override public Class<E> getElementType() { return derivedType; } /** * Transforms a value in the {@linkplain #base} set to a value in this set. * If there is no mapping in the derived set for the specified element, * then this method returns {@code null}. * * @param element A value in the {@linkplain #base} set. * @return The value that this view should contains instead of {@code element}, * or {@code null}. */ protected abstract E baseToDerived(final B element); /** * Transforms a value in this set to a value in the {@linkplain #base} set. * * @param element A value in this set. * @return The value stored in the {@linkplain #base} set. */ protected abstract B derivedToBase(final E element); /** * Returns an iterator over the elements contained in this set. * The iterator will invokes {@link #baseToDerived} for each element. * * @return an iterator over the elements contained in this set. */ @Override public Iterator<E> iterator() { return new Iter(base.iterator()); } /** * Returns the number of elements in this set. The default implementation counts * the number of elements returned by the {@link #iterator iterator}. * * @return the number of elements in this set. */ @Override public int size() { int count = 0; for (final Iterator<E> it=iterator(); it.hasNext();) { it.next(); count++; } return count; } /** * Returns {@code true} if this set contains no elements. * * @return {@code true} if this set contains no elements. */ @Override public boolean isEmpty() { return base.isEmpty() || super.isEmpty(); } /** * Returns {@code true} if this set contains the specified element. * The default implementation invokes * <code>{@linkplain #base}.contains({@linkplain #derivedToBase derivedToBase}(element))</code>. * * @param element object to be checked for containment in this set. * @return {@code true} if this set contains the specified element. */ @Override public boolean contains(final Object element) { if (derivedType.isInstance(element)) { return base.contains(derivedToBase(derivedType.cast(element))); } else { return false; } } /** * Ensures that this set contains the specified element. * The default implementation invokes * <code>{@linkplain #base}.add({@linkplain #derivedToBase derivedToBase}(element))</code>. * * @param element element whose presence in this set is to be ensured. * @return {@code true} if the set changed as a result of the call. * @throws UnsupportedOperationException if the {@linkplain #base} set doesn't * supports the {@code add} operation. */ @Override public boolean add(final E element) throws UnsupportedOperationException { return base.add(derivedToBase(element)); } /** * Removes a single instance of the specified element from this set. * The default implementation invokes * <code>{@linkplain #base}.remove({@linkplain #derivedToBase derivedToBase}(element))</code>. * * @param element element to be removed from this set, if present. * @return {@code true} if the set contained the specified element. * @throws UnsupportedOperationException if the {@linkplain #base} set doesn't * supports the {@code remove} operation. */ @Override public boolean remove(final Object element) throws UnsupportedOperationException { if (derivedType.isInstance(element)) { return base.remove(derivedToBase(derivedType.cast(element))); } else { return false; } } /** * Iterates through the elements in the set. */ @Decorator(Iterator.class) private final class Iter implements Iterator<E> { /** * The iterator from the {@linkplain #base} set. */ private final Iterator<B> iterator; /** * The next element to be returned, or {@code null}. */ private transient E next; /** * The iterator from the {@linkplain #base} set. */ public Iter(final Iterator<B> iterator) { this.iterator = iterator; } /** * Returns {@code true} if the iteration has more elements. */ @Override public boolean hasNext() { while (next == null) { if (!iterator.hasNext()) { return false; } next = baseToDerived(iterator.next()); } return true; } /** * Returns the next element in the iteration. */ @Override public E next() { while (next == null) { next = baseToDerived(iterator.next()); } final E value = next; next = null; return value; } /** * Removes from the underlying set the last element returned by the iterator. * * @throws UnsupportedOperationException if the {@linkplain #base} set doesn't * supports the {@code remove} operation. */ @Override public void remove() { iterator.remove(); } } }