/* * Geotoolkit.org - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2010-2012, Open Source Geospatial Foundation (OSGeo) * (C) 2010-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.internal; import java.io.Serializable; import java.util.AbstractSet; import java.util.Arrays; import java.util.Comparator; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.Set; import java.util.SortedSet; /** * An unmodifiable sorted set backed by an array of comparable objects. * This class is not public since it assumes that the given array is already * sorted and does not contains duplicated values (this is not verified). * * @param <E> The type of elements in the set. * * @author Martin Desruisseaux (Geomatys) * @version 3.10 * * @since 3.10 * @module */ public abstract class UnmodifiableArraySortedSet<E> extends AbstractSet<E> implements SortedSet<E>, Serializable { /** * For cross-version compatibility. */ private static final long serialVersionUID = -6259677334686182111L; /** * The lower and upper bounds of the array. */ protected final int lower, upper; /** * Creates a new instance. * * @param lower The index of the first valid element in the backing array. * @param upper The index after the last valid element in the backing array. */ protected UnmodifiableArraySortedSet(final int lower, final int upper) { this.lower = lower; this.upper = upper; } /** * Returns a new instance backed by the same array but using different lower and upper * array bounds. * * @param lower The index of the first valid element in the backing array. * @param upper The index after the last valid element in the backing array. * @return A new instance backed by the same array and using the given bounds. */ protected abstract UnmodifiableArraySortedSet<E> create(final int lower, final int upper); /** * Returns the element at the given index. * * @param i The index where to fetch the element. * @return The element at the given index. * @throws IndexOutOfBoundsException If the given index is out of bounds. */ protected abstract E elementAt(int i) throws IndexOutOfBoundsException; /** * Returns the index of the given element using the appropriate {@code Arrays.binarySearch} * method. * * @param e The object to search. * @return The index of the element, or a value derived from the insertion point as * documented in {@code Arrays.binarySearch}. */ protected abstract int indexOf(Object e); /** * Returns {@code null} since this implementation assumes that we use the natural ordering. */ @Override public Comparator<E> comparator() { return null; } /** * Returns the number of elements in this set. */ @Override public int size() { return upper - lower; } /** * Returns {@code true} if this set contains the given element. */ @Override public boolean contains(Object o) { final int i = indexOf(o); return i >= lower && i < upper; } /** * Returns the first element in this set. */ @Override public E first() { if (lower == upper) { throw new NoSuchElementException(); } return elementAt(lower); } /** * Returns the last element in this set. */ @Override public E last() { if (lower == upper) { throw new NoSuchElementException(); } return elementAt(upper - 1); } /** * Returns an iterator over all elements in the set. */ @Override public Iterator<E> iterator() { return new Iterator<E>() { private int index = lower; @Override public boolean hasNext() { return index < upper; } @Override public E next() { if (index < upper) { return elementAt(index++); } throw new NoSuchElementException(); } @Override public void remove() { throw new UnsupportedOperationException(); } }; } /** * Returns a sub-set from the beginning of this set to the given element (exclusive). */ @Override public SortedSet<E> headSet(final Object toElement) { int i = indexOf(toElement); if (i < 0) i = ~i; return (i == upper) ? this : create(0, i); } /** * Returns a sub-set from the given element (inclusive) to the end of this set. */ @Override public SortedSet<E> tailSet(final Object fromElement) { int i = indexOf(fromElement); if (i < 0) i = ~i; return (i == lower) ? this : create(i, upper); } /** * Returns a sub-set from the given element (inclusive) to the given one (exclusive). */ @Override public SortedSet<E> subSet(final Object fromElement, final Object toElement) { int lo = indexOf(fromElement); int hi = indexOf( toElement); if (lo < 0) lo = ~lo; if (hi < 0) hi = ~hi; return (lo == lower && hi == upper) ? this : create(lo, hi); } /** * An unmodifiable sorted set of numbers backed by an array of type {@code double[]}. * * @author Martin Desruisseaux (Geomatys) * @version 3.10 * * @since 3.10 * @module */ public static final class Number extends UnmodifiableArraySortedSet<java.lang.Number> { /** * For cross-version compatibility. */ private static final long serialVersionUID = -8037878367513806431L; /** * The sorted array of values. */ private final double[] values; /** * Creates a new instance from the given set. * * @param numbers The set to copy. */ public Number(final Set<? extends java.lang.Number> numbers) { super(0, numbers.size()); values = new double[upper]; int i = 0; for (final java.lang.Number e : numbers) { values[i++] = e.doubleValue(); } Arrays.sort(values); } /** * Creates a new instance wrapping the given array. */ private Number(final double[] values, final int lower, final int upper) { super(lower, upper); this.values = values; } /** * Creates a new instance wrapping the same array in the given range. */ @Override protected UnmodifiableArraySortedSet<java.lang.Number> create(int lower, int upper) { return new Number(values, lower, upper); } /** * Returns the element at the given index. */ @Override protected java.lang.Number elementAt(int i) throws IndexOutOfBoundsException { return java.lang.Double.valueOf(values[i]); } /** * Returns the index of the given element. */ @Override protected int indexOf(final Object e) { return Arrays.binarySearch(values, lower, upper, ((java.lang.Number) e).doubleValue()); } } /** * An unmodifiable sorted set of dates backed by an array of type {@code long[]}. * * @author Martin Desruisseaux (Geomatys) * @version 3.10 * * @since 3.10 * @module */ public static final class Date extends UnmodifiableArraySortedSet<java.util.Date> { /** * For cross-version compatibility. */ private static final long serialVersionUID = 6763321681710208337L; /** * The sorted array of times, in milliseconds since January 1st 1970. */ private final long[] times; /** * Creates a new instance from the given set. * * @param dates The set to copy. */ public Date(final Set<? extends java.lang.Number> dates) { super(0, dates.size()); times = new long[upper]; int i = 0; for (final java.lang.Number e : dates) { times[i++] = e.longValue(); } Arrays.sort(times); } /** * Creates a new instance wrapping the given array. */ private Date(final long[] times, final int lower, final int upper) { super(lower, upper); this.times = times; } /** * Creates a new instance wrapping the same array in the given range. */ @Override protected UnmodifiableArraySortedSet<java.util.Date> create(int lower, int upper) { return new Date(times, lower, upper); } /** * Returns the element at the given index. */ @Override protected java.util.Date elementAt(int i) throws IndexOutOfBoundsException { return new java.util.Date(times[i]); } /** * Returns the index of the given element. */ @Override protected int indexOf(final Object e) { return Arrays.binarySearch(times, lower, upper, ((java.util.Date) e).getTime()); } } }