/* * 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.lang.reflect.AccessibleObject; import java.lang.reflect.Field; import java.math.BigDecimal; import java.math.BigInteger; import java.math.MathContext; import java.nio.ByteOrder; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.*; import java.util.Map.Entry; import java.util.function.*; import java.util.stream.BaseStream; import java.util.stream.Collector; import java.util.stream.Collector.Characteristics; /* package */final class StreamExInternals { static final int INITIAL_SIZE = 128; static final Function<int[], Integer> UNBOX_INT = box -> box[0]; static final Function<long[], Long> UNBOX_LONG = box -> box[0]; static final Function<double[], Double> UNBOX_DOUBLE = box -> box[0]; static final Object NONE = new Object(); static final Set<Characteristics> NO_CHARACTERISTICS = EnumSet.noneOf(Characteristics.class); static final Set<Characteristics> UNORDERED_CHARACTERISTICS = EnumSet.of(Characteristics.UNORDERED); static final Set<Characteristics> UNORDERED_ID_CHARACTERISTICS = EnumSet.of(Characteristics.UNORDERED, Characteristics.IDENTITY_FINISH); static final Set<Characteristics> ID_CHARACTERISTICS = EnumSet.of(Characteristics.IDENTITY_FINISH); static final Field SOURCE_SPLITERATOR; static final Field SOURCE_STAGE; static final Field SOURCE_CLOSE_ACTION; static final Field SPLITERATOR_ITERATOR; static final VersionSpecific VER_SPEC = System.getProperty("java.version", "") .compareTo("1.9") > 0 ? new Java9Specific() : new VersionSpecific(); static { Deque<Field> fields = new ArrayDeque<>(); /* * Fields accessed via reflection are used only for reading and only to * make some performance optimizations decisions. They must be never * written and absence of these fields should not break anything. */ try { AccessController.doPrivileged((PrivilegedExceptionAction<Void>) () -> { Class<?> abstractPipelineClass = Class.forName("java.util.stream.AbstractPipeline"); fields.add(abstractPipelineClass.getDeclaredField("sourceSpliterator")); fields.add(abstractPipelineClass.getDeclaredField("sourceStage")); fields.add(abstractPipelineClass.getDeclaredField("sourceCloseAction")); fields.add(Class.forName("java.util.Spliterators$IteratorSpliterator").getDeclaredField("it")); try { // Work-around Java 9 security model Field unsafeField = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); unsafeField.setAccessible(true); sun.misc.Unsafe U = (sun.misc.Unsafe)unsafeField.get(null); Field override = AccessibleObject.class.getDeclaredField("override"); long offset = U.objectFieldOffset(override); for (Field f : fields) { U.putBoolean(f, offset, true); } } catch (LinkageError | ReflectiveOperationException | SecurityException ex) { for (Field f : fields) f.setAccessible(true); } return null; }); } catch (PrivilegedActionException e) { fields.clear(); } SOURCE_SPLITERATOR = fields.poll(); SOURCE_STAGE = fields.poll(); SOURCE_CLOSE_ACTION = fields.poll(); SPLITERATOR_ITERATOR = fields.poll(); } static final class ByteBuffer { int size = 0; byte[] data; ByteBuffer() { data = new byte[INITIAL_SIZE]; } ByteBuffer(int size) { data = new byte[size]; } void add(int n) { if (data.length == size) { data = copy(data, new byte[data.length * 2], size); } data[size++] = (byte) n; } void addUnsafe(int n) { data[size++] = (byte) n; } void addAll(ByteBuffer buf) { if (data.length < buf.size + size) { data = copy(data, new byte[buf.size + size], size); } System.arraycopy(buf.data, 0, data, size, buf.size); size += buf.size; } byte[] toArray() { return data.length == size ? data : Arrays.copyOfRange(data, 0, size); } } static final class CharBuffer { int size = 0; char[] data; CharBuffer() { data = new char[INITIAL_SIZE]; } CharBuffer(int size) { data = new char[size]; } void add(int n) { if (data.length == size) { data = copy(data, new char[data.length * 2], size); } data[size++] = (char) n; } void addUnsafe(int n) { data[size++] = (char) n; } void addAll(CharBuffer buf) { if (data.length < buf.size + size) { data = copy(data, new char[buf.size + size], size); } System.arraycopy(buf.data, 0, data, size, buf.size); size += buf.size; } char[] toArray() { return data.length == size ? data : Arrays.copyOfRange(data, 0, size); } } static final class ShortBuffer { int size = 0; short[] data; ShortBuffer() { data = new short[INITIAL_SIZE]; } ShortBuffer(int size) { data = new short[size]; } void add(int n) { if (data.length == size) { data = copy(data, new short[data.length * 2], size); } data[size++] = (short) n; } void addUnsafe(int n) { data[size++] = (short) n; } void addAll(ShortBuffer buf) { if (data.length < buf.size + size) { data = copy(data, new short[buf.size + size], size); } System.arraycopy(buf.data, 0, data, size, buf.size); size += buf.size; } short[] toArray() { return data.length == size ? data : Arrays.copyOfRange(data, 0, size); } } static final class FloatBuffer { int size = 0; float[] data; FloatBuffer() { data = new float[INITIAL_SIZE]; } FloatBuffer(int size) { data = new float[size]; } void add(double n) { if (data.length == size) { data = copy(data, new float[data.length * 2], size); } data[size++] = (float) n; } void addUnsafe(double n) { data[size++] = (float) n; } void addAll(FloatBuffer buf) { if (data.length < buf.size + size) { data = copy(data, new float[buf.size + size], size); } System.arraycopy(buf.data, 0, data, size, buf.size); size += buf.size; } float[] toArray() { return data.length == size ? data : Arrays.copyOfRange(data, 0, size); } } static final class IntBuffer { int size = 0; int[] data; IntBuffer() { data = new int[INITIAL_SIZE]; } IntBuffer(int size) { data = new int[size]; } void add(int n) { if (data.length == size) { data = copy(data, new int[data.length * 2], size); } data[size++] = n; } void addAll(IntBuffer buf) { if (data.length < buf.size + size) { data = copy(data, new int[buf.size + size], size); } System.arraycopy(buf.data, 0, data, size, buf.size); size += buf.size; } int[] toArray() { return data.length == size ? data : Arrays.copyOfRange(data, 0, size); } } static final class LongBuffer { int size = 0; long[] data; LongBuffer() { data = new long[INITIAL_SIZE]; } LongBuffer(int size) { data = new long[size]; } void add(long n) { if (data.length == size) { data = copy(data, new long[data.length * 2], size); } data[size++] = n; } void addAll(LongBuffer buf) { if (data.length < buf.size + size) { data = copy(data, new long[buf.size + size], size); } System.arraycopy(buf.data, 0, data, size, buf.size); size += buf.size; } long[] toArray() { return data.length == size ? data : Arrays.copyOfRange(data, 0, size); } } static final class DoubleBuffer { int size = 0; double[] data; DoubleBuffer() { data = new double[INITIAL_SIZE]; } DoubleBuffer(int size) { data = new double[size]; } void add(double n) { if (data.length == size) { data = copy(data, new double[data.length * 2], size); } data[size++] = n; } void addAll(DoubleBuffer buf) { if (data.length < buf.size + size) { data = copy(data, new double[buf.size + size], size); } System.arraycopy(buf.data, 0, data, size, buf.size); size += buf.size; } double[] toArray() { return data.length == size ? data : Arrays.copyOfRange(data, 0, size); } } static final class BooleanMap<T> extends AbstractMap<Boolean, T> { T trueValue, falseValue; BooleanMap(T trueValue, T falseValue) { this.trueValue = trueValue; this.falseValue = falseValue; } @Override public boolean containsKey(Object key) { return key instanceof Boolean; } @Override public T get(Object key) { if (Boolean.TRUE.equals(key)) return trueValue; if (Boolean.FALSE.equals(key)) return falseValue; return null; } @Override public Set<Map.Entry<Boolean, T>> entrySet() { return new AbstractSet<Map.Entry<Boolean, T>>() { @Override public Iterator<Map.Entry<Boolean, T>> iterator() { return Arrays.<Map.Entry<Boolean, T>> asList(new SimpleEntry<>(Boolean.TRUE, trueValue), new SimpleEntry<>(Boolean.FALSE, falseValue)).iterator(); } @Override public int size() { return 2; } }; } @Override public int size() { return 2; } @SuppressWarnings({ "unchecked", "rawtypes" }) static <A, R> PartialCollector<BooleanMap<A>, Map<Boolean, R>> partialCollector(Collector<?, A, R> downstream) { Supplier<A> downstreamSupplier = downstream.supplier(); Supplier<BooleanMap<A>> supplier = () -> new BooleanMap<>(downstreamSupplier.get(), downstreamSupplier .get()); BinaryOperator<A> downstreamCombiner = downstream.combiner(); BiConsumer<BooleanMap<A>, BooleanMap<A>> merger = (left, right) -> { left.trueValue = downstreamCombiner.apply(left.trueValue, right.trueValue); left.falseValue = downstreamCombiner.apply(left.falseValue, right.falseValue); }; if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) { return (PartialCollector) new PartialCollector<>(supplier, merger, Function.identity(), ID_CHARACTERISTICS); } Function<A, R> downstreamFinisher = downstream.finisher(); return new PartialCollector<>(supplier, merger, par -> new BooleanMap<>(downstreamFinisher .apply(par.trueValue), downstreamFinisher.apply(par.falseValue)), NO_CHARACTERISTICS); } } abstract static class BaseCollector<T, A, R> implements MergingCollector<T, A, R> { final Supplier<A> supplier; final BiConsumer<A, A> merger; final Function<A, R> finisher; final Set<Characteristics> characteristics; BaseCollector(Supplier<A> supplier, BiConsumer<A, A> merger, Function<A, R> finisher, Set<Characteristics> characteristics) { this.supplier = supplier; this.merger = merger; this.finisher = finisher; this.characteristics = characteristics; } @Override public Set<Characteristics> characteristics() { return characteristics; } @Override public Supplier<A> supplier() { return supplier; } @Override public Function<A, R> finisher() { return finisher; } @Override public BiConsumer<A, A> merger() { return merger; } } static final class PartialCollector<A, R> extends BaseCollector<Object, A, R> { PartialCollector(Supplier<A> supplier, BiConsumer<A, A> merger, Function<A, R> finisher, Set<Characteristics> characteristics) { super(supplier, merger, finisher, characteristics); } @Override public BiConsumer<A, Object> accumulator() { throw new UnsupportedOperationException(); } IntCollector<A, R> asInt(ObjIntConsumer<A> intAccumulator) { return new IntCollectorImpl<>(supplier, intAccumulator, merger, finisher, characteristics); } LongCollector<A, R> asLong(ObjLongConsumer<A> longAccumulator) { return new LongCollectorImpl<>(supplier, longAccumulator, merger, finisher, characteristics); } DoubleCollector<A, R> asDouble(ObjDoubleConsumer<A> doubleAccumulator) { return new DoubleCollectorImpl<>(supplier, doubleAccumulator, merger, finisher, characteristics); } <T> Collector<T, A, R> asRef(BiConsumer<A, T> accumulator) { return Collector.of(supplier, accumulator, combiner(), finisher, characteristics .toArray(new Characteristics[0])); } <T> Collector<T, A, R> asCancellable(BiConsumer<A, T> accumulator, Predicate<A> finished) { return new CancellableCollectorImpl<>(supplier, accumulator, combiner(), finisher, finished, characteristics); } static PartialCollector<int[], Integer> intSum() { return new PartialCollector<>(() -> new int[1], (box1, box2) -> box1[0] += box2[0], UNBOX_INT, UNORDERED_CHARACTERISTICS); } static PartialCollector<long[], Long> longSum() { return new PartialCollector<>(() -> new long[1], (box1, box2) -> box1[0] += box2[0], UNBOX_LONG, UNORDERED_CHARACTERISTICS); } static PartialCollector<ObjIntBox<BitSet>, boolean[]> booleanArray() { return new PartialCollector<>(() -> new ObjIntBox<>(new BitSet(), 0), (box1, box2) -> { box2.a.stream().forEach(i -> box1.a.set(i + box1.b)); box1.b = StrictMath.addExact(box1.b, box2.b); }, box -> { boolean[] res = new boolean[box.b]; box.a.stream().forEach(i -> res[i] = true); return res; }, NO_CHARACTERISTICS); } @SuppressWarnings("unchecked") static <K, D, A, M extends Map<K, D>> PartialCollector<Map<K, A>, M> grouping(Supplier<M> mapFactory, Collector<?, A, D> downstream) { BinaryOperator<A> downstreamMerger = downstream.combiner(); BiConsumer<Map<K, A>, Map<K, A>> merger = (map1, map2) -> { for (Map.Entry<K, A> e : map2.entrySet()) map1.merge(e.getKey(), e.getValue(), downstreamMerger); }; if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) { return (PartialCollector<Map<K, A>, M>) new PartialCollector<>((Supplier<Map<K, A>>) mapFactory, merger, Function.identity(), ID_CHARACTERISTICS); } Function<A, D> downstreamFinisher = downstream.finisher(); return new PartialCollector<>((Supplier<Map<K, A>>) mapFactory, merger, map -> { map.replaceAll((k, v) -> ((Function<A, A>) downstreamFinisher).apply(v)); return (M) map; }, NO_CHARACTERISTICS); } static PartialCollector<StringBuilder, String> joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix, boolean hasPS) { BiConsumer<StringBuilder, StringBuilder> merger = (sb1, sb2) -> { if (sb2.length() > 0) { if (sb1.length() > 0) sb1.append(delimiter); sb1.append(sb2); } }; Supplier<StringBuilder> supplier = StringBuilder::new; if (hasPS) return new PartialCollector<>(supplier, merger, sb -> String.valueOf(prefix) + sb + suffix, NO_CHARACTERISTICS); return new PartialCollector<>(supplier, merger, StringBuilder::toString, NO_CHARACTERISTICS); } } static abstract class CancellableCollector<T, A, R> implements Collector<T, A, R> { abstract Predicate<A> finished(); } static final class CancellableCollectorImpl<T, A, R> extends CancellableCollector<T, A, R> { private final Supplier<A> supplier; private final BiConsumer<A, T> accumulator; private final BinaryOperator<A> combiner; private final Function<A, R> finisher; private final Predicate<A> finished; private final Set<Characteristics> characteristics; CancellableCollectorImpl(Supplier<A> supplier, BiConsumer<A, T> accumulator, BinaryOperator<A> combiner, Function<A, R> finisher, Predicate<A> finished, Set<java.util.stream.Collector.Characteristics> characteristics) { this.supplier = supplier; this.accumulator = accumulator; this.combiner = combiner; this.finisher = finisher; this.finished = finished; this.characteristics = characteristics; } @Override public Supplier<A> supplier() { return supplier; } @Override public BiConsumer<A, T> accumulator() { return accumulator; } @Override public BinaryOperator<A> combiner() { return combiner; } @Override public Function<A, R> finisher() { return finisher; } @Override public Set<Characteristics> characteristics() { return characteristics; } @Override Predicate<A> finished() { return finished; } } static final class IntCollectorImpl<A, R> extends BaseCollector<Integer, A, R> implements IntCollector<A, R> { private final ObjIntConsumer<A> intAccumulator; IntCollectorImpl(Supplier<A> supplier, ObjIntConsumer<A> intAccumulator, BiConsumer<A, A> merger, Function<A, R> finisher, Set<Characteristics> characteristics) { super(supplier, merger, finisher, characteristics); this.intAccumulator = intAccumulator; } @Override public ObjIntConsumer<A> intAccumulator() { return intAccumulator; } } static final class LongCollectorImpl<A, R> extends BaseCollector<Long, A, R> implements LongCollector<A, R> { private final ObjLongConsumer<A> longAccumulator; LongCollectorImpl(Supplier<A> supplier, ObjLongConsumer<A> longAccumulator, BiConsumer<A, A> merger, Function<A, R> finisher, Set<Characteristics> characteristics) { super(supplier, merger, finisher, characteristics); this.longAccumulator = longAccumulator; } @Override public ObjLongConsumer<A> longAccumulator() { return longAccumulator; } } static final class DoubleCollectorImpl<A, R> extends BaseCollector<Double, A, R> implements DoubleCollector<A, R> { private final ObjDoubleConsumer<A> doubleAccumulator; DoubleCollectorImpl(Supplier<A> supplier, ObjDoubleConsumer<A> doubleAccumulator, BiConsumer<A, A> merger, Function<A, R> finisher, Set<Characteristics> characteristics) { super(supplier, merger, finisher, characteristics); this.doubleAccumulator = doubleAccumulator; } @Override public ObjDoubleConsumer<A> doubleAccumulator() { return doubleAccumulator; } } static class Box<A> implements Consumer<A> { A a; Box() { } Box(A obj) { this.a = obj; } @Override public void accept(A a) { this.a = a; } static <A, R> PartialCollector<Box<A>, R> partialCollector(Collector<?, A, R> c) { Supplier<A> supplier = c.supplier(); BinaryOperator<A> combiner = c.combiner(); Function<A, R> finisher = c.finisher(); return new PartialCollector<>(() -> new Box<>(supplier.get()), (box1, box2) -> box1.a = combiner.apply( box1.a, box2.a), box -> finisher.apply(box.a), NO_CHARACTERISTICS); } static <A> Optional<A> asOptional(Box<A> box) { return box == null ? Optional.empty() : Optional.of(box.a); } } static final class PairBox<A, B> extends Box<A> { B b; PairBox(A a, B b) { super(a); this.b = b; } static <T> PairBox<T, T> single(T a) { return new PairBox<>(a, a); } public void setB(B b) { this.b = b; } @Override public int hashCode() { return b == null ? 0 : b.hashCode(); } @Override public boolean equals(Object obj) { return obj != null && obj.getClass() == PairBox.class && Objects.equals(b, ((PairBox<?, ?>) obj).b); } } static final class ObjIntBox<A> extends Box<A> implements Entry<Integer, A> { int b; ObjIntBox(A a, int b) { super(a); this.b = b; } @Override public Integer getKey() { return b; } @Override public A getValue() { return a; } @Override public A setValue(A value) { throw new UnsupportedOperationException(); } @Override public int hashCode() { return Integer.hashCode(b) ^ (a == null ? 0 : a.hashCode()); } @Override public boolean equals(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry<?, ?> e = (Map.Entry<?, ?>) o; return getKey().equals(e.getKey()) && Objects.equals(a, e.getValue()); } @Override public String toString() { return b + "=" + a; } } static final class ObjLongBox<A> extends Box<A> implements Entry<A, Long> { long b; ObjLongBox(A a, long b) { super(a); this.b = b; } @Override public A getKey() { return a; } @Override public Long getValue() { return b; } @Override public Long setValue(Long value) { throw new UnsupportedOperationException(); } @Override public int hashCode() { return Long.hashCode(b) ^ (a == null ? 0 : a.hashCode()); } @Override public boolean equals(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry<?, ?> e = (Map.Entry<?, ?>) o; return getValue().equals(e.getValue()) && Objects.equals(a, e.getKey()); } @Override public String toString() { return a + "=" + b; } } static final class ObjDoubleBox<A> extends Box<A> { double b; ObjDoubleBox(A a, double b) { super(a); this.b = b; } } static final class PrimitiveBox { int i; double d; long l; boolean b; OptionalInt asInt() { return b ? OptionalInt.of(i) : OptionalInt.empty(); } OptionalLong asLong() { return b ? OptionalLong.of(l) : OptionalLong.empty(); } OptionalDouble asDouble() { return b ? OptionalDouble.of(d) : OptionalDouble.empty(); } static final BiConsumer<PrimitiveBox, PrimitiveBox> MAX_LONG = (box1, box2) -> { if (box2.b && (!box1.b || box1.l < box2.l)) { box1.from(box2); } }; static final BiConsumer<PrimitiveBox, PrimitiveBox> MIN_LONG = (box1, box2) -> { if (box2.b && (!box1.b || box1.l > box2.l)) { box1.from(box2); } }; static final BiConsumer<PrimitiveBox, PrimitiveBox> MAX_INT = (box1, box2) -> { if (box2.b && (!box1.b || box1.i < box2.i)) { box1.from(box2); } }; static final BiConsumer<PrimitiveBox, PrimitiveBox> MIN_INT = (box1, box2) -> { if (box2.b && (!box1.b || box1.i > box2.i)) { box1.from(box2); } }; static final BiConsumer<PrimitiveBox, PrimitiveBox> MAX_DOUBLE = (box1, box2) -> { if (box2.b && (!box1.b || Double.compare(box1.d, box2.d) < 0)) { box1.from(box2); } }; static final BiConsumer<PrimitiveBox, PrimitiveBox> MIN_DOUBLE = (box1, box2) -> { if (box2.b && (!box1.b || Double.compare(box1.d, box2.d) > 0)) { box1.from(box2); } }; public void from(PrimitiveBox box) { b = box.b; i = box.i; d = box.d; l = box.l; } } static final class AverageLong { long hi, lo, cnt; public void accept(long val) { cnt++; int cmp = Long.compareUnsigned(lo, lo += val); if (val > 0) { if (cmp > 0) hi++; } else if (cmp < 0) hi--; } public AverageLong combine(AverageLong other) { cnt += other.cnt; hi += other.hi; if (Long.compareUnsigned(lo, lo += other.lo) > 0) { hi++; } return this; } public OptionalDouble result() { if (cnt == 0) return OptionalDouble.empty(); if (hi == 0 && lo >= 0 || hi == -1 && lo < 0) { return OptionalDouble.of(((double) lo) / cnt); } return OptionalDouble.of(new BigDecimal(new BigInteger(java.nio.ByteBuffer.allocate(16).order( ByteOrder.BIG_ENDIAN).putLong(hi).putLong(lo).array())).divide(BigDecimal.valueOf(cnt), MathContext.DECIMAL64).doubleValue()); } } @SuppressWarnings("serial") static class CancelException extends Error { CancelException() { // Calling this constructor makes the Exception construction much // faster (like 0.3us vs 1.7us) super(null, null, false, false); } } static class ArrayCollection extends AbstractCollection<Object> { private final Object[] arr; ArrayCollection(Object[] arr) { this.arr = arr; } @Override public Iterator<Object> iterator() { return Arrays.asList(arr).iterator(); } @Override public int size() { return arr.length; } @Override public Object[] toArray() { // intentional contract violation here: // this way new ArrayList(new ArrayCollection(arr)) will not copy // array at all return arr; } } /** * A spliterator which may perform tail-stream optimization * * @param <T> */ interface TailSpliterator<T> extends Spliterator<T> { /** * Either advances by one element feeding it to consumer and returns * this or returns tail spliterator (this spliterator becomes invalid * and tail must be used instead) or returns null if traversal finished. * * @param action to feed the next element into * @return tail spliterator, this or null */ Spliterator<T> tryAdvanceOrTail(Consumer<? super T> action); /** * Traverses this spliterator and returns null if traversal is completed * or tail spliterator if it must be used for further traversal. * * @param action to feed the elements into * @return tail spliterator or null (never returns this) */ Spliterator<T> forEachOrTail(Consumer<? super T> action); static <T> Spliterator<T> tryAdvanceWithTail(Spliterator<T> target, Consumer<? super T> action) { while (true) { if (target instanceof TailSpliterator) { Spliterator<T> spltr = ((TailSpliterator<T>) target).tryAdvanceOrTail(action); if (spltr == null || spltr == target) return spltr; target = spltr; } else { return target.tryAdvance(action) ? target : null; } } } static <T> void forEachWithTail(Spliterator<T> target, Consumer<? super T> action) { while (true) { if (target instanceof TailSpliterator) { Spliterator<T> spltr = ((TailSpliterator<T>) target).forEachOrTail(action); if (spltr == null) break; target = spltr; } else { target.forEachRemaining(action); break; } } } } static abstract class CloneableSpliterator<T, S extends CloneableSpliterator<T, ?>> implements Spliterator<T>, Cloneable { @SuppressWarnings("unchecked") S doClone() { try { return (S) this.clone(); } catch (CloneNotSupportedException e) { throw new InternalError(); } } } static <T> T copy(T src, T dest, int size) { System.arraycopy(src, 0, dest, 0, size); return dest; } static ObjIntConsumer<StringBuilder> joinAccumulatorInt(CharSequence delimiter) { return (sb, i) -> (sb.length() > 0 ? sb.append(delimiter) : sb).append(i); } static ObjLongConsumer<StringBuilder> joinAccumulatorLong(CharSequence delimiter) { return (sb, i) -> (sb.length() > 0 ? sb.append(delimiter) : sb).append(i); } static ObjDoubleConsumer<StringBuilder> joinAccumulatorDouble(CharSequence delimiter) { return (sb, i) -> (sb.length() > 0 ? sb.append(delimiter) : sb).append(i); } static <T> BinaryOperator<T> selectFirst() { return (u, v) -> u; } static int checkLength(int a, int b) { if (a != b) throw new IllegalArgumentException("Length differs: " + a + " != " + b); return a; } static void rangeCheck(int arrayLength, int startInclusive, int endExclusive) { if (startInclusive > endExclusive) { throw new ArrayIndexOutOfBoundsException("startInclusive(" + startInclusive + ") > endExclusive(" + endExclusive + ")"); } if (startInclusive < 0) { throw new ArrayIndexOutOfBoundsException(startInclusive); } if (endExclusive > arrayLength) { throw new ArrayIndexOutOfBoundsException(endExclusive); } } @SuppressWarnings("unchecked") static <A> Predicate<A> finished(Collector<?, A, ?> collector) { if (collector instanceof CancellableCollector) return ((CancellableCollector<?, A, ?>) collector).finished(); return null; } @SuppressWarnings("unchecked") static <T> T none() { return (T) NONE; } static boolean mustCloseStream(BaseStream<?, ?> target) { try { if (SOURCE_STAGE != null && SOURCE_CLOSE_ACTION != null && SOURCE_CLOSE_ACTION.get(SOURCE_STAGE.get(target)) == null) return false; } catch (IllegalArgumentException | IllegalAccessException e) { // ignore } return true; } static <T> int drainTo(T[] array, Spliterator<T> spliterator) { Box<T> box = new Box<>(); int index = 0; while (index < array.length && spliterator.tryAdvance(box)) { array[index++] = box.a; } return index; } }