Emulate java.util.Spliterator This implementation does not perform split operations yet. Change-Id: I40c80f2104c26a21694b1132904acd6971496b1c
diff --git a/user/super/com/google/gwt/emul/java/lang/Iterable.java b/user/super/com/google/gwt/emul/java/lang/Iterable.java index b68cb6b..cec56d3 100644 --- a/user/super/com/google/gwt/emul/java/lang/Iterable.java +++ b/user/super/com/google/gwt/emul/java/lang/Iterable.java
@@ -18,6 +18,8 @@ import static javaemul.internal.InternalPreconditions.checkNotNull; import java.util.Iterator; +import java.util.Spliterator; +import java.util.Spliterators; import java.util.function.Consumer; /** @@ -37,4 +39,8 @@ action.accept(t); } } + + default Spliterator<T> spliterator() { + return Spliterators.spliteratorUnknownSize(iterator(), 0); + } }
diff --git a/user/super/com/google/gwt/emul/java/util/Arrays.java b/user/super/com/google/gwt/emul/java/util/Arrays.java index 9ad9fc7..374a557 100644 --- a/user/super/com/google/gwt/emul/java/util/Arrays.java +++ b/user/super/com/google/gwt/emul/java/util/Arrays.java
@@ -1043,6 +1043,43 @@ mergeSort(x, fromIndex, toIndex, c); } + public static Spliterator.OfDouble spliterator(double[] array) { + return Spliterators.spliterator(array, Spliterator.IMMUTABLE | Spliterator.ORDERED); + } + + public static Spliterator.OfDouble spliterator(double[] array, + int startInclusive, int endExclusive) { + return Spliterators.spliterator(array, startInclusive, endExclusive, + Spliterator.IMMUTABLE | Spliterator.ORDERED); + } + + public static Spliterator.OfInt spliterator(int[] array) { + return Spliterators.spliterator(array, Spliterator.IMMUTABLE | Spliterator.ORDERED); + } + + public static Spliterator.OfInt spliterator(int[] array, int startInclusive, int endExclusive) { + return Spliterators.spliterator(array, startInclusive, endExclusive, + Spliterator.IMMUTABLE | Spliterator.ORDERED); + } + + public static Spliterator.OfLong spliterator(long[] array) { + return Spliterators.spliterator(array, Spliterator.IMMUTABLE | Spliterator.ORDERED); + } + + public static Spliterator.OfLong spliterator(long[] array, int startInclusive, int endExclusive) { + return Spliterators.spliterator(array, startInclusive, endExclusive, + Spliterator.IMMUTABLE | Spliterator.ORDERED); + } + + public static <T> Spliterator<T> spliterator(T[] array) { + return Spliterators.spliterator(array, Spliterator.IMMUTABLE | Spliterator.ORDERED); + } + + public static <T> Spliterator<T> spliterator(T[] array, int startInclusive, int endExclusive) { + return Spliterators.spliterator(array, startInclusive, endExclusive, + Spliterator.IMMUTABLE | Spliterator.ORDERED); + } + public static String toString(boolean[] a) { if (a == null) { return "null";
diff --git a/user/super/com/google/gwt/emul/java/util/Collection.java b/user/super/com/google/gwt/emul/java/util/Collection.java index 0204f64..45b4b37 100644 --- a/user/super/com/google/gwt/emul/java/util/Collection.java +++ b/user/super/com/google/gwt/emul/java/util/Collection.java
@@ -53,6 +53,11 @@ int size(); + @Override + default Spliterator<E> spliterator() { + return Spliterators.spliterator(this, 0); + } + Object[] toArray(); <T> T[] toArray(T[] a);
diff --git a/user/super/com/google/gwt/emul/java/util/List.java b/user/super/com/google/gwt/emul/java/util/List.java index a9212bf..b6bd629 100644 --- a/user/super/com/google/gwt/emul/java/util/List.java +++ b/user/super/com/google/gwt/emul/java/util/List.java
@@ -80,6 +80,11 @@ @Override int size(); + @Override + default Spliterator<E> spliterator() { + return Spliterators.spliterator(this, Spliterator.ORDERED); + } + List<E> subList(int fromIndex, int toIndex); @Override
diff --git a/user/super/com/google/gwt/emul/java/util/PriorityQueue.java b/user/super/com/google/gwt/emul/java/util/PriorityQueue.java index 9a595c1..7fadc73 100644 --- a/user/super/com/google/gwt/emul/java/util/PriorityQueue.java +++ b/user/super/com/google/gwt/emul/java/util/PriorityQueue.java
@@ -194,6 +194,11 @@ } @Override + public Spliterator<E> spliterator() { + return Spliterators.spliterator(this, Spliterator.NONNULL); + } + + @Override public Object[] toArray() { return heap.toArray(); }
diff --git a/user/super/com/google/gwt/emul/java/util/Set.java b/user/super/com/google/gwt/emul/java/util/Set.java index 8c20796..07e6c18 100644 --- a/user/super/com/google/gwt/emul/java/util/Set.java +++ b/user/super/com/google/gwt/emul/java/util/Set.java
@@ -63,6 +63,11 @@ int size(); @Override + default Spliterator<E> spliterator() { + return Spliterators.spliterator(this, Spliterator.DISTINCT); + } + + @Override Object[] toArray(); @Override
diff --git a/user/super/com/google/gwt/emul/java/util/SortedSet.java b/user/super/com/google/gwt/emul/java/util/SortedSet.java index bc7a064..95e8fc8 100644 --- a/user/super/com/google/gwt/emul/java/util/SortedSet.java +++ b/user/super/com/google/gwt/emul/java/util/SortedSet.java
@@ -35,4 +35,16 @@ SortedSet<E> subSet(E fromElement, E toElement); SortedSet<E> tailSet(E fromElement); + + @Override + default Spliterator<E> spliterator() { + return new Spliterators.IteratorSpliterator<E>(this, + Spliterator.DISTINCT | Spliterator.ORDERED | Spliterator.SORTED) { + + @Override + public Comparator<? super E> getComparator() { + return SortedSet.this.comparator(); + } + }; + } }
diff --git a/user/super/com/google/gwt/emul/java/util/Spliterator.java b/user/super/com/google/gwt/emul/java/util/Spliterator.java new file mode 100644 index 0000000..365efd2 --- /dev/null +++ b/user/super/com/google/gwt/emul/java/util/Spliterator.java
@@ -0,0 +1,173 @@ +/* + * Copyright 2016 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package java.util; + +import static javaemul.internal.InternalPreconditions.checkCriticalNotNull; +import static javaemul.internal.InternalPreconditions.checkNotNull; + +import java.util.function.Consumer; +import java.util.function.DoubleConsumer; +import java.util.function.IntConsumer; +import java.util.function.LongConsumer; + +/** + * See <a href="https://docs.oracle.com/javase/8/docs/api/java/util/Spliterator.html"> + * the official Java API doc</a> for details. + * + * @param <T> the type of elements returned by Spliterator. + */ +public interface Spliterator<T> { + + int DISTINCT = 0x00000001; + + int ORDERED = 0x00000010; + + int NONNULL = 0x00000100; + + int CONCURRENT = 0x00001000; + + int SORTED = 0x00000004; + + int SIZED = 0x00000040; + + int IMMUTABLE = 0x00000400; + + int SUBSIZED = 0x00004000; + + int characteristics(); + + long estimateSize(); + + default void forEachRemaining(Consumer<? super T> consumer) { + checkNotNull(consumer); + while (tryAdvance(consumer)) { } + } + + default Comparator<? super T> getComparator() { + throw new IllegalStateException(); + } + + default long getExactSizeIfKnown() { + return hasCharacteristics(SIZED) ? estimateSize() : -1L; + } + + default boolean hasCharacteristics(int characteristics) { + return (characteristics() & characteristics) != 0; + } + + boolean tryAdvance(Consumer<? super T> consumer); + + Spliterator<T> trySplit(); + + /** + * See <a href="https://docs.oracle.com/javase/8/docs/api/java/util/Spliterator.OfPrimitive.html"> + * the official Java API doc</a> for details. + * + * @param <T> the type of elements returned by this Spliterator. + * @param <C> the type of primitive Consumer. + * @param <S> the type of primitive Spliterator. + */ + interface OfPrimitive<T, C, S extends OfPrimitive<T, C, S>> extends Spliterator<T> { + + boolean tryAdvance(C consumer); + + @Override + S trySplit(); + + default void forEachRemaining(C consumer) { + checkNotNull(consumer); + while (tryAdvance(consumer)) { } + } + } + + /** + * See <a href="https://docs.oracle.com/javase/8/docs/api/java/util/Spliterator.OfDouble.html"> + * the official Java API doc</a> for details. + */ + interface OfDouble extends OfPrimitive<Double, DoubleConsumer, OfDouble> { + @Override + default boolean tryAdvance(Consumer<? super Double> consumer) { + if (consumer instanceof DoubleConsumer) { + return tryAdvance((DoubleConsumer) consumer); + } else { + checkCriticalNotNull(consumer); + return tryAdvance((DoubleConsumer) consumer::accept); + } + } + + @Override + default void forEachRemaining(Consumer<? super Double> consumer) { + if (consumer instanceof DoubleConsumer) { + forEachRemaining((DoubleConsumer) consumer); + } else { + checkCriticalNotNull(consumer); + forEachRemaining((DoubleConsumer) consumer::accept); + } + } + } + + /** + * See <a href="https://docs.oracle.com/javase/8/docs/api/java/util/Spliterator.OfInt.html"> + * the official Java API doc</a> for details. + */ + interface OfInt extends OfPrimitive<Integer, IntConsumer, OfInt> { + @Override + default boolean tryAdvance(Consumer<? super Integer> consumer) { + if (consumer instanceof IntConsumer) { + return tryAdvance((IntConsumer) consumer); + } else { + checkCriticalNotNull(consumer); + return tryAdvance((IntConsumer) consumer::accept); + } + } + + @Override + default void forEachRemaining(Consumer<? super Integer> consumer) { + if (consumer instanceof IntConsumer) { + forEachRemaining((IntConsumer) consumer); + } else { + checkCriticalNotNull(consumer); + forEachRemaining((IntConsumer) consumer::accept); + } + } + } + + /** + * See <a href="https://docs.oracle.com/javase/8/docs/api/java/util/Spliterator.OfLong.html"> + * the official Java API doc</a> for details. + */ + interface OfLong extends OfPrimitive<Long, LongConsumer, OfLong> { + @Override + default boolean tryAdvance(Consumer<? super Long> consumer) { + if (consumer instanceof LongConsumer) { + return tryAdvance((LongConsumer) consumer); + } else { + checkCriticalNotNull(consumer); + return tryAdvance((LongConsumer) consumer::accept); + } + } + + @Override + default void forEachRemaining(Consumer<? super Long> consumer) { + if (consumer instanceof LongConsumer) { + forEachRemaining((LongConsumer) consumer); + } else { + checkCriticalNotNull(consumer); + forEachRemaining((LongConsumer) consumer::accept); + } + } + } +}
diff --git a/user/super/com/google/gwt/emul/java/util/Spliterators.java b/user/super/com/google/gwt/emul/java/util/Spliterators.java new file mode 100644 index 0000000..7e44465 --- /dev/null +++ b/user/super/com/google/gwt/emul/java/util/Spliterators.java
@@ -0,0 +1,736 @@ +/* + * Copyright 2016 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package java.util; + +import static javaemul.internal.InternalPreconditions.checkCriticalElement; +import static javaemul.internal.InternalPreconditions.checkCriticalPositionIndexes; +import static javaemul.internal.InternalPreconditions.checkCriticalState; +import static javaemul.internal.InternalPreconditions.checkNotNull; + +import java.util.function.Consumer; +import java.util.function.DoubleConsumer; +import java.util.function.IntConsumer; +import java.util.function.LongConsumer; + +/** + * See <a href="https://docs.oracle.com/javase/8/docs/api/java/util/Spliterators.html"> + * the official Java API doc</a> for details. + * + * Since it's hard to implement parallel algorithms in the browser environment + * and to keep code simple, implementation does not provide splitting. + */ +public final class Spliterators { + + private static class BaseSpliterator<T, S extends Spliterator<T>> { + private final int characteristics; + private long sizeEstimate; + + BaseSpliterator(long size, int characteristics) { + this.sizeEstimate = size; + this.characteristics = (characteristics & Spliterator.SIZED) != 0 ? + characteristics | Spliterator.SUBSIZED : characteristics; + } + + public int characteristics() { + return characteristics; + } + + public long estimateSize() { + return sizeEstimate; + } + + public S trySplit() { + // see javadoc for java.util.Spliterator + return null; + } + } + + /** + * See <a href="https://docs.oracle.com/javase/8/docs/api/java/util/Spliterators.AbstractSpliterator.html"> + * the official Java API doc</a> for details. + */ + public abstract static class AbstractSpliterator<T> + extends BaseSpliterator<T, Spliterator<T>> implements Spliterator<T> { + + protected AbstractSpliterator(long size, int characteristics) { + super(size, characteristics); + } + } + + /** + * See <a href="https://docs.oracle.com/javase/8/docs/api/java/util/Spliterators.AbstractDoubleSpliterator.html"> + * the official Java API doc</a> for details. + */ + public abstract static class AbstractDoubleSpliterator + extends BaseSpliterator<Double, Spliterator.OfDouble> implements Spliterator.OfDouble { + + protected AbstractDoubleSpliterator(long size, int characteristics) { + super(size, characteristics); + } + } + + /** + * See <a href="https://docs.oracle.com/javase/8/docs/api/java/util/Spliterators.AbstractIntSpliterator.html"> + * the official Java API doc</a> for details. + */ + public abstract static class AbstractIntSpliterator + extends BaseSpliterator<Integer, Spliterator.OfInt> implements Spliterator.OfInt { + + protected AbstractIntSpliterator(long size, int characteristics) { + super(size, characteristics); + } + } + + /** + * See <a href="https://docs.oracle.com/javase/8/docs/api/java/util/Spliterators.AbstractLongSpliterator.html"> + * the official Java API doc</a> for details. + */ + public abstract static class AbstractLongSpliterator + extends BaseSpliterator<Long, Spliterator.OfLong> implements Spliterator.OfLong { + + protected AbstractLongSpliterator(long size, int characteristics) { + super(size, characteristics); + } + } + + @SuppressWarnings("unchecked") + public static <T> Spliterator<T> emptySpliterator() { + return (Spliterator<T>) EmptySpliterator.OF_REF; + } + + public static Spliterator.OfDouble emptyDoubleSpliterator() { + return EmptySpliterator.OF_DOUBLE; + } + + public static Spliterator.OfInt emptyIntSpliterator() { + return EmptySpliterator.OF_INT; + } + + public static Spliterator.OfLong emptyLongSpliterator() { + return EmptySpliterator.OF_LONG; + } + + public static <T> Spliterator<T> spliterator(Object[] array, int characteristics) { + return new ArraySpliterator<>(array, characteristics); + } + + public static <T> Spliterator<T> spliterator(Object[] array, int fromIndex, int toIndex, + int characteristics) { + return new ArraySpliterator<>(array, fromIndex, toIndex, characteristics); + } + + public static Spliterator.OfInt spliterator(int[] array, int characteristics) { + return new IntArraySpliterator(array, characteristics); + } + + public static Spliterator.OfInt spliterator(int[] array, int fromIndex, int toIndex, + int characteristics) { + return new IntArraySpliterator(array, fromIndex, toIndex, characteristics); + } + + public static Spliterator.OfLong spliterator(long[] array, int characteristics) { + return new LongArraySpliterator(array, characteristics); + } + + public static Spliterator.OfLong spliterator(long[] array, int fromIndex, int toIndex, + int characteristics) { + return new LongArraySpliterator(array, fromIndex, toIndex, characteristics); + } + + public static Spliterator.OfDouble spliterator(double[] array, int characteristics) { + return new DoubleArraySpliterator(array, characteristics); + } + + public static Spliterator.OfDouble spliterator(double[] array, int fromIndex, int toIndex, + int characteristics) { + return new DoubleArraySpliterator(array, fromIndex, toIndex, characteristics); + } + + public static <T> Spliterator<T> spliterator(Collection<? extends T> c, int characteristics) { + return new IteratorSpliterator<>(c, characteristics); + } + + public static <T> Spliterator<T> spliterator(Iterator<? extends T> it, long size, + int characteristics) { + return new IteratorSpliterator<>(it, size, characteristics); + } + + public static <T> Spliterator<T> spliteratorUnknownSize(Iterator<? extends T> it, + int characteristics) { + return new IteratorSpliterator<>(it, characteristics); + } + + public static Spliterator.OfInt spliterator(PrimitiveIterator.OfInt it, long size, + int characteristics) { + return new IntIteratorSpliterator(it, size, characteristics); + } + + public static Spliterator.OfInt spliteratorUnknownSize(PrimitiveIterator.OfInt it, + int characteristics) { + return new IntIteratorSpliterator(it, characteristics); + } + + public static Spliterator.OfLong spliterator(PrimitiveIterator.OfLong it, long size, + int characteristics) { + return new LongIteratorSpliterator(it, size, characteristics); + } + + public static Spliterator.OfLong spliteratorUnknownSize(PrimitiveIterator.OfLong it, + int characteristics) { + return new LongIteratorSpliterator(it, characteristics); + } + + public static Spliterator.OfDouble spliterator(PrimitiveIterator.OfDouble it, long size, + int characteristics) { + return new DoubleIteratorSpliterator(it, size, characteristics); + } + + public static Spliterator.OfDouble spliteratorUnknownSize(PrimitiveIterator.OfDouble it, + int characteristics) { + return new DoubleIteratorSpliterator(it, characteristics); + } + + public static <T> Iterator<T> iterator(Spliterator<? extends T> spliterator) { + return new ConsumerIterator<>(spliterator); + } + + public static PrimitiveIterator.OfDouble iterator(Spliterator.OfDouble spliterator) { + return new DoubleConsumerIterator(spliterator); + } + + public static PrimitiveIterator.OfInt iterator(Spliterator.OfInt spliterator) { + return new IntConsumerIterator(spliterator); + } + + public static PrimitiveIterator.OfLong iterator(Spliterator.OfLong spliterator) { + return new LongConsumerIterator(spliterator); + } + + private abstract static class EmptySpliterator<T, S extends Spliterator<T>, C> { + + static final Spliterator<Object> OF_REF = new EmptySpliterator.OfRef<>(); + static final Spliterator.OfDouble OF_DOUBLE = new EmptySpliterator.OfDouble(); + static final Spliterator.OfInt OF_INT = new EmptySpliterator.OfInt(); + static final Spliterator.OfLong OF_LONG = new EmptySpliterator.OfLong(); + + public int characteristics() { + return Spliterator.SIZED | Spliterator.SUBSIZED; + } + + public long estimateSize() { + return 0; + } + + public void forEachRemaining(C consumer) { + checkNotNull(consumer); + } + + public boolean tryAdvance(C consumer) { + checkNotNull(consumer); + return false; + } + + public S trySplit() { + return null; + } + + private static final class OfRef<T> + extends EmptySpliterator<T, Spliterator<T>, Consumer<? super T>> + implements Spliterator<T> { + + OfRef() { } + } + + private static final class OfDouble + extends EmptySpliterator<Double, Spliterator.OfDouble, DoubleConsumer> + implements Spliterator.OfDouble { + + OfDouble() { } + } + + private static final class OfInt + extends EmptySpliterator<Integer, Spliterator.OfInt, IntConsumer> + implements Spliterator.OfInt { + + OfInt() { } + } + + private static final class OfLong + extends EmptySpliterator<Long, Spliterator.OfLong, LongConsumer> + implements Spliterator.OfLong { + + OfLong() { } + } + } + + private static final class ConsumerIterator<T> implements Consumer<T>, Iterator<T> { + private final Spliterator<? extends T> spliterator; + private T nextElement; + private boolean hasElement = false; + + ConsumerIterator(Spliterator<? extends T> spliterator) { + this.spliterator = checkNotNull(spliterator); + } + + @Override + public void accept(T element) { + nextElement = element; + } + + @Override + public boolean hasNext() { + if (!hasElement) { + hasElement = spliterator.tryAdvance(this); + } + return hasElement; + } + + @Override + public T next() { + checkCriticalElement(hasNext()); + hasElement = false; + T element = nextElement; + nextElement = null; + return element; + } + } + + private static final class DoubleConsumerIterator + implements DoubleConsumer, PrimitiveIterator.OfDouble { + + private final Spliterator.OfDouble spliterator; + private double nextElement; + private boolean hasElement = false; + + DoubleConsumerIterator(Spliterator.OfDouble spliterator) { + this.spliterator = checkNotNull(spliterator); + } + + @Override + public void accept(double d) { + nextElement = d; + } + + @Override + public boolean hasNext() { + if (!hasElement) { + hasElement = spliterator.tryAdvance(this); + } + return hasElement; + } + + @Override + public double nextDouble() { + checkCriticalElement(hasNext()); + hasElement = false; + return nextElement; + } + } + + private static final class IntConsumerIterator + implements IntConsumer, PrimitiveIterator.OfInt { + + private final Spliterator.OfInt spliterator; + private int nextElement; + private boolean hasElement = false; + + IntConsumerIterator(Spliterator.OfInt spliterator) { + this.spliterator = checkNotNull(spliterator); + } + + @Override + public void accept(int i) { + nextElement = i; + } + + @Override + public boolean hasNext() { + if (!hasElement) { + hasElement = spliterator.tryAdvance(this); + } + return hasElement; + } + + @Override + public int nextInt() { + checkCriticalElement(hasNext()); + hasElement = false; + return nextElement; + } + } + + private static final class LongConsumerIterator + implements LongConsumer, PrimitiveIterator.OfLong { + + private final Spliterator.OfLong spliterator; + private long nextElement; + private boolean hasElement = false; + + LongConsumerIterator(Spliterator.OfLong spliterator) { + this.spliterator = checkNotNull(spliterator); + } + + @Override + public void accept(long l) { + nextElement = l; + } + + @Override + public boolean hasNext() { + if (!hasElement) { + hasElement = spliterator.tryAdvance(this); + } + return hasElement; + } + + @Override + public long nextLong() { + checkCriticalElement(hasNext()); + hasElement = false; + return nextElement; + } + } + + static class IteratorSpliterator<T> implements Spliterator<T> { + private Collection<? extends T> collection; + private Iterator<? extends T> it; + private final int characteristics; + private long estimateSize; + + IteratorSpliterator(Collection<? extends T> collection, int characteristics) { + this.collection = checkNotNull(collection); + this.characteristics = sizeKnownIteratorSpliteratorCharacteristics(characteristics); + } + + IteratorSpliterator(Iterator<? extends T> it, long size, int characteristics) { + this.it = checkNotNull(it); + this.characteristics = sizeKnownIteratorSpliteratorCharacteristics(characteristics); + this.estimateSize = size; + } + + IteratorSpliterator(Iterator<? extends T> it, int characteristics) { + this.it = checkNotNull(it); + this.characteristics = sizeUnknownSpliteratorCharacteristics(characteristics); + this.estimateSize = Long.MAX_VALUE; + } + + @Override + public int characteristics() { + return characteristics; + } + + @Override + public long estimateSize() { + initIterator(); + return estimateSize; + } + + @Override + public void forEachRemaining(Consumer<? super T> consumer) { + initIterator(); + it.forEachRemaining(consumer); + } + + @Override + public Comparator<? super T> getComparator() { + checkSorted(characteristics); + return null; + } + + @Override + public boolean tryAdvance(Consumer<? super T> consumer) { + checkNotNull(consumer); + initIterator(); + if (it.hasNext()) { + consumer.accept(it.next()); + return true; + } + return false; + } + + @Override + public Spliterator<T> trySplit() { + // see javadoc for java.util.Spliterator + return null; + } + + private void initIterator() { + if (it == null) { + it = collection.iterator(); + estimateSize = (long) collection.size(); + } + } + } + + private static final class DoubleIteratorSpliterator extends AbstractDoubleSpliterator { + private final PrimitiveIterator.OfDouble it; + + DoubleIteratorSpliterator(PrimitiveIterator.OfDouble it, long size, int characteristics) { + super(size, sizeKnownIteratorSpliteratorCharacteristics(characteristics)); + this.it = checkNotNull(it); + } + + DoubleIteratorSpliterator(PrimitiveIterator.OfDouble it, int characteristics) { + super(Long.MAX_VALUE, sizeUnknownSpliteratorCharacteristics(characteristics)); + this.it = checkNotNull(it); + } + + @Override + public void forEachRemaining(DoubleConsumer consumer) { + it.forEachRemaining(consumer); + } + + @Override + public Comparator<? super Double> getComparator() { + checkSorted(characteristics()); + return null; + } + + @Override + public boolean tryAdvance(DoubleConsumer consumer) { + checkNotNull(consumer); + if (it.hasNext()) { + consumer.accept(it.nextDouble()); + return true; + } + return false; + } + } + + private static final class IntIteratorSpliterator extends AbstractIntSpliterator { + private final PrimitiveIterator.OfInt it; + + IntIteratorSpliterator(PrimitiveIterator.OfInt it, long size, int characteristics) { + super(size, sizeKnownIteratorSpliteratorCharacteristics(characteristics)); + this.it = checkNotNull(it); + } + + IntIteratorSpliterator(PrimitiveIterator.OfInt it, int characteristics) { + super(Long.MAX_VALUE, sizeUnknownSpliteratorCharacteristics(characteristics)); + this.it = checkNotNull(it); + } + + @Override + public void forEachRemaining(IntConsumer consumer) { + it.forEachRemaining(consumer); + } + + @Override + public Comparator<? super Integer> getComparator() { + checkSorted(characteristics()); + return null; + } + + @Override + public boolean tryAdvance(IntConsumer consumer) { + checkNotNull(consumer); + if (it.hasNext()) { + consumer.accept(it.nextInt()); + return true; + } + return false; + } + } + + private static final class LongIteratorSpliterator extends AbstractLongSpliterator { + private final PrimitiveIterator.OfLong it; + + LongIteratorSpliterator(PrimitiveIterator.OfLong it, long size, int characteristics) { + super(size, sizeKnownIteratorSpliteratorCharacteristics(characteristics)); + this.it = checkNotNull(it); + } + + LongIteratorSpliterator(PrimitiveIterator.OfLong it, int characteristics) { + super(Long.MAX_VALUE, sizeUnknownSpliteratorCharacteristics(characteristics)); + this.it = checkNotNull(it); + } + + @Override + public void forEachRemaining(LongConsumer consumer) { + it.forEachRemaining(consumer); + } + + @Override + public Comparator<? super Long> getComparator() { + checkSorted(characteristics()); + return null; + } + + @Override + public boolean tryAdvance(LongConsumer consumer) { + checkNotNull(consumer); + if (it.hasNext()) { + consumer.accept(it.nextLong()); + return true; + } + return false; + } + } + + private abstract static class BaseArraySpliterator<T, S extends Spliterator<T>, C> { + private int index; + private final int limit; + private final int characteristics; + + BaseArraySpliterator(int from, int limit, int size, int characteristics) { + checkCriticalPositionIndexes(from, limit, size); + this.index = from; + this.limit = limit; + this.characteristics = sizeKnownSpliteratorCharacteristics(characteristics); + } + + public int characteristics() { + return characteristics; + } + + public long estimateSize() { + return limit - index; + } + + public void forEachRemaining(C consumer) { + checkNotNull(consumer); + while (index < limit) { + consume(consumer, index++); + } + } + + public Comparator<? super T> getComparator() { + checkSorted(characteristics); + return null; + } + + public boolean tryAdvance(C consumer) { + checkNotNull(consumer); + if (index < limit) { + consume(consumer, index++); + return true; + } + return false; + } + + public S trySplit() { + // see javadoc for java.util.Spliterator + return null; + } + + protected abstract void consume(C consumer, int index); + } + + private static final class ArraySpliterator<T> + extends BaseArraySpliterator<T, Spliterator<T>, Consumer<? super T>> + implements Spliterator<T> { + + private final Object[] array; + + ArraySpliterator(Object[] array, int characteristics) { + this(array, 0, array.length, characteristics); + } + + ArraySpliterator(Object[] array, int from, int limit, int characteristics) { + super(from, limit, array.length, characteristics); + this.array = array; + } + + @SuppressWarnings("unchecked") + @Override + protected void consume(Consumer<? super T> consumer, int index) { + consumer.accept((T) array[index]); + } + } + + private static final class DoubleArraySpliterator + extends BaseArraySpliterator<Double, Spliterator.OfDouble, DoubleConsumer> + implements Spliterator.OfDouble { + + private final double[] array; + + DoubleArraySpliterator(double[] array, int characteristics) { + this(array, 0, array.length, characteristics); + } + + DoubleArraySpliterator(double[] array, int from, int limit, int characteristics) { + super(from, limit, array.length, characteristics); + this.array = array; + } + + @Override + protected void consume(DoubleConsumer consumer, int index) { + consumer.accept(array[index]); + } + } + + private static final class IntArraySpliterator + extends BaseArraySpliterator<Integer, Spliterator.OfInt, IntConsumer> + implements Spliterator.OfInt { + + private final int[] array; + + IntArraySpliterator(int[] array, int characteristics) { + this(array, 0, array.length, characteristics); + } + + IntArraySpliterator(int[] array, int from, int limit, int characteristics) { + super(from, limit, array.length, characteristics); + this.array = array; + } + + @Override + protected void consume(IntConsumer consumer, int index) { + consumer.accept(array[index]); + } + } + + private static final class LongArraySpliterator + extends BaseArraySpliterator<Long, Spliterator.OfLong, LongConsumer> + implements Spliterator.OfLong { + + private final long[] array; + + LongArraySpliterator(long[] array, int characteristics) { + this(array, 0, array.length, characteristics); + } + + LongArraySpliterator(long[] array, int from, int limit, int characteristics) { + super(from, limit, array.length, characteristics); + this.array = array; + } + + @Override + protected void consume(LongConsumer consumer, int index) { + consumer.accept(array[index]); + } + } + + private static void checkSorted(int characteristics) { + checkCriticalState((characteristics & Spliterator.SORTED) != 0); + } + + private static int sizeKnownSpliteratorCharacteristics(int characteristics) { + return characteristics | Spliterator.SIZED | Spliterator.SUBSIZED; + } + + private static int sizeKnownIteratorSpliteratorCharacteristics(int characteristics) { + return (characteristics & Spliterator.CONCURRENT) == 0 ? + sizeKnownSpliteratorCharacteristics(characteristics) : characteristics; + } + + private static int sizeUnknownSpliteratorCharacteristics(int characteristics) { + return characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED); + } + + private Spliterators() { } + +}
diff --git a/user/test/com/google/gwt/emultest/EmulJava8Suite.java b/user/test/com/google/gwt/emultest/EmulJava8Suite.java index 7b311b3..0d90d04 100644 --- a/user/test/com/google/gwt/emultest/EmulJava8Suite.java +++ b/user/test/com/google/gwt/emultest/EmulJava8Suite.java
@@ -24,6 +24,7 @@ import com.google.gwt.emultest.java8.util.OptionalLongTest; import com.google.gwt.emultest.java8.util.OptionalTest; import com.google.gwt.emultest.java8.util.PrimitiveIteratorTest; +import com.google.gwt.emultest.java8.util.SpliteratorsTest; import com.google.gwt.emultest.java8.util.StringJoinerTest; import com.google.gwt.junit.tools.GWTTestSuite; @@ -44,6 +45,7 @@ suite.addTestSuite(OptionalLongTest.class); suite.addTestSuite(OptionalDoubleTest.class); suite.addTestSuite(PrimitiveIteratorTest.class); + suite.addTestSuite(SpliteratorsTest.class); suite.addTestSuite(StringJoinerTest.class); suite.addTestSuite(DoubleSummaryStatisticsTest.class); suite.addTestSuite(IntSummaryStatisticsTest.class);
diff --git a/user/test/com/google/gwt/emultest/java8/util/SpliteratorsTest.java b/user/test/com/google/gwt/emultest/java8/util/SpliteratorsTest.java new file mode 100644 index 0000000..4c5a23b --- /dev/null +++ b/user/test/com/google/gwt/emultest/java8/util/SpliteratorsTest.java
@@ -0,0 +1,308 @@ +/* + * Copyright 2016 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.emultest.java8.util; + +import com.google.gwt.junit.client.GWTTestCase; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Deque; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.PrimitiveIterator; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.function.Supplier; + +/** + * Tests for Spliterators JRE emulation. + */ +public class SpliteratorsTest extends GWTTestCase { + + @Override + public String getModuleName() { + return "com.google.gwt.emultest.EmulSuite"; + } + + public void testEmptySpliterator() { + testSpliterator(new Object[0], Spliterators::emptySpliterator, true); + } + + public void testEmptyDoubleSpliterator() { + testDoubleSpliterator(new double[0], Spliterators::emptyDoubleSpliterator, true); + } + + public void testEmptyIntSpliterator() { + testIntSpliterator(new int[0], Spliterators::emptyIntSpliterator, true); + } + + public void testEmptyLongSpliterator() { + testLongSpliterator(new long[0], Spliterators::emptyLongSpliterator, true); + } + + public void testSpliterator() { + final String[] original = {"1", "2", "3", "4"}; + testSpliterator(original, () -> Spliterators.spliterator(Arrays.asList(original), 0), true); + testSpliterator(original, () -> Spliterators.spliterator(Arrays.asList(original).iterator(), original.length, 0), true); + testSpliterator(original, () -> Spliterators.spliteratorUnknownSize(Arrays.asList(original).iterator(), 0), false); + testSpliterator(original, () -> Spliterators.spliterator(original, 0), true); + testSpliterator(Arrays.copyOfRange(original, 1, 3), () -> Spliterators.spliterator(original, 1, 3, 0), true); + } + + public void testDoubleSpliterator() { + final double[] original = {1., 2., 3., 4.}; + testDoubleSpliterator(original, () -> Spliterators.spliterator(original, 0), true); + testDoubleSpliterator(Arrays.copyOfRange(original, 1, 3), () -> Spliterators.spliterator(original, 1, 3, 0), true); + testDoubleSpliterator(original, () -> Spliterators.spliterator(createPrimitiveDoubleIterator(original), original.length, 0), true); + } + + public void testIntSpliterator() { + final int[] original = {1, 2, 3, 4}; + testIntSpliterator(original, () -> Spliterators.spliterator(original, 0), true); + testIntSpliterator(Arrays.copyOfRange(original, 1, 3), () -> Spliterators.spliterator(original, 1, 3, 0), true); + testIntSpliterator(original, () -> Spliterators.spliterator(createPrimitiveIntIterator(original), original.length, 0), true); + } + + public void testLongSpliterator() { + final long[] original = {1, 2, 3, 4}; + testLongSpliterator(original, () -> Spliterators.spliterator(original, 0), true); + testLongSpliterator(Arrays.copyOfRange(original, 1, 3), () -> Spliterators.spliterator(original, 1, 3, 0), true); + testLongSpliterator(original, () -> Spliterators.spliterator(createPrimitiveLongIterator(original), original.length, 0), true); + } + + public void testIterator() { + final String[] original = {"1", "2", "3", "4"}; + Spliterator<String> spliterator = Spliterators.spliterator(Arrays.asList(original), 0); + Iterator<String> it = Spliterators.iterator(spliterator); + + try { + it.remove(); + fail(); + } catch (UnsupportedOperationException expected) { + } + + Deque<String> values = new LinkedList<>(Arrays.asList(original)); + it.forEachRemaining(value -> assertEquals(values.pop(), value)); + assertEquals(0, values.size()); + } + + public void testDoubleIterator() { + final double[] original = {1., 2., 3., 4.}; + Spliterator.OfDouble spliterator = Spliterators.spliterator(original, 0); + PrimitiveIterator.OfDouble it = Spliterators.iterator(spliterator); + + try { + it.remove(); + fail(); + } catch (UnsupportedOperationException expected) { + } + + Deque<Double> values = new LinkedList<>(toDoubleCollection(original)); + it.forEachRemaining((double value) -> assertEquals((double) values.pop(), value)); + assertEquals(0, values.size()); + } + + public void testIntIterator() { + final int[] original = {1, 2, 3, 4}; + Spliterator.OfInt spliterator = Spliterators.spliterator(original, 0); + PrimitiveIterator.OfInt it = Spliterators.iterator(spliterator); + + try { + it.remove(); + fail(); + } catch (UnsupportedOperationException expected) { + } + + Deque<Integer> values = new LinkedList<>(toIntCollection(original)); + it.forEachRemaining((int value) -> assertEquals((int) values.pop(), value)); + assertEquals(0, values.size()); + } + + public void testLongIterator() { + final long[] original = {1, 2, 3, 4}; + Spliterator.OfLong spliterator = Spliterators.spliterator(original, 0); + PrimitiveIterator.OfLong it = Spliterators.iterator(spliterator); + + try { + it.remove(); + fail(); + } catch (UnsupportedOperationException expected) { + } + + Deque<Long> values = new LinkedList<>(toLongCollection(original)); + it.forEachRemaining((long value) -> assertEquals((long) values.pop(), value)); + assertEquals(0, values.size()); + } + + private <T> void testSpliterator(T[] original, Supplier<Spliterator<T>> supplier, boolean sizeKnown) { + Spliterator<T> spliterator = supplier.get(); + if (sizeKnown) { + assertEquals(original.length, spliterator.estimateSize()); + assertEquals(original.length, spliterator.getExactSizeIfKnown()); + } else { + assertEquals(Long.MAX_VALUE, spliterator.estimateSize()); + assertEquals(-1L, spliterator.getExactSizeIfKnown()); + } + + Deque<T> values = new LinkedList<>(Arrays.asList(original)); + spliterator.forEachRemaining(value -> assertEquals(values.pop(), value)); + spliterator.forEachRemaining(value -> fail()); + assertEquals(0, values.size()); + + spliterator = supplier.get(); + for (T originalValue : original) { + assertTrue(spliterator.tryAdvance(value -> assertEquals(originalValue, value))); + } + assertFalse(spliterator.tryAdvance(value -> fail())); + } + + private void testDoubleSpliterator(double[] original, Supplier<Spliterator.OfDouble> supplier, boolean sizeKnown) { + Spliterator.OfDouble spliterator = supplier.get(); + if (sizeKnown) { + assertEquals(original.length, spliterator.estimateSize()); + assertEquals(original.length, spliterator.getExactSizeIfKnown()); + } else { + assertEquals(Long.MAX_VALUE, spliterator.estimateSize()); + assertEquals(-1L, spliterator.getExactSizeIfKnown()); + } + + Deque<Double> values = new LinkedList<>(toDoubleCollection(original)); + spliterator.forEachRemaining((double value) -> assertEquals((double) values.pop(), value)); + spliterator.forEachRemaining((double value) -> fail()); + assertEquals(0, values.size()); + + spliterator = supplier.get(); + for (double originalValue : original) { + assertTrue(spliterator.tryAdvance((double value) -> assertEquals(originalValue, value))); + } + assertFalse(spliterator.tryAdvance((double value) -> fail())); + } + + private void testIntSpliterator(int[] original, Supplier<Spliterator.OfInt> supplier, boolean sizeKnown) { + Spliterator.OfInt spliterator = supplier.get(); + if (sizeKnown) { + assertEquals(original.length, spliterator.estimateSize()); + assertEquals(original.length, spliterator.getExactSizeIfKnown()); + } else { + assertEquals(Long.MAX_VALUE, spliterator.estimateSize()); + assertEquals(-1L, spliterator.getExactSizeIfKnown()); + } + + Deque<Integer> values = new LinkedList<>(toIntCollection(original)); + spliterator.forEachRemaining((int value) -> assertEquals((int) values.pop(), value)); + spliterator.forEachRemaining((int value) -> fail()); + assertEquals(0, values.size()); + + spliterator = supplier.get(); + for (int originalValue : original) { + assertTrue(spliterator.tryAdvance((int value) -> assertEquals(originalValue, value))); + } + assertFalse(spliterator.tryAdvance((int value) -> fail())); + } + + private void testLongSpliterator(long[] original, Supplier<Spliterator.OfLong> supplier, boolean sizeKnown) { + Spliterator.OfLong spliterator = supplier.get(); + if (sizeKnown) { + assertEquals(original.length, spliterator.estimateSize()); + assertEquals(original.length, spliterator.getExactSizeIfKnown()); + } else { + assertEquals(Long.MAX_VALUE, spliterator.estimateSize()); + assertEquals(-1L, spliterator.getExactSizeIfKnown()); + } + + Deque<Long> values = new LinkedList<>(toLongCollection(original)); + spliterator.forEachRemaining((long value) -> assertEquals((long) values.pop(), value)); + spliterator.forEachRemaining((long value) -> fail()); + assertEquals(0, values.size()); + + spliterator = supplier.get(); + for (long originalValue : original) { + assertTrue(spliterator.tryAdvance((long value) -> assertEquals(originalValue, value))); + } + assertFalse(spliterator.tryAdvance((long value) -> fail())); + } + + private static Collection<Double> toDoubleCollection(double[] values) { + ArrayList<Double> c = new ArrayList<>(); + for (double value : values) { + c.add(value); + } + return c; + } + + private static Collection<Integer> toIntCollection(int[] values) { + ArrayList<Integer> c = new ArrayList<>(); + for (int value : values) { + c.add(value); + } + return c; + } + + private static Collection<Long> toLongCollection(long[] values) { + ArrayList<Long> c = new ArrayList<>(); + for (long value : values) { + c.add(value); + } + return c; + } + + private static PrimitiveIterator.OfDouble createPrimitiveDoubleIterator(double[] values) { + final Iterator<Double> it = toDoubleCollection(values).iterator(); + return new PrimitiveIterator.OfDouble() { + @Override + public double nextDouble() { + return it.next(); + } + + @Override + public boolean hasNext() { + return it.hasNext(); + } + }; + } + + private static PrimitiveIterator.OfInt createPrimitiveIntIterator(int[] values) { + final Iterator<Integer> it = toIntCollection(values).iterator(); + return new PrimitiveIterator.OfInt() { + @Override + public int nextInt() { + return it.next(); + } + + @Override + public boolean hasNext() { + return it.hasNext(); + } + }; + } + + private static PrimitiveIterator.OfLong createPrimitiveLongIterator(long[] values) { + final Iterator<Long> it = toLongCollection(values).iterator(); + return new PrimitiveIterator.OfLong() { + @Override + public long nextLong() { + return it.next(); + } + + @Override + public boolean hasNext() { + return it.hasNext(); + } + }; + } + +}