blob: 78b8fc614b49222d33c87ab0041c7a6ca1a15fb2 [file] [log] [blame]
/*
* 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.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 abstract static class BaseSpliterator<T, S extends Spliterator<T>>
implements 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) {
checkCriticalArrayBounds(fromIndex, toIndex, array.length);
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) {
checkCriticalArrayBounds(fromIndex, toIndex, array.length);
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) {
checkCriticalArrayBounds(fromIndex, toIndex, array.length);
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) {
checkCriticalArrayBounds(fromIndex, toIndex, array.length);
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>
implements Spliterator<T> {
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>
implements Spliterator<T> {
private int index;
private final int limit;
private final int characteristics;
BaseArraySpliterator(int from, int limit, int characteristics) {
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, 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, 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, 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, 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);
}
/**
* We cant use InternalPreconditions.checkCriticalArrayBounds here because
* Spliterators must throw only ArrayIndexOutOfBoundsException on range check by contract.
*/
private static void checkCriticalArrayBounds(int start, int end, int length) {
if (start > end || start < 0 || end > length) {
throw new ArrayIndexOutOfBoundsException(
"fromIndex: " + start + ", toIndex: " + end + ", length: " + length);
}
}
private Spliterators() { }
}