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

net.openhft.chronicle.wire.internal.reduction.ReductionUtil Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2016-2022 chronicle.software
 *
 *       https://chronicle.software
 *
 * 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 net.openhft.chronicle.wire.internal.reduction;

import net.openhft.chronicle.core.Jvm;
import net.openhft.chronicle.core.io.InvalidMarshallableException;
import net.openhft.chronicle.core.util.ObjectUtils;
import net.openhft.chronicle.wire.DocumentContext;
import net.openhft.chronicle.wire.ExcerptListener;
import net.openhft.chronicle.wire.MarshallableIn;
import net.openhft.chronicle.wire.Wire;
import net.openhft.chronicle.wire.domestic.extractor.DocumentExtractor;
import net.openhft.chronicle.wire.domestic.extractor.ToDoubleDocumentExtractor;
import net.openhft.chronicle.wire.domestic.extractor.ToLongDocumentExtractor;
import net.openhft.chronicle.wire.domestic.reduction.Reduction;
import org.jetbrains.annotations.NotNull;

import java.util.function.*;
import java.util.stream.Collector;

import static java.util.Objects.requireNonNull;

/**
 * The ReductionUtil class provides utility methods and inner classes related to the reduction process.
 * It offers functionalities to work with marshallable objects and listeners to read excerpts
 * from documents and perform various reduction operations on them.
 */
public final class ReductionUtil {

    // Suppresses default constructor, ensuring non-instantiability.
    private ReductionUtil() {
    }

    /**
     * Reads excerpts from the given tailer until no more are present. For each excerpt, the given listener is invoked.
     *
     * @param tailer The MarshallableIn instance to read excerpts from.
     * @param excerptListener The listener to notify for each excerpt.
     * @return The index of the last read excerpt.
     * @throws InvalidMarshallableException if an issue occurs during reading.
     */
    public static long accept(@NotNull final MarshallableIn tailer,
                              @NotNull final ExcerptListener excerptListener) throws InvalidMarshallableException {
        requireNonNull(tailer);
        long lastIndex = -1;
        boolean end = false;
        while (!end) {
            try (final DocumentContext dc = tailer.readingDocument()) {
                final Wire wire = dc.wire();
                if (dc.isPresent() && wire != null) {
                    lastIndex = dc.index();
                    excerptListener.onExcerpt(wire, lastIndex);
                } else {
                    end = true;
                }
            }
        }
        return lastIndex;
    }

    /**
     * The CollectorReduction class provides functionalities to perform reduction operations using
     * a specific collector and an extractor. It extracts data from a wire, collects it using the
     * provided collector, and then performs the final reduction.
     *
     * @param  Type of the element to extract.
     * @param  Intermediate accumulation type of the collector.
     * @param  Result type of the reduction.
     */
    public static final class CollectorReduction implements Reduction {

        // Extracts elements of type E from a wire.
        private final DocumentExtractor extractor;

        // The collector to accumulate elements and produce a final result.
        private final Collector collector;

        // The current accumulated value.
        private final A accumulation;

        /**
         * Initializes a new instance of CollectorReduction with the provided extractor and collector.
         *
         * @param extractor The extractor to fetch elements from a wire.
         * @param collector The collector to accumulate and reduce the elements.
         */
        public CollectorReduction(@NotNull final DocumentExtractor extractor,
                                  @NotNull final Collector collector) {
            this.extractor = extractor;
            this.collector = collector;

            // Warn if the collector doesn't have CONCURRENT characteristic.
            if (!collector.characteristics().contains(Collector.Characteristics.CONCURRENT)) {
                Jvm.warn().on(CollectorReduction.class, "The collector " + collector + " should generally have the characteristics CONCURRENT");
            }
            this.accumulation = collector.supplier().get();
        }

        @Override
        public void onExcerpt(@NotNull Wire wire, long index) throws InvalidMarshallableException {
            final E element = extractor.extract(wire, index);
            if (element != null) {
                collector.accumulator()
                        .accept(accumulation, element);
            }
        }

        @SuppressWarnings("unchecked")
        @NotNull
        @Override
        public R reduction() {
            if (collector.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
                return (R) accumulation;
            }
            return collector.finisher().apply(accumulation);
        }

        @Override
        public long accept(@NotNull final MarshallableIn tailer) throws InvalidMarshallableException {
            requireNonNull(tailer);
            return ReductionUtil.accept(tailer, this);
        }
    }

    /**
     * The LongSupplierReduction class provides functionalities to perform reduction operations
     * over long values extracted from documents. It reads long values from a wire, accumulates them,
     * and then offers a final reduction in the form of a LongSupplier.
     *
     * @param  Intermediate accumulation type.
     */
    public static final class LongSupplierReduction implements Reduction {

        // Extracts long values from a wire.
        private final ToLongDocumentExtractor extractor;

        // The accumulator to accumulate long values.
        private final ObjLongConsumer accumulator;

        // The current accumulated value.
        private final A accumulation;

        // Function to finish the reduction and produce a result.
        private final ToLongFunction finisher;

        /**
         * Initializes a new instance of LongSupplierReduction with the provided extractor, supplier,
         * accumulator, and finisher.
         *
         * @param extractor The extractor to fetch long values from a wire.
         * @param supplier The supplier to initialize the accumulation.
         * @param accumulator The accumulator to accumulate long values.
         * @param finisher The function to finish the reduction.
         */
        public LongSupplierReduction(@NotNull final ToLongDocumentExtractor extractor,
                                     @NotNull final Supplier supplier,
                                     @NotNull final ObjLongConsumer accumulator,
                                     @NotNull final ToLongFunction finisher) {
            this.extractor = requireNonNull(extractor);
            this.accumulator = requireNonNull(accumulator);
            requireNonNull(supplier);
            this.accumulation = requireNonNull(supplier.get());
            this.finisher = requireNonNull(finisher);
        }

