All Downloads are FREE. Search and download functionalities are using the official Maven repository.

java8.util.stream.StreamSpliterators Maven / Gradle / Ivy

Go to download

streamsupport is a backport of the Java 8 java.util.function (functional interfaces) and java.util.stream (streams) API for Java 6 / 7 and Android developers

The newest version!
/*
 * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package java8.util.stream;

import java.util.Comparator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;

import java8.util.Objects;
import java8.util.Spliterators;
import java8.util.concurrent.ForkJoinPool;
import java8.util.function.BooleanSupplier;
import java8.util.function.Consumer;
import java8.util.function.DoubleConsumer;
import java8.util.function.DoubleSupplier;
import java8.util.function.IntConsumer;
import java8.util.function.IntSupplier;
import java8.util.function.LongConsumer;
import java8.util.function.LongSupplier;
import java8.util.function.Supplier;
import java8.util.Spliterator;

/**
 * Spliterator implementations for wrapping and delegating spliterators, used
 * in the implementation of the {@link Stream#spliterator()} method.
 *
 * @since 1.8
 */
class StreamSpliterators {

    /**
     * Abstract wrapping spliterator that binds to the spliterator of a
     * pipeline helper on first operation.
     *
     * 

This spliterator is not late-binding and will bind to the source * spliterator when first operated on. * *

A wrapping spliterator produced from a sequential stream * cannot be split if there are stateful operations present. */ private abstract static class AbstractWrappingSpliterator implements Spliterator { // @@@ Detect if stateful operations are present or not // If not then can split otherwise cannot /** * True if this spliterator supports splitting */ final boolean isParallel; final PipelineHelper ph; /** * Supplier for the source spliterator. Client provides either a * spliterator or a supplier. */ private Supplier> spliteratorSupplier; /** * Source spliterator. Either provided from client or obtained from * supplier. */ Spliterator spliterator; /** * Sink chain for the downstream stages of the pipeline, ultimately * leading to the buffer. Used during partial traversal. */ Sink bufferSink; /** * A function that advances one element of the spliterator, pushing * it to bufferSink. Returns whether any elements were processed. * Used during partial traversal. */ BooleanSupplier pusher; /** Next element to consume from the buffer, used during partial traversal */ long nextToConsume; /** Buffer into which elements are pushed. Used during partial traversal. */ T_BUFFER buffer; /** * True if full traversal has occurred (with possible cancellation). * If doing a partial traversal, there may be still elements in buffer. */ boolean finished; /** * Construct an AbstractWrappingSpliterator from a * {@code Supplier}. */ AbstractWrappingSpliterator(PipelineHelper ph, Supplier> spliteratorSupplier, boolean parallel) { this.ph = ph; this.spliteratorSupplier = spliteratorSupplier; this.spliterator = null; this.isParallel = parallel; } /** * Construct an AbstractWrappingSpliterator from a * {@code Spliterator}. */ AbstractWrappingSpliterator(PipelineHelper ph, Spliterator spliterator, boolean parallel) { this.ph = ph; this.spliteratorSupplier = null; this.spliterator = spliterator; this.isParallel = parallel; } @Override public boolean hasCharacteristics(int characteristics) { return Spliterators.hasCharacteristics(this, characteristics); } /** * Called before advancing to set up spliterator, if needed. */ final void init() { if (spliterator == null) { spliterator = spliteratorSupplier.get(); spliteratorSupplier = null; } } /** * Get an element from the source, pushing it into the sink chain, * setting up the buffer if needed * @return whether there are elements to consume from the buffer */ final boolean doAdvance() { if (buffer == null) { if (finished) return false; init(); initPartialTraversalState(); nextToConsume = 0; bufferSink.begin(spliterator.getExactSizeIfKnown()); return fillBuffer(); } else { ++nextToConsume; boolean hasNext = nextToConsume < buffer.count(); if (!hasNext) { nextToConsume = 0; buffer.clear(); hasNext = fillBuffer(); } return hasNext; } } /** * Invokes the shape-specific constructor with the provided arguments * and returns the result. */ abstract AbstractWrappingSpliterator wrap(Spliterator s); /** * Initializes buffer, sink chain, and pusher for a shape-specific * implementation. */ abstract void initPartialTraversalState(); @Override public Spliterator trySplit() { if (isParallel && buffer == null && !finished) { init(); Spliterator split = spliterator.trySplit(); return (split == null) ? null : wrap(split); } else return null; } /** * If the buffer is empty, push elements into the sink chain until * the source is empty or cancellation is requested. * @return whether there are elements to consume from the buffer */ private boolean fillBuffer() { while (buffer.count() == 0) { if (bufferSink.cancellationRequested() || !pusher.getAsBoolean()) { if (finished) return false; else { bufferSink.end(); // might trigger more elements finished = true; } } } return true; } @Override public final long estimateSize() { long exactSizeIfKnown = getExactSizeIfKnown(); // Use the estimate of the wrapped spliterator // Note this may not be accurate if there are filter/flatMap // operations filtering or adding elements to the stream return exactSizeIfKnown == -1L ? spliterator.estimateSize() : exactSizeIfKnown; } @Override public final long getExactSizeIfKnown() { init(); return ph.exactOutputSizeIfKnown(spliterator); } @Override public final int characteristics() { init(); // Get the characteristics from the pipeline int c = StreamOpFlag.toCharacteristics(StreamOpFlag.toStreamFlags(ph.getStreamAndOpFlags())); // Mask off the size and uniform characteristics and replace with // those of the spliterator // Note that a non-uniform spliterator can change from something // with an exact size to an estimate for a sub-split, for example // with HashSet where the size is known at the top level spliterator // but for sub-splits only an estimate is known if ((c & Spliterator.SIZED) != 0) { c &= ~(Spliterator.SIZED | Spliterator.SUBSIZED); c |= (spliterator.characteristics() & (Spliterator.SIZED | Spliterator.SUBSIZED)); } return c; } @Override public Comparator getComparator() { if (!hasCharacteristics(SORTED)) throw new IllegalStateException(); return null; } @Override public final String toString() { return String.format("%s[%s]", getClass().getName(), spliterator); } } static final class WrappingSpliterator extends AbstractWrappingSpliterator> { WrappingSpliterator(PipelineHelper ph, Supplier> supplier, boolean parallel) { super(ph, supplier, parallel); } WrappingSpliterator(PipelineHelper ph, Spliterator spliterator, boolean parallel) { super(ph, spliterator, parallel); } @Override WrappingSpliterator wrap(Spliterator s) { return new WrappingSpliterator<>(ph, s, isParallel); } @Override void initPartialTraversalState() { SpinedBuffer b = new SpinedBuffer<>(); buffer = b; bufferSink = ph.wrapSink(b::accept); pusher = () -> spliterator.tryAdvance(bufferSink); } @Override public boolean tryAdvance(Consumer consumer) { Objects.requireNonNull(consumer); boolean hasNext = doAdvance(); if (hasNext) consumer.accept(buffer.get(nextToConsume)); return hasNext; } @Override public void forEachRemaining(Consumer consumer) { if (buffer == null && !finished) { Objects.requireNonNull(consumer); init(); ph.wrapAndCopyInto((Consumer) consumer::accept, spliterator); finished = true; } else { do { } while (tryAdvance(consumer)); } } } static final class IntWrappingSpliterator extends AbstractWrappingSpliterator implements Spliterator.OfInt { IntWrappingSpliterator(PipelineHelper ph, Supplier> supplier, boolean parallel) { super(ph, supplier, parallel); } IntWrappingSpliterator(PipelineHelper ph, Spliterator spliterator, boolean parallel) { super(ph, spliterator, parallel); } @Override AbstractWrappingSpliterator wrap(Spliterator s) { return new IntWrappingSpliterator<>(ph, s, isParallel); } @Override void initPartialTraversalState() { SpinedBuffer.OfInt b = new SpinedBuffer.OfInt(); buffer = b; Sink.OfInt trampoline = new Sink.OfInt() { @Override public void end() { } @Override public boolean cancellationRequested() { return false; } @Override public void begin(long size) { } @Override public void accept(double value) { SinkDefaults.reject(); } @Override public void accept(long value) { SinkDefaults.reject(); } @Override public void accept(Integer i) { accept(i.intValue()); } @Override public void accept(int value) { b.accept(value); } }; bufferSink = ph.wrapSink(trampoline); pusher = () -> spliterator.tryAdvance(bufferSink); } @Override public Spliterator.OfInt trySplit() { return (Spliterator.OfInt) super.trySplit(); } @Override public boolean tryAdvance(IntConsumer consumer) { Objects.requireNonNull(consumer); boolean hasNext = doAdvance(); if (hasNext) consumer.accept(buffer.get(nextToConsume)); return hasNext; } @Override public boolean tryAdvance(Consumer action) { return Spliterators.OfInt.tryAdvance(this, action); } @Override public void forEachRemaining(IntConsumer consumer) { if (buffer == null && !finished) { Objects.requireNonNull(consumer); init(); Sink.OfInt trampoline = new Sink.OfInt() { @Override public void end() { } @Override public boolean cancellationRequested() { return false; } @Override public void begin(long size) { } @Override public void accept(double value) { SinkDefaults.reject(); } @Override public void accept(long value) { SinkDefaults.reject(); } @Override public void accept(Integer i) { accept(i.intValue()); } @Override public void accept(int value) { consumer.accept(value); } }; ph.wrapAndCopyInto(trampoline, spliterator); finished = true; } else { do { } while (tryAdvance(consumer)); } } @Override public void forEachRemaining(Consumer action) { Spliterators.OfInt.forEachRemaining(this, action); } } static final class LongWrappingSpliterator extends AbstractWrappingSpliterator implements Spliterator.OfLong { LongWrappingSpliterator(PipelineHelper ph, Supplier> supplier, boolean parallel) { super(ph, supplier, parallel); } LongWrappingSpliterator(PipelineHelper ph, Spliterator spliterator, boolean parallel) { super(ph, spliterator, parallel); } @Override AbstractWrappingSpliterator wrap(Spliterator s) { return new LongWrappingSpliterator<>(ph, s, isParallel); } @Override void initPartialTraversalState() { SpinedBuffer.OfLong b = new SpinedBuffer.OfLong(); buffer = b; Sink.OfLong trampoline = new Sink.OfLong() { @Override public void end() { } @Override public boolean cancellationRequested() { return false; } @Override public void begin(long size) { } @Override public void accept(double value) { SinkDefaults.reject(); } @Override public void accept(int value) { SinkDefaults.reject(); } @Override public void accept(Long i) { accept(i.longValue()); } @Override public void accept(long value) { b.accept(value); } }; bufferSink = ph.wrapSink(trampoline); pusher = () -> spliterator.tryAdvance(bufferSink); } @Override public Spliterator.OfLong trySplit() { return (Spliterator.OfLong) super.trySplit(); } @Override public boolean tryAdvance(LongConsumer consumer) { Objects.requireNonNull(consumer); boolean hasNext = doAdvance(); if (hasNext) consumer.accept(buffer.get(nextToConsume)); return hasNext; } @Override public boolean tryAdvance(Consumer action) { return Spliterators.OfLong.tryAdvance(this, action); } @Override public void forEachRemaining(LongConsumer consumer) { if (buffer == null && !finished) { Objects.requireNonNull(consumer); init(); Sink.OfLong trampoline = new Sink.OfLong() { @Override public void end() { } @Override public boolean cancellationRequested() { return false; } @Override public void begin(long size) { } @Override public void accept(double value) { SinkDefaults.reject(); } @Override public void accept(int value) { SinkDefaults.reject(); } @Override public void accept(Long i) { accept(i.longValue()); } @Override public void accept(long value) { consumer.accept(value); } }; ph.wrapAndCopyInto(trampoline, spliterator); finished = true; } else { do { } while (tryAdvance(consumer)); } } @Override public void forEachRemaining(Consumer action) { Spliterators.OfLong.forEachRemaining(this, action); } } static final class DoubleWrappingSpliterator extends AbstractWrappingSpliterator implements Spliterator.OfDouble { DoubleWrappingSpliterator(PipelineHelper ph, Supplier> supplier, boolean parallel) { super(ph, supplier, parallel); } DoubleWrappingSpliterator(PipelineHelper ph, Spliterator spliterator, boolean parallel) { super(ph, spliterator, parallel); } @Override AbstractWrappingSpliterator wrap(Spliterator s) { return new DoubleWrappingSpliterator<>(ph, s, isParallel); } @Override void initPartialTraversalState() { SpinedBuffer.OfDouble b = new SpinedBuffer.OfDouble(); buffer = b; Sink.OfDouble trampoline = new Sink.OfDouble() { @Override public void begin(long size) { } @Override public void end() { } @Override public boolean cancellationRequested() { return false; } @Override public void accept(int value) { SinkDefaults.reject(); } @Override public void accept(long value) { SinkDefaults.reject(); } @Override public void accept(double value) { b.accept(value); } @Override public void accept(Double i) { accept(i.doubleValue()); } }; bufferSink = ph.wrapSink(trampoline); pusher = () -> spliterator.tryAdvance(bufferSink); } @Override public Spliterator.OfDouble trySplit() { return (Spliterator.OfDouble) super.trySplit(); } @Override public boolean tryAdvance(DoubleConsumer consumer) { Objects.requireNonNull(consumer); boolean hasNext = doAdvance(); if (hasNext) consumer.accept(buffer.get(nextToConsume)); return hasNext; } @Override public boolean tryAdvance(Consumer action) { return Spliterators.OfDouble.tryAdvance(this, action); } @Override public void forEachRemaining(DoubleConsumer consumer) { if (buffer == null && !finished) { Objects.requireNonNull(consumer); init(); Sink.OfDouble trampoline = new Sink.OfDouble() { @Override public void begin(long size) { } @Override public void end() { } @Override public boolean cancellationRequested() { return false; } @Override public void accept(int value) { SinkDefaults.reject(); } @Override public void accept(long value) { SinkDefaults.reject(); } @Override public void accept(double value) { consumer.accept(value); } @Override public void accept(Double i) { accept(i.doubleValue()); } }; ph.wrapAndCopyInto(trampoline, spliterator); finished = true; } else { do { } while (tryAdvance(consumer)); } } @Override public void forEachRemaining(Consumer action) { Spliterators.OfDouble.forEachRemaining(this, action); } } /** * Spliterator implementation that delegates to an underlying spliterator, * acquiring the spliterator from a {@code Supplier} on the * first call to any spliterator method. * @param */ static class DelegatingSpliterator> implements Spliterator { private final Supplier supplier; private T_SPLITR s; DelegatingSpliterator(Supplier supplier) { this.supplier = supplier; } T_SPLITR get() { if (s == null) { s = supplier.get(); } return s; } @Override public boolean hasCharacteristics(int characteristics) { return Spliterators.hasCharacteristics(this, characteristics); } @Override @SuppressWarnings("unchecked") public T_SPLITR trySplit() { return (T_SPLITR) get().trySplit(); } @Override public boolean tryAdvance(Consumer consumer) { return get().tryAdvance(consumer); } @Override public void forEachRemaining(Consumer consumer) { get().forEachRemaining(consumer); } @Override public long estimateSize() { return get().estimateSize(); } @Override public int characteristics() { return get().characteristics(); } @Override public Comparator getComparator() { return get().getComparator(); } @Override public long getExactSizeIfKnown() { return get().getExactSizeIfKnown(); } @Override public String toString() { return getClass().getName() + "[" + get() + "]"; } static class OfPrimitive> extends DelegatingSpliterator implements Spliterator.OfPrimitive { OfPrimitive(Supplier supplier) { super(supplier); } @Override public boolean tryAdvance(T_CONS consumer) { return get().tryAdvance(consumer); } @Override public void forEachRemaining(T_CONS consumer) { get().forEachRemaining(consumer); } } static final class OfInt extends OfPrimitive implements Spliterator.OfInt { OfInt(Supplier supplier) { super(supplier); } } static final class OfLong extends OfPrimitive implements Spliterator.OfLong { OfLong(Supplier supplier) { super(supplier); } } static final class OfDouble extends OfPrimitive implements Spliterator.OfDouble { OfDouble(Supplier supplier) { super(supplier); } } } /** * A slice Spliterator from a source Spliterator that reports * {@code SUBSIZED}. * */ abstract static class SliceSpliterator> { // The start index of the slice final long sliceOrigin; // One past the last index of the slice final long sliceFence; // The spliterator to slice T_SPLITR s; // current (absolute) index, modified on advance/split long index; // one past last (absolute) index or sliceFence, which ever is smaller long fence; SliceSpliterator(T_SPLITR s, long sliceOrigin, long sliceFence, long origin, long fence) { this.s = s; this.sliceOrigin = sliceOrigin; this.sliceFence = sliceFence; this.index = origin; this.fence = fence; } protected abstract T_SPLITR makeSpliterator(T_SPLITR s, long sliceOrigin, long sliceFence, long origin, long fence); public T_SPLITR trySplit() { if (sliceOrigin >= fence) return null; if (index >= fence) return null; // Keep splitting until the left and right splits intersect with the slice // thereby ensuring the size estimate decreases. // This also avoids creating empty spliterators which can result in // existing and additionally created F/J tasks that perform // redundant work on no elements. while (true) { @SuppressWarnings("unchecked") T_SPLITR leftSplit = (T_SPLITR) s.trySplit(); if (leftSplit == null) return null; long leftSplitFenceUnbounded = index + leftSplit.estimateSize(); long leftSplitFence = Math.min(leftSplitFenceUnbounded, sliceFence); if (sliceOrigin >= leftSplitFence) { // The left split does not intersect with, and is to the left of, the slice // The right split does intersect // Discard the left split and split further with the right split index = leftSplitFence; } else if (leftSplitFence >= sliceFence) { // The right split does not intersect with, and is to the right of, the slice // The left split does intersect // Discard the right split and split further with the left split s = leftSplit; fence = leftSplitFence; } else if (index >= sliceOrigin && leftSplitFenceUnbounded <= sliceFence) { // The left split is contained within the slice, return the underlying left split // Right split is contained within or intersects with the slice index = leftSplitFence; return leftSplit; } else { // The left split intersects with the slice // Right split is contained within or intersects with the slice return makeSpliterator(leftSplit, sliceOrigin, sliceFence, index, index = leftSplitFence); } } } public long estimateSize() { return (sliceOrigin < fence) ? fence - Math.max(sliceOrigin, index) : 0; } public int characteristics() { return s.characteristics(); } static final class OfRef extends SliceSpliterator> implements Spliterator { OfRef(Spliterator s, long sliceOrigin, long sliceFence) { this(s, sliceOrigin, sliceFence, 0, Math.min(s.estimateSize(), sliceFence)); } private OfRef(Spliterator s, long sliceOrigin, long sliceFence, long origin, long fence) { super(s, sliceOrigin, sliceFence, origin, fence); } @Override protected Spliterator makeSpliterator(Spliterator s, long sliceOrigin, long sliceFence, long origin, long fence) { return new OfRef<>(s, sliceOrigin, sliceFence, origin, fence); } @Override public boolean tryAdvance(Consumer action) { Objects.requireNonNull(action); if (sliceOrigin >= fence) return false; while (sliceOrigin > index) { s.tryAdvance(e -> {}); index++; } if (index >= fence) return false; index++; return s.tryAdvance(action); } @Override public void forEachRemaining(Consumer action) { Objects.requireNonNull(action); if (sliceOrigin >= fence) return; if (index >= fence) return; if (index >= sliceOrigin && (index + s.estimateSize()) <= sliceFence) { // The spliterator is contained within the slice s.forEachRemaining(action); index = fence; } else { // The spliterator intersects with the slice while (sliceOrigin > index) { s.tryAdvance(e -> {}); index++; } // Traverse elements up to the fence for (;index < fence; index++) { s.tryAdvance(action); } } } @Override public long getExactSizeIfKnown() { return Spliterators.getExactSizeIfKnown(this); } @Override public boolean hasCharacteristics(int characteristics) { return Spliterators.hasCharacteristics(this, characteristics); } @Override public Comparator getComparator() { return Spliterators.getComparator(this); } } static abstract class OfPrimitive, T_CONS> extends SliceSpliterator implements Spliterator.OfPrimitive { OfPrimitive(T_SPLITR s, long sliceOrigin, long sliceFence) { this(s, sliceOrigin, sliceFence, 0, Math.min(s.estimateSize(), sliceFence)); } OfPrimitive(T_SPLITR s, long sliceOrigin, long sliceFence, long origin, long fence) { super(s, sliceOrigin, sliceFence, origin, fence); } @Override public boolean tryAdvance(T_CONS action) { Objects.requireNonNull(action); if (sliceOrigin >= fence) return false; while (sliceOrigin > index) { s.tryAdvance(emptyConsumer()); index++; } if (index >= fence) return false; index++; return s.tryAdvance(action); } @Override public void forEachRemaining(T_CONS action) { Objects.requireNonNull(action); if (sliceOrigin >= fence) return; if (index >= fence) return; if (index >= sliceOrigin && (index + s.estimateSize()) <= sliceFence) { // The spliterator is contained within the slice s.forEachRemaining(action); index = fence; } else { // The spliterator intersects with the slice while (sliceOrigin > index) { s.tryAdvance(emptyConsumer()); index++; } // Traverse elements up to the fence for (;index < fence; index++) { s.tryAdvance(action); } } } protected abstract T_CONS emptyConsumer(); } static final class OfInt extends OfPrimitive implements Spliterator.OfInt { OfInt(Spliterator.OfInt s, long sliceOrigin, long sliceFence) { super(s, sliceOrigin, sliceFence); } OfInt(Spliterator.OfInt s, long sliceOrigin, long sliceFence, long origin, long fence) { super(s, sliceOrigin, sliceFence, origin, fence); } @Override public long getExactSizeIfKnown() { return Spliterators.getExactSizeIfKnown(this); } @Override public boolean hasCharacteristics(int characteristics) { return Spliterators.hasCharacteristics(this, characteristics); } @Override public Comparator getComparator() { return Spliterators.getComparator(this); } @Override public boolean tryAdvance(Consumer action) { return Spliterators.OfInt.tryAdvance(this, action); } @Override public void forEachRemaining(Consumer action) { Spliterators.OfInt.forEachRemaining(this, action); } @Override protected Spliterator.OfInt makeSpliterator(Spliterator.OfInt s, long sliceOrigin, long sliceFence, long origin, long fence) { return new SliceSpliterator.OfInt(s, sliceOrigin, sliceFence, origin, fence); } @Override protected IntConsumer emptyConsumer() { return e -> {}; } } static final class OfLong extends OfPrimitive implements Spliterator.OfLong { OfLong(Spliterator.OfLong s, long sliceOrigin, long sliceFence) { super(s, sliceOrigin, sliceFence); } OfLong(Spliterator.OfLong s, long sliceOrigin, long sliceFence, long origin, long fence) { super(s, sliceOrigin, sliceFence, origin, fence); } @Override public long getExactSizeIfKnown() { return Spliterators.getExactSizeIfKnown(this); } @Override public boolean hasCharacteristics(int characteristics) { return Spliterators.hasCharacteristics(this, characteristics); } @Override public Comparator getComparator() { return Spliterators.getComparator(this); } @Override public boolean tryAdvance(Consumer action) { return Spliterators.OfLong.tryAdvance(this, action); } @Override public void forEachRemaining(Consumer action) { Spliterators.OfLong.forEachRemaining(this, action); } @Override protected Spliterator.OfLong makeSpliterator(Spliterator.OfLong s, long sliceOrigin, long sliceFence, long origin, long fence) { return new SliceSpliterator.OfLong(s, sliceOrigin, sliceFence, origin, fence); } @Override protected LongConsumer emptyConsumer() { return e -> {}; } } static final class OfDouble extends OfPrimitive implements Spliterator.OfDouble { OfDouble(Spliterator.OfDouble s, long sliceOrigin, long sliceFence) { super(s, sliceOrigin, sliceFence); } OfDouble(Spliterator.OfDouble s, long sliceOrigin, long sliceFence, long origin, long fence) { super(s, sliceOrigin, sliceFence, origin, fence); } @Override public long getExactSizeIfKnown() { return Spliterators.getExactSizeIfKnown(this); } @Override public boolean hasCharacteristics(int characteristics) { return Spliterators.hasCharacteristics(this, characteristics); } @Override public Comparator getComparator() { return Spliterators.getComparator(this); } @Override public boolean tryAdvance(Consumer action) { return Spliterators.OfDouble.tryAdvance(this, action); } @Override public void forEachRemaining(Consumer action) { Spliterators.OfDouble.forEachRemaining(this, action); } @Override protected Spliterator.OfDouble makeSpliterator(Spliterator.OfDouble s, long sliceOrigin, long sliceFence, long origin, long fence) { return new SliceSpliterator.OfDouble(s, sliceOrigin, sliceFence, origin, fence); } @Override protected DoubleConsumer emptyConsumer() { return e -> {}; } } } /** * A slice Spliterator that does not preserve order, if any, of a source * Spliterator. * * Note: The source spliterator may report {@code ORDERED} since that * spliterator be the result of a previous pipeline stage that was * collected to a {@code Node}. It is the order of the pipeline stage * that governs whether this slice spliterator is to be used or not. */ abstract static class UnorderedSliceSpliterator> { static final int CHUNK_SIZE = 1 << 7; // The spliterator to slice protected final T_SPLITR s; protected final boolean unlimited; protected final int chunkSize; private final long skipThreshold; private final AtomicLong permits; UnorderedSliceSpliterator(T_SPLITR s, long skip, long limit) { this.s = s; this.unlimited = limit < 0; this.skipThreshold = limit >= 0 ? limit : 0; this.chunkSize = limit >= 0 ? (int) Math.min(CHUNK_SIZE, ((skip + limit) / AbstractTask.getLeafTarget()) + 1) : CHUNK_SIZE; this.permits = new AtomicLong(limit >= 0 ? skip + limit : skip); } UnorderedSliceSpliterator(T_SPLITR s, UnorderedSliceSpliterator parent) { this.s = s; this.unlimited = parent.unlimited; this.permits = parent.permits; this.skipThreshold = parent.skipThreshold; this.chunkSize = parent.chunkSize; } /** * Acquire permission to skip or process elements. The caller must * first acquire the elements, then consult this method for guidance * as to what to do with the data. * *

We use an {@code AtomicLong} to atomically maintain a counter, * which is initialized as skip+limit if we are limiting, or skip only * if we are not limiting. The user should consult the method * {@code checkPermits()} before acquiring data elements. * * @param numElements the number of elements the caller has in hand * @return the number of elements that should be processed; any * remaining elements should be discarded. */ protected final long acquirePermits(long numElements) { long remainingPermits; long grabbing; // permits never increase, and don't decrease below zero do { remainingPermits = permits.get(); if (remainingPermits == 0) return unlimited ? numElements : 0; grabbing = Math.min(remainingPermits, numElements); } while (grabbing > 0 && !permits.compareAndSet(remainingPermits, remainingPermits - grabbing)); if (unlimited) return Math.max(numElements - grabbing, 0); else if (remainingPermits > skipThreshold) return Math.max(grabbing - (remainingPermits - skipThreshold), 0); else return grabbing; } enum PermitStatus { NO_MORE, MAYBE_MORE, UNLIMITED } /** Call to check if permits might be available before acquiring data */ protected final PermitStatus permitStatus() { if (permits.get() > 0) return PermitStatus.MAYBE_MORE; else return unlimited ? PermitStatus.UNLIMITED : PermitStatus.NO_MORE; } public final T_SPLITR trySplit() { // Stop splitting when there are no more limit permits if (permits.get() == 0) return null; @SuppressWarnings("unchecked") T_SPLITR split = (T_SPLITR) s.trySplit(); return split == null ? null : makeSpliterator(split); } protected abstract T_SPLITR makeSpliterator(T_SPLITR s); public final long estimateSize() { return s.estimateSize(); } public final int characteristics() { return s.characteristics() & ~(Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.ORDERED); } static final class OfRef extends UnorderedSliceSpliterator> implements Spliterator, Consumer { T tmpSlot; OfRef(Spliterator s, long skip, long limit) { super(s, skip, limit); } OfRef(Spliterator s, OfRef parent) { super(s, parent); } @Override public final void accept(T t) { tmpSlot = t; } @Override public boolean tryAdvance(Consumer action) { Objects.requireNonNull(action); while (permitStatus() != PermitStatus.NO_MORE) { if (!s.tryAdvance(this)) return false; else if (acquirePermits(1) == 1) { action.accept(tmpSlot); tmpSlot = null; return true; } } return false; } @Override public void forEachRemaining(Consumer action) { Objects.requireNonNull(action); ArrayBuffer.OfRef sb = null; PermitStatus permitStatus; while ((permitStatus = permitStatus()) != PermitStatus.NO_MORE) { if (permitStatus == PermitStatus.MAYBE_MORE) { // Optimistically traverse elements up to a threshold of chunkSize if (sb == null) sb = new ArrayBuffer.OfRef<>(chunkSize); else sb.reset(); long permitsRequested = 0; do { } while (s.tryAdvance(sb) && ++permitsRequested < chunkSize); if (permitsRequested == 0) return; sb.forEach(action, acquirePermits(permitsRequested)); } else { // Must be UNLIMITED; let 'er rip s.forEachRemaining(action); return; } } } @Override public long getExactSizeIfKnown() { return Spliterators.getExactSizeIfKnown(this); } @Override public boolean hasCharacteristics(int characteristics) { return Spliterators.hasCharacteristics(this, characteristics); } @Override public Comparator getComparator() { return Spliterators.getComparator(this); } @Override protected Spliterator makeSpliterator(Spliterator s) { return new UnorderedSliceSpliterator.OfRef<>(s, this); } } /** * Concrete sub-types must also be an instance of type {@code T_CONS}. * * @param the type of the spined buffer. Must also be a type of * {@code T_CONS}. */ abstract static class OfPrimitive< T, T_CONS, T_BUFF extends ArrayBuffer.OfPrimitive, T_SPLITR extends Spliterator.OfPrimitive> extends UnorderedSliceSpliterator implements Spliterator.OfPrimitive { OfPrimitive(T_SPLITR s, long skip, long limit) { super(s, skip, limit); } OfPrimitive(T_SPLITR s, UnorderedSliceSpliterator.OfPrimitive parent) { super(s, parent); } @Override public boolean tryAdvance(T_CONS action) { Objects.requireNonNull(action); @SuppressWarnings("unchecked") T_CONS consumer = (T_CONS) this; while (permitStatus() != PermitStatus.NO_MORE) { if (!s.tryAdvance(consumer)) return false; else if (acquirePermits(1) == 1) { acceptConsumed(action); return true; } } return false; } protected abstract void acceptConsumed(T_CONS action); @Override public void forEachRemaining(T_CONS action) { Objects.requireNonNull(action); T_BUFF sb = null; PermitStatus permitStatus; while ((permitStatus = permitStatus()) != PermitStatus.NO_MORE) { if (permitStatus == PermitStatus.MAYBE_MORE) { // Optimistically traverse elements up to a threshold of chunkSize if (sb == null) sb = bufferCreate(chunkSize); else sb.reset(); @SuppressWarnings("unchecked") T_CONS sbc = (T_CONS) sb; long permitsRequested = 0; do { } while (s.tryAdvance(sbc) && ++permitsRequested < chunkSize); if (permitsRequested == 0) return; sb.forEach(action, acquirePermits(permitsRequested)); } else { // Must be UNLIMITED; let 'er rip s.forEachRemaining(action); return; } } } protected abstract T_BUFF bufferCreate(int initialCapacity); } static final class OfInt extends OfPrimitive implements Spliterator.OfInt, IntConsumer { int tmpValue; OfInt(Spliterator.OfInt s, long skip, long limit) { super(s, skip, limit); } OfInt(Spliterator.OfInt s, UnorderedSliceSpliterator.OfInt parent) { super(s, parent); } @Override public void accept(int value) { tmpValue = value; } @Override public long getExactSizeIfKnown() { return Spliterators.getExactSizeIfKnown(this); } @Override public boolean hasCharacteristics(int characteristics) { return Spliterators.hasCharacteristics(this, characteristics); } @Override public Comparator getComparator() { return Spliterators.getComparator(this); } @Override public boolean tryAdvance(Consumer action) { return Spliterators.OfInt.tryAdvance(this, action); } @Override public void forEachRemaining(Consumer action) { Spliterators.OfInt.forEachRemaining(this, action); } @Override protected void acceptConsumed(IntConsumer action) { action.accept(tmpValue); } @Override protected ArrayBuffer.OfInt bufferCreate(int initialCapacity) { return new ArrayBuffer.OfInt(initialCapacity); } @Override protected Spliterator.OfInt makeSpliterator(Spliterator.OfInt s) { return new UnorderedSliceSpliterator.OfInt(s, this); } } static final class OfLong extends OfPrimitive implements Spliterator.OfLong, LongConsumer { long tmpValue; OfLong(Spliterator.OfLong s, long skip, long limit) { super(s, skip, limit); } OfLong(Spliterator.OfLong s, UnorderedSliceSpliterator.OfLong parent) { super(s, parent); } @Override public void accept(long value) { tmpValue = value; } @Override public long getExactSizeIfKnown() { return Spliterators.getExactSizeIfKnown(this); } @Override public boolean hasCharacteristics(int characteristics) { return Spliterators.hasCharacteristics(this, characteristics); } @Override public Comparator getComparator() { return Spliterators.getComparator(this); } @Override public boolean tryAdvance(Consumer action) { return Spliterators.OfLong.tryAdvance(this, action); } @Override public void forEachRemaining(Consumer action) { Spliterators.OfLong.forEachRemaining(this, action); } @Override protected void acceptConsumed(LongConsumer action) { action.accept(tmpValue); } @Override protected ArrayBuffer.OfLong bufferCreate(int initialCapacity) { return new ArrayBuffer.OfLong(initialCapacity); } @Override protected Spliterator.OfLong makeSpliterator(Spliterator.OfLong s) { return new UnorderedSliceSpliterator.OfLong(s, this); } } static final class OfDouble extends OfPrimitive implements Spliterator.OfDouble, DoubleConsumer { double tmpValue; OfDouble(Spliterator.OfDouble s, long skip, long limit) { super(s, skip, limit); } OfDouble(Spliterator.OfDouble s, UnorderedSliceSpliterator.OfDouble parent) { super(s, parent); } @Override public void accept(double value) { tmpValue = value; } @Override public long getExactSizeIfKnown() { return Spliterators.getExactSizeIfKnown(this); } @Override public boolean hasCharacteristics(int characteristics) { return Spliterators.hasCharacteristics(this, characteristics); } @Override public Comparator getComparator() { return Spliterators.getComparator(this); } @Override public boolean tryAdvance(Consumer action) { return Spliterators.OfDouble.tryAdvance(this, action); } @Override public void forEachRemaining(Consumer action) { Spliterators.OfDouble.forEachRemaining(this, action); } @Override protected void acceptConsumed(DoubleConsumer action) { action.accept(tmpValue); } @Override protected ArrayBuffer.OfDouble bufferCreate(int initialCapacity) { return new ArrayBuffer.OfDouble(initialCapacity); } @Override protected Spliterator.OfDouble makeSpliterator(Spliterator.OfDouble s) { return new UnorderedSliceSpliterator.OfDouble(s, this); } } } /** * A wrapping spliterator that only reports distinct elements of the * underlying spliterator. Does not preserve size and encounter order. */ static final class DistinctSpliterator implements Spliterator, Consumer { // The value to represent null in the ConcurrentHashMap private static final Object NULL_VALUE = new Object(); // The underlying spliterator private final Spliterator s; // ConcurrentHashMap holding distinct elements as keys private final ConcurrentMap seen; // Temporary element, only used with tryAdvance private T tmpSlot; DistinctSpliterator(Spliterator s) { // Pre-size map to reduce concurrent re-sizes this(s, new ConcurrentHashMap<>(512, 0.75f, ForkJoinPool.getCommonPoolParallelism() + 1)); } private DistinctSpliterator(Spliterator s, ConcurrentMap seen) { this.s = s; this.seen = seen; } @Override public long getExactSizeIfKnown() { return Spliterators.getExactSizeIfKnown(this); } @Override public boolean hasCharacteristics(int characteristics) { return Spliterators.hasCharacteristics(this, characteristics); } @Override public void accept(T t) { this.tmpSlot = t; } @SuppressWarnings("unchecked") private T mapNull(T t) { return t != null ? t : (T) NULL_VALUE; } @Override public boolean tryAdvance(Consumer action) { while (s.tryAdvance(this)) { if (seen.putIfAbsent(mapNull(tmpSlot), Boolean.TRUE) == null) { action.accept(tmpSlot); tmpSlot = null; return true; } } return false; } @Override public void forEachRemaining(Consumer action) { s.forEachRemaining(t -> { if (seen.putIfAbsent(mapNull(t), Boolean.TRUE) == null) { action.accept(t); } }); } @Override public Spliterator trySplit() { Spliterator split = s.trySplit(); return (split != null) ? new DistinctSpliterator<>(split, seen) : null; } @Override public long estimateSize() { return s.estimateSize(); } @Override public int characteristics() { return (s.characteristics() & ~(Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.SORTED | Spliterator.ORDERED)) | Spliterator.DISTINCT; } @Override public Comparator getComparator() { return s.getComparator(); } } /** * A Spliterator that infinitely supplies elements in no particular order. * *

Splitting divides the estimated size in two and stops when the * estimate size is 0. * *

The {@code forEachRemaining} method if invoked will never terminate. * The {@code tryAdvance} method always returns true. * */ abstract static class InfiniteSupplyingSpliterator implements Spliterator { long estimate; protected InfiniteSupplyingSpliterator(long estimate) { this.estimate = estimate; } @Override public long estimateSize() { return estimate; } @Override public int characteristics() { return IMMUTABLE; } @Override public long getExactSizeIfKnown() { return Spliterators.getExactSizeIfKnown(this); } @Override public boolean hasCharacteristics(int characteristics) { return Spliterators.hasCharacteristics(this, characteristics); } @Override public Comparator getComparator() { return Spliterators.getComparator(this); } static final class OfRef extends InfiniteSupplyingSpliterator { final Supplier s; OfRef(long size, Supplier s) { super(size); this.s = s; } @Override public void forEachRemaining(Consumer action) { Spliterators.forEachRemaining(this, action); } @Override public boolean tryAdvance(Consumer action) { Objects.requireNonNull(action); action.accept(s.get()); return true; } @Override public Spliterator trySplit() { if (estimate == 0) return null; return new InfiniteSupplyingSpliterator.OfRef<>(estimate >>>= 1, s); } } static final class OfInt extends InfiniteSupplyingSpliterator implements Spliterator.OfInt { final IntSupplier s; OfInt(long size, IntSupplier s) { super(size); this.s = s; } @Override public boolean tryAdvance(IntConsumer action) { Objects.requireNonNull(action); action.accept(s.getAsInt()); return true; } @Override public Spliterator.OfInt trySplit() { if (estimate == 0) return null; return new InfiniteSupplyingSpliterator.OfInt(estimate = estimate >>> 1, s); } @Override public void forEachRemaining(IntConsumer action) { Spliterators.OfInt.forEachRemaining(this, action); } @Override public void forEachRemaining(Consumer action) { Spliterators.OfInt.forEachRemaining(this, action); } @Override public boolean tryAdvance(Consumer action) { return Spliterators.OfInt.tryAdvance(this, action); } } static final class OfLong extends InfiniteSupplyingSpliterator implements Spliterator.OfLong { final LongSupplier s; OfLong(long size, LongSupplier s) { super(size); this.s = s; } @Override public boolean tryAdvance(LongConsumer action) { Objects.requireNonNull(action); action.accept(s.getAsLong()); return true; } @Override public Spliterator.OfLong trySplit() { if (estimate == 0) return null; return new InfiniteSupplyingSpliterator.OfLong(estimate = estimate >>> 1, s); } @Override public void forEachRemaining(LongConsumer action) { Spliterators.OfLong.forEachRemaining(this, action); } @Override public void forEachRemaining(Consumer action) { Spliterators.OfLong.forEachRemaining(this, action); } @Override public boolean tryAdvance(Consumer action) { return Spliterators.OfLong.tryAdvance(this, action); } } static final class OfDouble extends InfiniteSupplyingSpliterator implements Spliterator.OfDouble { final DoubleSupplier s; OfDouble(long size, DoubleSupplier s) { super(size); this.s = s; } @Override public boolean tryAdvance(DoubleConsumer action) { Objects.requireNonNull(action); action.accept(s.getAsDouble()); return true; } @Override public boolean tryAdvance(Consumer action) { return Spliterators.OfDouble.tryAdvance(this, action); } @Override public Spliterator.OfDouble trySplit() { if (estimate == 0) return null; return new InfiniteSupplyingSpliterator.OfDouble(estimate = estimate >>> 1, s); } @Override public void forEachRemaining(DoubleConsumer action) { Spliterators.OfDouble.forEachRemaining(this, action); } @Override public void forEachRemaining(Consumer action) { Spliterators.OfDouble.forEachRemaining(this, action); } } } // @@@ Consolidate with Node.Builder abstract static class ArrayBuffer { int index; void reset() { index = 0; } static final class OfRef extends ArrayBuffer implements Consumer { final Object[] array; OfRef(int size) { this.array = new Object[size]; } @Override public void accept(T t) { array[index++] = t; } public void forEach(Consumer action, long fence) { for (int i = 0; i < fence; i++) { @SuppressWarnings("unchecked") T t = (T) array[i]; action.accept(t); } } } abstract static class OfPrimitive extends ArrayBuffer { int index; @Override void reset() { index = 0; } abstract void forEach(T_CONS action, long fence); } static final class OfInt extends OfPrimitive implements IntConsumer { final int[] array; OfInt(int size) { this.array = new int[size]; } @Override public void accept(int t) { array[index++] = t; } @Override public void forEach(IntConsumer action, long fence) { for (int i = 0; i < fence; i++) { action.accept(array[i]); } } } static final class OfLong extends OfPrimitive implements LongConsumer { final long[] array; OfLong(int size) { this.array = new long[size]; } @Override public void accept(long t) { array[index++] = t; } @Override public void forEach(LongConsumer action, long fence) { for (int i = 0; i < fence; i++) { action.accept(array[i]); } } } static final class OfDouble extends OfPrimitive implements DoubleConsumer { final double[] array; OfDouble(int size) { this.array = new double[size]; } @Override public void accept(double t) { array[index++] = t; } @Override void forEach(DoubleConsumer action, long fence) { for (int i = 0; i < fence; i++) { action.accept(array[i]); } } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy