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

com.github.dm.jrt.operator.sequence.Sequences Maven / Gradle / Ivy

/*
 * Copyright 2016 Davide Maestroni
 *
 * 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 com.github.dm.jrt.operator.sequence;

import com.github.dm.jrt.core.channel.Channel;
import com.github.dm.jrt.core.util.ConstantConditions;
import com.github.dm.jrt.core.util.DeepEqualObject;
import com.github.dm.jrt.function.BiFunction;
import com.github.dm.jrt.function.BiFunctionDecorator;
import com.github.dm.jrt.function.Consumer;
import com.github.dm.jrt.function.Function;
import com.github.dm.jrt.function.FunctionDecorator;

import org.jetbrains.annotations.NotNull;

import java.math.BigDecimal;
import java.math.BigInteger;

import static com.github.dm.jrt.core.util.Reflection.asArgs;
import static com.github.dm.jrt.operator.math.Numbers.toBigDecimalSafe;

/**
 * Utility class providing functions that produce sequences of data.
 * 

* Created by davide-maestroni on 07/02/2016. */ public class Sequences { /** * Avoid explicit instantiation. */ protected Sequences() { ConstantConditions.avoid(); } /** * Returns a consumer generating the specified range of data. *
* The generated data will start from the specified first one up to and including the specified * last one, by computing each next element through the specified function. * * @param start the first element of the range. * @param end the last element of the range. * @param incrementFunction the function incrementing the current element. * @param the data type. * @return the consumer instance. */ @NotNull public static > Consumer> range( @NotNull final DATA start, @NotNull final DATA end, @NotNull final Function incrementFunction) { return new RangeConsumer(ConstantConditions.notNull("start element", start), ConstantConditions.notNull("end element", end), FunctionDecorator.decorate(incrementFunction)); } /** * Returns a consumer generating the specified range of data. *
* The stream will generate a range of numbers up to and including the {@code end} element, by * applying a default increment of {@code +1} or {@code -1} depending on the comparison between * the first and the last element. That is, if the first element is less than the last, the * increment will be {@code +1}. On the contrary, if the former is greater than the latter, the * increment will be {@code -1}. * * @param start the first element of the range. * @param end the last element of the range. * @param the number type. * @return the consumer instance. */ @NotNull @SuppressWarnings("unchecked") public static Consumer> range(@NotNull final N start, @NotNull final N end) { return (Consumer>) numberRange(start, end); } /** * Returns a consumer generating the specified range of data. *
* The stream will generate a range of numbers by applying the specified increment up to and * including the {@code end} element. * * @param start the first element of the range. * @param end the last element of the range. * @param increment the increment to apply to the current element. * @param the number type. * @return the consumer instance. */ @NotNull @SuppressWarnings("unchecked") public static Consumer> range(@NotNull final N start, @NotNull final N end, @NotNull final N increment) { return (Consumer>) numberRange(start, end, increment); } /** * Returns a consumer generating the specified sequence of data. *
* The generated data will start from the specified first and will produce the specified number * of elements, by computing each next one through the specified function. * * @param start the first element of the sequence. * @param count the number of generated elements. * @param nextFunction the function computing the next element. * @param the data type. * @return the consumer instance. * @throws java.lang.IllegalArgumentException if the count is not positive. */ @NotNull public static Consumer> sequence(@NotNull final DATA start, final long count, @NotNull final BiFunction nextFunction) { return new SequenceConsumer(ConstantConditions.notNull("start element", start), ConstantConditions.positive("sequence size", count), BiFunctionDecorator.decorate(nextFunction)); } @NotNull private static Consumer> numberRange( @NotNull final N start, @NotNull final N end) { if ((start instanceof BigDecimal) || (end instanceof BigDecimal)) { final BigDecimal startValue = toBigDecimalSafe(start); final BigDecimal endValue = toBigDecimalSafe(end); return numberRange(startValue, endValue, (startValue.compareTo(endValue) <= 0) ? 1 : -1); } else if ((start instanceof BigInteger) || (end instanceof BigInteger)) { final BigDecimal startDecimal = toBigDecimalSafe(start); final BigDecimal endDecimal = toBigDecimalSafe(end); if ((startDecimal.scale() > 0) || (endDecimal.scale() > 0)) { return numberRange(startDecimal, endDecimal, (startDecimal.compareTo(endDecimal) <= 0) ? 1 : -1); } final BigInteger startValue = startDecimal.toBigInteger(); final BigInteger endValue = endDecimal.toBigInteger(); return numberRange(startValue, endValue, (startValue.compareTo(endValue) <= 0) ? 1 : -1); } else if ((start instanceof Double) || (end instanceof Double)) { final double startValue = start.doubleValue(); final double endValue = end.doubleValue(); return numberRange(start, end, (startValue <= endValue) ? 1 : -1); } else if ((start instanceof Float) || (end instanceof Float)) { final float startValue = start.floatValue(); final float endValue = end.floatValue(); return numberRange(start, end, (startValue <= endValue) ? 1 : -1); } else if ((start instanceof Long) || (end instanceof Long)) { final long startValue = start.longValue(); final long endValue = end.longValue(); return numberRange(start, end, (startValue <= endValue) ? 1 : -1); } else if ((start instanceof Integer) || (end instanceof Integer)) { final int startValue = start.intValue(); final int endValue = end.intValue(); return numberRange(start, end, (startValue <= endValue) ? 1 : -1); } else if ((start instanceof Short) || (end instanceof Short)) { final short startValue = start.shortValue(); final short endValue = end.shortValue(); return numberRange(start, end, (short) ((startValue <= endValue) ? 1 : -1)); } else if ((start instanceof Byte) || (end instanceof Byte)) { final byte startValue = start.byteValue(); final byte endValue = end.byteValue(); return numberRange(start, end, (byte) ((startValue <= endValue) ? 1 : -1)); } throw new IllegalArgumentException( "unsupported Number class: [" + start.getClass().getCanonicalName() + ", " + end.getClass() .getCanonicalName() + "]"); } @NotNull private static Consumer> numberRange( @NotNull final N start, @NotNull final N end, @NotNull final N increment) { if ((start instanceof BigDecimal) || (end instanceof BigDecimal) || (increment instanceof BigDecimal)) { final BigDecimal startValue = toBigDecimalSafe(start); final BigDecimal endValue = toBigDecimalSafe(end); final BigDecimal incValue = toBigDecimalSafe(increment); return new RangeConsumer(startValue, endValue, new BigDecimalInc(incValue)); } else if ((start instanceof BigInteger) || (end instanceof BigInteger) || (increment instanceof BigInteger)) { final BigDecimal startDecimal = toBigDecimalSafe(start); final BigDecimal endDecimal = toBigDecimalSafe(end); final BigDecimal incDecimal = toBigDecimalSafe(increment); if ((startDecimal.scale() > 0) || (endDecimal.scale() > 0) || (incDecimal.scale() > 0)) { return new RangeConsumer(startDecimal, endDecimal, new BigDecimalInc(incDecimal)); } final BigInteger startValue = startDecimal.toBigInteger(); final BigInteger endValue = endDecimal.toBigInteger(); final BigInteger incValue = incDecimal.toBigInteger(); return new RangeConsumer(startValue, endValue, new BigIntegerInc(incValue)); } else if ((start instanceof Double) || (end instanceof Double) || (increment instanceof Double)) { final double startValue = start.doubleValue(); final double endValue = end.doubleValue(); final double incValue = increment.doubleValue(); return new RangeConsumer(startValue, endValue, new DoubleInc(incValue)); } else if ((start instanceof Float) || (end instanceof Float) || (increment instanceof Float)) { final float startValue = start.floatValue(); final float endValue = end.floatValue(); final float incValue = increment.floatValue(); return new RangeConsumer(startValue, endValue, new FloatInc(incValue)); } else if ((start instanceof Long) || (end instanceof Long) || (increment instanceof Long)) { final long startValue = start.longValue(); final long endValue = end.longValue(); final long incValue = increment.longValue(); return new RangeConsumer(startValue, endValue, new LongInc(incValue)); } else if ((start instanceof Integer) || (end instanceof Integer) || (increment instanceof Integer)) { final int startValue = start.intValue(); final int endValue = end.intValue(); final int incValue = increment.intValue(); return new RangeConsumer(startValue, endValue, new IntegerInc(incValue)); } else if ((start instanceof Short) || (end instanceof Short) || (increment instanceof Short)) { final short startValue = start.shortValue(); final short endValue = end.shortValue(); final short incValue = increment.shortValue(); return new RangeConsumer(startValue, endValue, new ShortInc(incValue)); } else if ((start instanceof Byte) || (end instanceof Byte) || (increment instanceof Byte)) { final byte startValue = start.byteValue(); final byte endValue = end.byteValue(); final byte incValue = increment.byteValue(); return new RangeConsumer(startValue, endValue, new ByteInc(incValue)); } throw new IllegalArgumentException( "unsupported Number class: [" + start.getClass().getCanonicalName() + ", " + end.getClass() .getCanonicalName() + ", " + increment.getClass().getCanonicalName() + "]"); } /** * Function incrementing a big decimal of a specific value. */ private static class BigDecimalInc extends NumberInc { private final BigDecimal mIncValue; /** * Constructor. * * @param incValue the incrementation value. */ private BigDecimalInc(final BigDecimal incValue) { super(incValue); mIncValue = incValue; } public BigDecimal apply(final BigDecimal bigDecimal) { return bigDecimal.add(mIncValue); } } /** * Function incrementing a big integer of a specific value. */ private static class BigIntegerInc extends NumberInc { private final BigInteger mIncValue; /** * Constructor. * * @param incValue the incrementation value. */ private BigIntegerInc(final BigInteger incValue) { super(incValue); mIncValue = incValue; } public BigInteger apply(final BigInteger bigInteger) { return bigInteger.add(mIncValue); } } /** * Function incrementing a short of a specific value. */ private static class ByteInc extends NumberInc { private final byte mIncValue; /** * Constructor. * * @param incValue the incrementation value. */ private ByteInc(final byte incValue) { super(incValue); mIncValue = incValue; } public Byte apply(final Byte aByte) { return (byte) (aByte + mIncValue); } } /** * Function incrementing a double of a specific value. */ private static class DoubleInc extends NumberInc { private final double mIncValue; /** * Constructor. * * @param incValue the incrementation value. */ private DoubleInc(final double incValue) { super(incValue); mIncValue = incValue; } public Double apply(final Double aDouble) { return aDouble + mIncValue; } } /** * Function incrementing a float of a specific value. */ private static class FloatInc extends NumberInc { private final float mIncValue; /** * Constructor. * * @param incValue the incrementation value. */ private FloatInc(final float incValue) { super(incValue); mIncValue = incValue; } public Float apply(final Float aFloat) { return aFloat + mIncValue; } } /** * Function incrementing an integer of a specific value. */ private static class IntegerInc extends NumberInc { private final int mIncValue; /** * Constructor. * * @param incValue the incrementation value. */ private IntegerInc(final int incValue) { super(incValue); mIncValue = incValue; } public Integer apply(final Integer integer) { return integer + mIncValue; } } /** * Function incrementing a long of a specific value. */ private static class LongInc extends NumberInc { private final long mIncValue; /** * Constructor. * * @param incValue the incrementation value. */ private LongInc(final long incValue) { super(incValue); mIncValue = incValue; } public Long apply(final Long aLong) { return aLong + mIncValue; } } /** * Base abstract function incrementing a number of a specific value. *
* It provides an implementation for {@code equals()} and {@code hashCode()} methods. */ private static abstract class NumberInc extends DeepEqualObject implements Function { /** * Constructor. * * @param incValue the incrementation value. */ private NumberInc(@NotNull final N incValue) { super(asArgs(incValue)); } } /** * Consumer implementation generating a range of data. * * @param the output data type. */ private static class RangeConsumer> extends DeepEqualObject implements Consumer> { private final OUT mEnd; private final Function mIncrementFunction; private final OUT mStart; /** * Constructor. * * @param start the first element of the range. * @param end the last element of the range. * @param incrementFunction the function incrementing the current element. */ private RangeConsumer(@NotNull final OUT start, @NotNull final OUT end, @NotNull final Function incrementFunction) { super(asArgs(start, end, incrementFunction)); mStart = start; mEnd = end; mIncrementFunction = incrementFunction; } public void accept(final Channel result) throws Exception { final OUT start = mStart; final OUT end = mEnd; final Function increment = mIncrementFunction; OUT current = start; if (start.compareTo(end) <= 0) { while (current.compareTo(end) <= 0) { result.pass(current); current = increment.apply(current); } } else { while (current.compareTo(end) >= 0) { result.pass(current); current = increment.apply(current); } } } } /** * Consumer implementation generating a sequence of data. * * @param the output data type. */ private static class SequenceConsumer extends DeepEqualObject implements Consumer> { private final long mCount; private final BiFunctionDecorator mNextFunction; private final OUT mStart; /** * Constructor. * * @param start the first element of the sequence. * @param count the size of the sequence. * @param nextFunction the function computing the next element. */ private SequenceConsumer(@NotNull final OUT start, final long count, @NotNull final BiFunctionDecorator nextFunction) { super(asArgs(start, count, nextFunction)); mStart = start; mCount = count; mNextFunction = nextFunction; } public void accept(final Channel result) throws Exception { final BiFunctionDecorator next = mNextFunction; OUT current = mStart; final long last = mCount - 1; if (last >= 0) { result.pass(current); } for (long i = 0; i < last; ++i) { current = next.apply(current, i); result.pass(current); } } } /** * Function incrementing a short of a specific value. */ private static class ShortInc extends NumberInc { private final short mIncValue; /** * Constructor. * * @param incValue the incrementation value. */ private ShortInc(final short incValue) { super(incValue); mIncValue = incValue; } public Short apply(final Short aShort) { return (short) (aShort + mIncValue); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy