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

com.tangosol.internal.util.stream.ReferencePipeline Maven / Gradle / Ivy

There is a newer version: 24.09
Show newest version
/*
 * Copyright (c) 2000, 2020, Oracle and/or its affiliates.
 *
 * Licensed under the Universal Permissive License v 1.0 as shown at
 * http://oss.oracle.com/licenses/upl.
 */
package com.tangosol.internal.util.stream;

import com.tangosol.internal.util.stream.collectors.BiReducingCollector;
import com.tangosol.internal.util.stream.collectors.MappingCollector;
import com.tangosol.internal.util.stream.collectors.ReducingCollector;

import com.tangosol.io.ExternalizableLite;

import com.tangosol.io.pof.PofReader;
import com.tangosol.io.pof.PofWriter;
import com.tangosol.io.pof.PortableObject;

import com.tangosol.net.NamedCache;
import com.tangosol.net.PartitionedService;

import com.tangosol.net.partition.AbstractPartitionedIterator;
import com.tangosol.net.partition.PartitionSet;

import com.tangosol.util.ExternalizableHelper;
import com.tangosol.util.Filter;
import com.tangosol.util.InvocableMap;
import com.tangosol.util.SimpleHolder;
import com.tangosol.util.Streamer;

import com.tangosol.util.comparator.SafeComparator;

import com.tangosol.util.filter.PartitionedFilter;

import com.tangosol.util.function.Remote;

import com.tangosol.util.stream.RemoteCollector;
import com.tangosol.util.stream.RemoteCollectors;
import com.tangosol.util.stream.RemotePipeline;
import com.tangosol.util.stream.RemoteDoubleStream;
import com.tangosol.util.stream.RemoteIntStream;
import com.tangosol.util.stream.RemoteLongStream;
import com.tangosol.util.stream.RemoteStream;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Objects;
import java.util.Optional;
import java.util.Spliterator;

import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.function.ToDoubleFunction;
import java.util.function.ToIntFunction;
import java.util.function.ToLongFunction;

import java.util.stream.BaseStream;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import java.util.stream.Stream;

import javax.json.bind.annotation.JsonbProperty;

/**
 * Abstract base class for an intermediate pipeline stage or pipeline source
 * stage implementing whose elements are of type {@code U}.
 *
 * @param       key type
 * @param       value type
 * @param    type of elements in the upstream source
 * @param   type of elements produced by this stage
 * @param    the type of input stream
 *
 * @author as  2014.08.26
 * @since 12.2.1
 */