        @Override
        public void onExcerpt(@NotNull Wire wire, long index) throws InvalidMarshallableException {
            final long element = extractor.extractAsLong(wire, index);
            if (element != Long.MIN_VALUE) {
                accumulator.accept(accumulation, element);
            }
        }

        @NotNull
        @Override
        public LongSupplier reduction() {
            return () -> finisher.applyAsLong(accumulation);
        }

        @Override
        public long accept(@NotNull final MarshallableIn tailer) throws InvalidMarshallableException {
            requireNonNull(tailer);
            return ReductionUtil.accept(tailer, this);
        }
    }

    /**
     * The DoubleSupplierReduction class provides functionalities to perform reduction operations
     * over double values extracted from documents. It reads double values from a wire, accumulates them,
     * and then offers a final reduction in the form of a DoubleSupplier.
     *
     * @param  Intermediate accumulation type.
     */
    public static final class DoubleSupplierReduction implements Reduction {

        // Extracts double values from a wire.
        private final ToDoubleDocumentExtractor extractor;

        // The accumulator to accumulate double values.
        private final ObjDoubleConsumer accumulator;

        // The current accumulated value.
        private final A accumulation;

        // Function to finish the reduction and produce a result.
        private final ToDoubleFunction finisher;

        /**
         * Initializes a new instance of DoubleSupplierReduction with the provided extractor, supplier,
         * accumulator, and finisher.
         *
         * @param extractor The extractor to fetch double values from a wire.
         * @param supplier The supplier to initialize the accumulation.
         * @param accumulator The accumulator to accumulate double values.
         * @param finisher The function to finish the reduction.
         */
        public DoubleSupplierReduction(@NotNull final ToDoubleDocumentExtractor extractor,
                                       @NotNull final Supplier supplier,
                                       @NotNull final ObjDoubleConsumer accumulator,
                                       @NotNull final ToDoubleFunction finisher) {
            this.extractor = requireNonNull(extractor);
            this.accumulator = requireNonNull(accumulator);
            requireNonNull(supplier);
            this.accumulation = requireNonNull(supplier.get());
            this.finisher = requireNonNull(finisher);
        }

        @Override
        public void onExcerpt(@NotNull Wire wire, long index) throws InvalidMarshallableException {
            final double element = extractor.extractAsDouble(wire, index);
            if (!Double.isNaN(element)) {
                accumulator.accept(accumulation, element);
            }
        }

        @NotNull
        @Override
        public DoubleSupplier reduction() {
            return () -> finisher.applyAsDouble(accumulation);
        }

        @Override
        public long accept(@NotNull final MarshallableIn tailer) throws InvalidMarshallableException {
            requireNonNull(tailer);
            return ReductionUtil.accept(tailer, this);
        }
    }

    // Reduction Builders

    /**
     * The VanillaReductionBuilder class assists in building reductions based on the extraction of elements of type E.
     * It leverages provided DocumentExtractors to aid in this process.
     *
     * @param  The type of element to be extracted from documents.
     */
    public static final class VanillaReductionBuilder implements Reduction.ReductionBuilder {

        // Extracts elements of type E from a wire/document.
        private final DocumentExtractor extractor;

        /**
         * Initializes a new instance of VanillaReductionBuilder with the provided extractor.
         *
         * @param extractor The extractor to fetch elements of type E from a wire.
         */
        public VanillaReductionBuilder(@NotNull final DocumentExtractor extractor) {
            this.extractor = extractor;
        }

        @Override
        public  Reduction collecting(@NotNull Collector collector) {
            ObjectUtils.requireNonNull(collector);
            // Create a new CollectorReduction using the provided collector and this builder's extractor.
            return new ReductionUtil.CollectorReduction<>(extractor, collector);
        }
    }

    /**
     * The VanillaLongReductionBuilder class assists in building reductions that work with long values.
     * It leverages provided ToLongDocumentExtractors to aid in this process.
     */
    public static final class VanillaLongReductionBuilder implements Reduction.LongReductionBuilder {

        // Extracts long values from a wire/document.
        private final ToLongDocumentExtractor extractor;

        /**
         * Initializes a new instance of VanillaLongReductionBuilder with the provided long extractor.
         *
         * @param extractor The extractor to fetch long values from a wire.
         */
        public VanillaLongReductionBuilder(@NotNull final ToLongDocumentExtractor extractor) {
            this.extractor = extractor;
        }

        @Override
        public  Reduction reducing(@NotNull final Supplier supplier,
                                                    @NotNull final ObjLongConsumer accumulator,
                                                    @NotNull final ToLongFunction finisher) {
            ObjectUtils.requireNonNull(supplier);
            ObjectUtils.requireNonNull(accumulator);
            ObjectUtils.requireNonNull(finisher);
            return new ReductionUtil.LongSupplierReduction<>(extractor, supplier, accumulator, finisher);
        }
    }

    public static final class VanillaDoubleReductionBuilder implements Reduction.DoubleReductionBuilder {

        private final ToDoubleDocumentExtractor extractor;

        public VanillaDoubleReductionBuilder(@NotNull final ToDoubleDocumentExtractor extractor) {
            this.extractor = extractor;
        }

        @Override
        public  Reduction reducing(@NotNull final Supplier supplier,
                                                      @NotNull final ObjDoubleConsumer accumulator,
                                                      @NotNull final ToDoubleFunction finisher) {
            ObjectUtils.requireNonNull(supplier);
            ObjectUtils.requireNonNull(accumulator);
            ObjectUtils.requireNonNull(finisher);
            return new ReductionUtil.DoubleSupplierReduction<>(extractor, supplier, accumulator, finisher);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy