/* * Copyright 2015, 2016 Tagir Valeev * * 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 one.util.streamex; import java.util.List; import java.util.Map.Entry; import java.util.Spliterator; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.DoubleBinaryOperator; import java.util.function.DoubleConsumer; import java.util.function.IntBinaryOperator; import java.util.function.IntConsumer; import java.util.function.LongBinaryOperator; import java.util.function.LongConsumer; import static one.util.streamex.StreamExInternals.*; /** * @author Tagir Valeev */ /* package */abstract class RangeBasedSpliterator<T, S extends RangeBasedSpliterator<T, ?>> extends CloneableSpliterator<T, S> { int cur; int limit; public RangeBasedSpliterator(int fromInclusive, int toExclusive) { this.cur = fromInclusive; this.limit = toExclusive; } @Override public long estimateSize() { return limit - cur; } @Override public int characteristics() { return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED; } @Override public S trySplit() { int size = limit - cur; if (size >= 2) { S clone = doClone(); clone.limit = this.cur = this.cur + size / 2; return clone; } return null; } static final class AsEntry<T> extends RangeBasedSpliterator<Entry<Integer, T>, AsEntry<T>> { private final List<T> list; public AsEntry(List<T> list) { super(0, list.size()); this.list = list; } @Override public boolean tryAdvance(Consumer<? super Entry<Integer, T>> action) { if (cur < limit) { action.accept(new ObjIntBox<>(list.get(cur), cur)); cur++; return true; } return false; } @Override public void forEachRemaining(Consumer<? super Entry<Integer, T>> action) { int l = limit, c = cur; List<T> list = this.list; while (c < l) { action.accept(new ObjIntBox<>(list.get(c), c)); c++; } cur = limit; } } static final class OfSubLists<T> extends RangeBasedSpliterator<List<T>, OfSubLists<T>> { private final List<T> source; private final int length; private final int shift; private final int listSize; public OfSubLists(List<T> source, int length, int shift) { super(0, Math.max(0, source.size() - Math.max(length - shift, 0) - 1) / shift + 1); this.source = source; this.listSize = source.size(); this.shift = shift; this.length = length; } @Override public boolean tryAdvance(Consumer<? super List<T>> action) { if (cur < limit) { int start = cur * shift; int stop = listSize - length > start ? start + length : listSize; action.accept(source.subList(start, stop)); cur++; return true; } return false; } @Override public void forEachRemaining(Consumer<? super List<T>> action) { int l = limit, c = cur, ll = length, sf = shift, ls = listSize; int start = cur * sf; while (c < l) { int stop = ls - ll > start ? start + ll : ls; action.accept(source.subList(start, stop)); start += sf; c++; } cur = limit; } } static final class ZipRef<U, V, T> extends RangeBasedSpliterator<T, ZipRef<U, V, T>> { private final List<U> l1; private final List<V> l2; private final BiFunction<? super U, ? super V, ? extends T> mapper; public ZipRef(int fromInclusive, int toExclusive, BiFunction<? super U, ? super V, ? extends T> mapper, List<U> l1, List<V> l2) { super(fromInclusive, toExclusive); this.l1 = l1; this.l2 = l2; this.mapper = mapper; } @Override public boolean tryAdvance(Consumer<? super T> action) { if (cur < limit) { action.accept(mapper.apply(l1.get(cur), l2.get(cur))); cur++; return true; } return false; } @Override public void forEachRemaining(Consumer<? super T> action) { int l = limit, c = cur; while (c < l) { action.accept(mapper.apply(l1.get(c), l2.get(c))); c++; } cur = limit; } } static final class ZipInt extends RangeBasedSpliterator<Integer, ZipInt> implements Spliterator.OfInt { private final IntBinaryOperator mapper; private final int[] arr1, arr2; public ZipInt(int fromInclusive, int toExclusive, IntBinaryOperator mapper, int[] arr1, int[] arr2) { super(fromInclusive, toExclusive); this.mapper = mapper; this.arr1 = arr1; this.arr2 = arr2; } @Override public boolean tryAdvance(IntConsumer action) { if (cur < limit) { action.accept(mapper.applyAsInt(arr1[cur], arr2[cur])); cur++; return true; } return false; } @Override public void forEachRemaining(IntConsumer action) { int l = limit, c = cur; while (c < l) { action.accept(mapper.applyAsInt(arr1[c], arr2[c])); c++; } cur = limit; } } static final class OfByte extends RangeBasedSpliterator<Integer, OfByte> implements Spliterator.OfInt { private final byte[] array; public OfByte(int fromInclusive, int toExclusive, byte[] array) { super(fromInclusive, toExclusive); this.array = array; } @Override public boolean tryAdvance(IntConsumer action) { if (cur < limit) { action.accept(array[cur]); cur++; return true; } return false; } @Override public void forEachRemaining(IntConsumer action) { int l = limit, c = cur; while (c < l) { action.accept(array[c++]); } cur = limit; } } static final class OfChar extends RangeBasedSpliterator<Integer, OfChar> implements Spliterator.OfInt { private final char[] array; public OfChar(int fromInclusive, int toExclusive, char[] array) { super(fromInclusive, toExclusive); this.array = array; } @Override public boolean tryAdvance(IntConsumer action) { if (cur < limit) { action.accept(array[cur]); cur++; return true; } return false; } @Override public void forEachRemaining(IntConsumer action) { int l = limit, c = cur; while (c < l) { action.accept(array[c++]); } cur = limit; } } static final class OfShort extends RangeBasedSpliterator<Integer, OfShort> implements Spliterator.OfInt { private final short[] array; public OfShort(int fromInclusive, int toExclusive, short[] array) { super(fromInclusive, toExclusive); this.array = array; } @Override public boolean tryAdvance(IntConsumer action) { if (cur < limit) { action.accept(array[cur]); cur++; return true; } return false; } @Override public void forEachRemaining(IntConsumer action) { int l = limit, c = cur; while (c < l) { action.accept(array[c++]); } cur = limit; } } static final class ZipLong extends RangeBasedSpliterator<Long, ZipLong> implements Spliterator.OfLong { private final LongBinaryOperator mapper; private final long[] arr1, arr2; public ZipLong(int fromInclusive, int toExclusive, LongBinaryOperator mapper, long[] arr1, long[] arr2) { super(fromInclusive, toExclusive); this.mapper = mapper; this.arr1 = arr1; this.arr2 = arr2; } @Override public boolean tryAdvance(LongConsumer action) { if (cur < limit) { action.accept(mapper.applyAsLong(arr1[cur], arr2[cur])); cur++; return true; } return false; } @Override public void forEachRemaining(LongConsumer action) { int l = limit, c = cur; while (c < l) { action.accept(mapper.applyAsLong(arr1[c], arr2[c])); c++; } cur = limit; } } static final class OfFloat extends RangeBasedSpliterator<Double, OfFloat> implements Spliterator.OfDouble { private final float[] array; public OfFloat(int fromInclusive, int toExclusive, float[] array) { super(fromInclusive, toExclusive); this.array = array; } @Override public boolean tryAdvance(DoubleConsumer action) { if (cur < limit) { action.accept(array[cur]); cur++; return true; } return false; } @Override public void forEachRemaining(DoubleConsumer action) { int l = limit, c = cur; while (c < l) { action.accept(array[c++]); } cur = limit; } } static final class ZipDouble extends RangeBasedSpliterator<Double, ZipDouble> implements Spliterator.OfDouble { private final DoubleBinaryOperator mapper; private final double[] arr1, arr2; public ZipDouble(int fromInclusive, int toExclusive, DoubleBinaryOperator mapper, double[] arr1, double[] arr2) { super(fromInclusive, toExclusive); this.mapper = mapper; this.arr1 = arr1; this.arr2 = arr2; } @Override public boolean tryAdvance(DoubleConsumer action) { if (cur < limit) { action.accept(mapper.applyAsDouble(arr1[cur], arr2[cur])); cur++; return true; } return false; } @Override public void forEachRemaining(DoubleConsumer action) { int l = limit, c = cur; while (c < l) { action.accept(mapper.applyAsDouble(arr1[c], arr2[c])); c++; } cur = limit; } } }