@SuppressWarnings("Convert2MethodRef")
public abstract class ReferencePipeline>
        extends AbstractPipeline>
        implements RemoteStream
    {
    // ---- constructors ----------------------------------------------------

    /**
     * Deserialization constructor.
     */
    protected ReferencePipeline()
        {
        }

    /**
     * Constructor for the head of a stream pipeline.
     *
     * @param map             the stream source
     * @param fParallel       true if the pipeline is parallel
     */
    protected ReferencePipeline(InvocableMap map, boolean fParallel,
                             Collection colKeys, Filter filter,
                             Function> intermediateOp)
        {
        super(map, fParallel, colKeys, filter, intermediateOp);
        }

    /**
     * Construct intermediate stage of the pipeline.
     *
     * @param previousStage   previous stage in the pipeline
     * @param intermediateOp  Intermediate operation performed by this stage
     */
    protected ReferencePipeline(AbstractPipeline previousStage,
                                Function> intermediateOp)
        {
        super(previousStage, intermediateOp);
        }

    // ---- intermediate operations -----------------------------------------

    public RemoteStream sequential()
        {
        setParallel(false);
        return this;
        }

    public RemoteStream parallel()
        {
        setParallel(true);
        return this;
        }

    public RemoteStream unordered()
        {
        return new StatelessOp<>(this, (s) -> s.unordered());
        }

    public RemoteStream filter(Predicate filter)
        {
        return new StatelessOp<>(this, (s) -> s.filter(filter));
        }

    public  RemoteStream map(Function mapper)
        {
        return new StatelessOp<>(this, (s) -> s.map(mapper));
        }

    public RemoteIntStream mapToInt(ToIntFunction mapper)
        {
        return new IntPipeline.StatelessOp<>(this, (s) -> s.mapToInt(mapper));
        }

    public RemoteLongStream mapToLong(ToLongFunction mapper)
        {
        return new LongPipeline.StatelessOp<>(this, s -> s.mapToLong(mapper));
        }

    public RemoteDoubleStream mapToDouble(ToDoubleFunction mapper)
        {
        return new DoublePipeline.StatelessOp<>(this, s -> s.mapToDouble(mapper));
        }

    public  RemoteStream flatMap(Function> mapper)
        {
        return new StatelessOp<>(this, (s) -> s.flatMap(mapper));
        }

    public RemoteIntStream flatMapToInt(Function mapper)
        {
        return new IntPipeline.StatelessOp<>(this, (s) -> s.flatMapToInt(mapper));
        }

    public RemoteLongStream flatMapToLong(Function mapper)
        {
        return new LongPipeline.StatelessOp<>(this, s -> s.flatMapToLong(mapper));
        }

    public RemoteDoubleStream flatMapToDouble(Function mapper)
        {
        return new DoublePipeline.StatelessOp<>(this, s -> s.flatMapToDouble(mapper));
        }

    public RemoteStream peek(Consumer action)
        {
        return new StatelessOp<>(this, (s) -> s.peek(action));
        }

    public Stream limit(long maxSize)
        {
        return collect(new StatefulOp<>(this, (s) -> s.limit(maxSize)),
                       toCollection()).stream().limit(maxSize);
        }

    public Stream skip(long n)
        {
        return collect(this, toCollection()).stream().skip(n);
        }

    public Stream distinct()
        {
        return collect(this, toSet()).stream();
        }

    public RemoteStream sorted()
        {
        SafeComparator comp = SafeComparator.INSTANCE;
        StatefulOp> op =
                new StatefulOp<>(this, (s) -> s.sorted(comp));
        op.setComparator(comp);
        return op;
        }

    public RemoteStream sorted(Comparator comparator)
        {
        SafeComparator comp = new SafeComparator<>(comparator);
        StatefulOp> op =
                new StatefulOp<>(this, (s) -> s.sorted(comp));
        op.setComparator(comp);
        return op;
        }

    // ---- terminal operations ---------------------------------------------

    public Iterator iterator()
        {
        if (isSorted() || !isPartitionable())
            {
            return collect(toCollection()).iterator();
            }

        return createPartitionedIterator((filter) -> getMap().aggregate(filter, new CollectorAggregator<>(this, toCollection())), false);
        }

    public Spliterator spliterator()
        {
        if (isSorted() || !isPartitionable())
            {
            return collect(toCollection()).spliterator();
            }

        return new PartitionedSpliterator<>(createPartitionedIterator((filter) -> getMap().aggregate(filter, new CollectorAggregator<>(this, toCollection())), false));
        }

    public void forEach(Consumer action)
        {
        iterator().forEachRemaining(action);
        }

    public void forEachOrdered(Consumer action)
        {
        forEach(action);
        }

    public Object[] toArray()
        {
        return collect(toCollection()).toArray();
        }

    @SuppressWarnings("SuspiciousToArrayCall")
    public  A[] toArray(IntFunction generator)
        {
        Collection col = collect(toCollection());
        return col.toArray(generator.apply(col.size()));
        }

    public P_OUT reduce(P_OUT identity, BinaryOperator accumulator)
        {
        return collect(reducing(identity, accumulator));
        }

    public Optional reduce(BinaryOperator accumulator)
        {
        return collect(reducing(accumulator));
        }

    public  U reduce(U identity, BiFunction accumulator, BinaryOperator combiner)
        {
        return collect(reducing(identity, accumulator, combiner));
        }

    public  R collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner)
        {
        Remote.BinaryOperator operator = (left, right) ->
            {
            combiner.accept(left, right);
            return left;
            };

        return collect(RemoteCollector.of(supplier, accumulator, operator));
        }

    public  R collect(RemoteCollector collector)
        {
        return collect(this, collector);
        }

    public Optional min(Comparator comparator)
        {
        return collect(minBy(comparator));
        }

    public Optional max(Comparator comparator)
        {
        return collect(maxBy(comparator));
        }

    public long count()
        {
        return collect(RemoteCollectors.counting());
        }

    public boolean anyMatch(Predicate predicate)
        {
        return invoke(new MatcherAggregator<>(this, (s) -> s.anyMatch(predicate), (p) -> p));
        }

    public boolean allMatch(Predicate predicate)
        {
        return invoke(new MatcherAggregator<>(this, (s) -> s.allMatch(predicate), (p) -> !p));
        }

    public boolean noneMatch(Predicate predicate)
        {
        return invoke(new MatcherAggregator<>(this, (s) -> s.noneMatch(predicate), (p) -> !p));
        }

    public Optional findFirst()
        {
        return invoke(new FinderAggregator<>(this, Stream::findFirst));
        }

    public Optional findAny()
        {
        return invoke(new FinderAggregator<>(this, Stream::findAny));
        }

    // ---- helper methods --------------------------------------------------

    protected  R collect(RemotePipeline> pipeline, RemoteCollector collector)
        {
        return invoke(new CollectorAggregator<>(pipeline, collector));
        }

    protected static  RemoteCollector mapping(Function mapper, RemoteCollector downstream)
        {
        return new MappingCollector<>(mapper, downstream);
        }

    protected static  RemoteCollector> minBy(Comparator comparator)
        {
        return reducing(Remote.BinaryOperator.minBy(comparator));
        }

    protected static  RemoteCollector> maxBy(Comparator comparator)
        {
        return reducing(Remote.BinaryOperator.maxBy(comparator));
        }

    protected static  RemoteCollector> reducing(BinaryOperator op)
        {
        return RemoteCollectors.collectingAndThen(reducing(null, op), Optional::ofNullable);
        }

    protected static  RemoteCollector reducing(T identity, BinaryOperator op)
        {
        return new ReducingCollector<>(identity, op);
        }

    protected static  RemoteCollector, U> reducing(U identity,
                                    BiFunction mapper,
                                    BinaryOperator op)
        {
        return new BiReducingCollector<>(identity, mapper, op);
        }

    protected PartitionedIterator createPartitionedIterator(Function> supplier, boolean fByMember)
        {
        NamedCache         cache   = (NamedCache) getMap();
        PartitionedService service = (PartitionedService) cache.getCacheService();
        int                cParts  = service.getPartitionCount();
        PartitionSet       parts   = new PartitionSet(cParts).fill();

        return new PartitionedIterator<>(getInvoker().getFilter(), cache, parts, supplier, fByMember);
        }

    // ---- pipeline stage implementations ----------------------------------

    /**
     * A stage in a pipeline representing beginning of the pipeline.
     *
     * @param   the type of input elements
     * @param  the type of output elements
     * @param   the type of input stream
     */
    public static class Head>
            extends ReferencePipeline
        {
        /**
         * Deserialization constructor.
         */
        public Head()
            {
            }

        /**
         * Construct Head instance.
         *
         * @param map             the parent map this stream was created from
         * @param parallel        a flag specifying whether this stream should be
         *                        evaluated in parallel
         * @param filter          a filter that should be used to narrow down
         *                        parent map contents before stream evaluation
         * @param intermediateOp  intermediate operation for this stage
         */
        protected Head(InvocableMap map, boolean parallel,
                    Collection colKeys, Filter filter,
                    Remote.Function> intermediateOp)
            {
            super(map, parallel, colKeys, filter, intermediateOp);
            }
        }

    /**
     * A stage in a pipeline representing stateless operation.
     *
     * @param   the type of input elements
     * @param  the type of output elements
     * @param   the type of input stream
     */
    public static class StatelessOp>
            extends ReferencePipeline
        {
        /**
         * Deserialization constructor.
         */
        public StatelessOp()
            {
            }

        /**
         * Construct StatelessOp instance.
         *
         * @param previousStage   the upstream pipeline stage
         * @param intermediateOp  intermediate operation for this stage
         */
        StatelessOp(AbstractPipeline previousStage, Remote.Function> intermediateOp)
            {
            super(previousStage, intermediateOp);
            }
        }

    /**
     * A stage in a pipeline representing stateful operation.
     *
     * @param   the type of input elements
     * @param  the type of output elements
     * @param   the type of input stream
     */
    public static class StatefulOp>
            extends ReferencePipeline
        {
        /**
         * Deserialization constructor.
         */
        public StatefulOp()
            {
            }

        /**
         * Construct StatefulOp instance.
         *
         * @param previousStage   the upstream pipeline stage
         * @param intermediateOp  intermediate operation for this stage
         */
        StatefulOp(AbstractPipeline previousStage, Remote.Function> intermediateOp)
            {
            super(previousStage, intermediateOp);
            }
        }

    // ---- inner class: PartitionedIterator --------------------------------

    protected static class PartitionedIterator
            extends AbstractPartitionedIterator
        {
        public PartitionedIterator(Filter filter, NamedCache cache, PartitionSet setPids,
                                   Function> supplier, boolean fByMember)
            {
            super(filter, cache, setPids, fByMember, false);

            Objects.requireNonNull(supplier);
            m_supplier = supplier;
            }

        public PartitionedIterator(PartitionedIterator that, PartitionSet setPids)
            {
            super(that.m_filter, that.m_cache, setPids, that.m_fByMember, that.m_fRandom);

            m_supplier = that.m_supplier;
            }

        protected Iterable nextIterable(PartitionedFilter filter)
            {
            return m_supplier.apply(filter);
            }

        protected PartitionSet getPartitionSet()
            {
            return m_setPids;
            }

        private Function> m_supplier;
        }

    // ---- inner class: PartitionedSpliterator -----------------------------

    protected static class PartitionedSpliterator
            implements Spliterator
        {
        public PartitionedSpliterator(PartitionedIterator iterator)
            {
            this(iterator, 0);
            }

        public PartitionedSpliterator(PartitionedIterator iterator, int nCharacteristics)
            {
            m_iterator         = iterator;
            m_nCharacteristics = nCharacteristics;
            }

        @Override
        public void forEachRemaining(Consumer action)
            {
            Objects.requireNonNull(action);
            m_iterator.forEachRemaining(action);
            }

        @Override
        public boolean tryAdvance(Consumer action)
            {
            Objects.requireNonNull(action);

            Iterator it = m_iterator;
            if (it.hasNext())
                {
                action.accept(it.next());
                return true;
                }

            return false;
            }

        public Spliterator trySplit()
            {
            PartitionSet parts = m_iterator.getPartitionSet().split();
            if (parts == null)
                {
                return null;
                }

            PartitionedIterator iterator = new PartitionedIterator<>(m_iterator, parts);
            return new PartitionedSpliterator<>(iterator, m_nCharacteristics);
            }

        public long estimateSize()
            {
            return Long.MAX_VALUE;
            }

        public int characteristics()
            {
            return Spliterator.CONCURRENT | m_nCharacteristics;
            }

        private PartitionedIterator m_iterator;
        private int m_nCharacteristics;
        }

    // ---- inner class: MatcherAggregator ----------------------------------

    /**
     * Aggregator used by matching terminal operations ({@link RemoteStream#anyMatch},
     * {@link RemoteStream#allMatch} and {@link RemoteStream#noneMatch}).
     *
     * @param  the type of the Map entry keys
     * @param  the type of the Map entry values
     * @param  the type of stream elements to match
     */
    public static class MatcherAggregator
            implements InvocableMap.StreamingAggregator,
                       ExternalizableLite, PortableObject
        {
        // ---- constructors ------------------------------------------------

        /**
         * Deserialization constructor.
         */
        public MatcherAggregator()
            {
            }

        /**
         * Construct MatcherAggregator instance.
         *
         * @param pipeline      pipeline of intermediate operations to evaluate
         * @param fnMatcher     matching operation to invoke on the stream
         * @param predShortCircuit  predicate that determines if the aggregation
         *                      should be short-circuited
         */
        MatcherAggregator(RemotePipeline> pipeline,
                          Remote.Function, Boolean> fnMatcher,
                          Remote.Predicate predShortCircuit)
            {
            m_pipeline         = pipeline;
            m_fnMatcher        = fnMatcher;
            m_predShortCircuit = predShortCircuit;
            }

        // ---- InvocableMap.StreamingAggregator interface ------------------

        @Override
        public InvocableMap.StreamingAggregator supply()
            {
            return new MatcherAggregator<>(m_pipeline, m_fnMatcher, m_predShortCircuit);
            }

        @Override
        public boolean accumulate(Streamer> streamer)
            {
            Stream stream = m_pipeline.evaluate(streamer.stream());
            m_fResult = m_fnMatcher.apply(stream);
            return !m_predShortCircuit.test(m_fResult);
            }

        @Override
        public boolean accumulate(InvocableMap.Entry entry)
            {
            throw new UnsupportedOperationException();
            }

        @Override
        public boolean combine(Boolean partialResult)
            {
            if (!m_fDone)
                {
                m_fResult = partialResult;
                m_fDone   = m_predShortCircuit.test(m_fResult);
                }
            return !m_fDone;
            }

        @Override
        public Boolean getPartialResult()
            {
            return m_fResult;
            }

        @Override
        public Boolean finalizeResult()
            {
            return m_fResult;
            }

        @Override
        public int characteristics()
            {
            return SERIAL;
            }

        // ---- ExternalizableLite interface --------------------------------

        @Override
        public void readExternal(DataInput in) throws IOException
            {
            m_pipeline         = ExternalizableHelper.readObject(in);
            m_fnMatcher        = ExternalizableHelper.readObject(in);
            m_predShortCircuit = ExternalizableHelper.readObject(in);
            }

        @Override
        public void writeExternal(DataOutput out) throws IOException
            {
            ExternalizableHelper.writeObject(out, m_pipeline);
            ExternalizableHelper.writeObject(out, m_fnMatcher);
            ExternalizableHelper.writeObject(out, m_predShortCircuit);
            }

        // ---- PortableObject interface ------------------------------------

        public void readExternal(PofReader reader) throws IOException
            {
            m_pipeline         = reader.readObject(0);
            m_fnMatcher        = reader.readObject(1);
            m_predShortCircuit = reader.readObject(2);
            }

        public void writeExternal(PofWriter writer) throws IOException
            {
            writer.writeObject(0, m_pipeline);
            writer.writeObject(1, m_fnMatcher);
            writer.writeObject(2, m_predShortCircuit);
            }

        // ---- data members ------------------------------------------------

        /**
         * Pipeline of intermediate operations to evaluate.
         */
        @JsonbProperty("pipeline")
        private RemotePipeline> m_pipeline;

        /**
         * Matching operation to invoke on the stream
         */
        @JsonbProperty("fnMatcher")
        private Remote.Function, Boolean> m_fnMatcher;

        /**
         * Predicate that determines if the aggregation should be short-circuited.
         */
        @JsonbProperty("predShortCircuit")
        private Remote.Predicate m_predShortCircuit;

        /**
         * The aggregation result.
         */
        private transient Boolean m_fResult;

        /**
         * If true, indicates that no more accumulation is necessary.
         */
        private transient boolean m_fDone;
        }

    // ---- inner class: FinderAggregator -----------------------------------

    /**
     * Aggregator used by finder terminal operations ({@link RemoteStream#findFirst()}
     * and {@link RemoteStream#findAny()}).
     *
     * @param  the type of the Map entry keys
     * @param  the type of the Map entry values
     * @param  the type of stream elements to find
     */
    public static class FinderAggregator
            implements InvocableMap.StreamingAggregator, Optional>,
                       ExternalizableLite, PortableObject
        {
        // ---- constructors ------------------------------------------------

        /**
         * Deserialization constructor.
         */
        public FinderAggregator()
            {
            }

        /**
         * Construct FinderAggregator instance.
         *
         * @param pipeline  pipeline of intermediate operations to evaluate
         * @param fnFinder  find operation to invoke on the stream
         */
        FinderAggregator(RemotePipeline> pipeline,
                         Remote.Function, Optional> fnFinder)
            {
            m_pipeline = pipeline;
            m_fnFinder = fnFinder;
            }

        // ---- InvocableMap.StreamingAggregator interface ------------------

        @Override
        public InvocableMap.StreamingAggregator, Optional> supply()
            {
            return new FinderAggregator<>(m_pipeline, m_fnFinder);
            }

        @Override
        public boolean accumulate(Streamer> streamer)
            {
            Stream stream = m_pipeline.evaluate(streamer.stream());
            m_result = m_fnFinder.apply(stream);
            return !m_result.isPresent();
            }

        @Override
        public boolean accumulate(InvocableMap.Entry entry)
            {
            throw new UnsupportedOperationException();
            }

        @Override
        public boolean combine(Optional partialResult)
            {
            if (!m_fDone)
                {
                m_result = partialResult;
                m_fDone  = m_result.isPresent();
                }
            return !m_fDone;
            }

        @Override
        public Optional getPartialResult()
            {
            return m_result;
            }

        @Override
        public Optional finalizeResult()
            {
            return m_result;
            }

        @Override
        public int characteristics()
            {
            return SERIAL;
            }

        // ---- ExternalizableLite interface --------------------------------

        @Override
        public void readExternal(DataInput in) throws IOException
            {
            m_pipeline = ExternalizableHelper.readObject(in);
            m_fnFinder = ExternalizableHelper.readObject(in);
            }

        @Override
        public void writeExternal(DataOutput out) throws IOException
            {
            ExternalizableHelper.writeObject(out, m_pipeline);
            ExternalizableHelper.writeObject(out, m_fnFinder);
            }

        // ---- PortableObject interface ------------------------------------

        public void readExternal(PofReader reader) throws IOException
            {
            m_pipeline = reader.readObject(0);
            m_fnFinder = reader.readObject(1);
            }

        public void writeExternal(PofWriter writer) throws IOException
            {
            writer.writeObject(0, m_pipeline);
            writer.writeObject(1, m_fnFinder);
            }

        // ---- data members ------------------------------------------------

        /**
         * Pipeline of intermediate operations to evaluate.
         */
        @JsonbProperty("pipeline")
        private RemotePipeline> m_pipeline;

        /**
         * Find operation to invoke on the stream
         */
        @JsonbProperty("fnFinder")
        private Remote.Function, Optional> m_fnFinder;

        /**
         * The aggregation result.
         */
        private transient Optional m_result = Optional.empty();

        /**
         * If true, indicates that no more accumulation is necessary.
         */
        private transient boolean m_fDone;
        }
    }