diff --git a/prism/.classpath b/prism/.classpath index 1bef3aa5af..4b1d86cb08 100644 --- a/prism/.classpath +++ b/prism/.classpath @@ -1,7 +1,12 @@ - + + + + + + @@ -12,5 +17,6 @@ + diff --git a/prism/Makefile b/prism/Makefile index 12544d2ef2..72d4748056 100644 --- a/prism/Makefile +++ b/prism/Makefile @@ -14,6 +14,7 @@ # If this is a problem, the best solution is to create symlinks. export PRISM_SRC_DIR = src +export PRISM_TESTS_DIR = unit-tests export PRISM_CLASSES_DIR = classes export PRISM_OBJ_DIR = obj export PRISM_LIB_DIR = lib @@ -176,6 +177,7 @@ else endif LD = $(CXX) JAVAC = javac +JAVA = java export CC CXX LD JAVAC JAVACC @@ -323,6 +325,7 @@ export CFLAGS CXXFLAGS LDFLAGS JFLAGS LIBPREFIX LIBSUFFIX ########################################## MAKE_DIRS = dd jdd odd dv prism mtbdd sparse hybrid parser settings userinterface pepa/compiler simulator jltl2ba jltl2dstar explicit pta param strat automata common cex +TEST_DIRS = common EXT_PACKAGES = lpsolve55 lp_solve_5.5_java @@ -368,7 +371,7 @@ extpackages: checks # Compile main PRISM code # (we also do some preparatory checks, and build launch scripts afterwards) -prism: checks make_dirs bin_scripts +prism: checks make_dirs bin_scripts make_tests # Compile each (top-level) source directory separately make_dirs: @@ -397,6 +400,22 @@ make_dirs: (dos2unix $(PRISM_INCLUDE_DIR)/jni/*.h) \ fi; +make_tests: + @for dir in $(TEST_DIRS); do \ + echo Making $(PRISM_TESTS_DIR)/$$dir ...; \ + (cd $(PRISM_TESTS_DIR)/$$dir && \ + $(MAKE) \ + CUDD_DIR="$(CUDD_DIR)" \ + JAVA_INCLUDES="$(JAVA_INCLUDES)" \ + JAVA_JNI_H_DIR="$(JAVA_JNI_H_DIR)" \ + JAVA_JNI_MD_H_DIR="$(JAVA_JNI_MD_H_DIR)" \ + SHARED="$(SHARED)" \ + EXE="$(EXE)" \ + LIBMATH="$(LIBMATH)" \ + CLASSPATHSEP="$(CLASSPATHSEP)") \ + || exit 1; \ + done; \ + # Copy/modify the launch scripts and put in the bin directory bin_scripts: @for target in $(BIN_TARGETS); do \ @@ -472,6 +491,8 @@ count_loc: ########### # Testing # ########### +unittests: + $(JAVA) -jar lib/junit-platform-console-standalone-1.7.2.jar -cp classes --scan-classpath # Run a single test case from the test suite (useful quick check that the build was ok) test: diff --git a/prism/lib/junit-platform-console-standalone-1.7.2.jar b/prism/lib/junit-platform-console-standalone-1.7.2.jar new file mode 100644 index 0000000000..f37056501f Binary files /dev/null and b/prism/lib/junit-platform-console-standalone-1.7.2.jar differ diff --git a/prism/src/common/IntSet.java b/prism/src/common/IntSet.java index 8bac70fd54..1ca419be81 100644 --- a/prism/src/common/IntSet.java +++ b/prism/src/common/IntSet.java @@ -3,6 +3,7 @@ // Copyright (c) 2016- // Authors: // * Joachim Klein (TU Dresden) +// * Steffen Maercker (TU Dresden) // //------------------------------------------------------------------------------ // @@ -27,13 +28,18 @@ package common; import java.util.BitSet; +import java.util.Objects; +import java.util.PrimitiveIterator; import java.util.Spliterator; import java.util.Spliterators; -import java.util.PrimitiveIterator.OfInt; +import java.util.function.IntPredicate; import java.util.stream.IntStream; import java.util.stream.StreamSupport; import common.IterableBitSet; +import common.iterable.FunctionalPrimitiveIterable; +import common.iterable.FunctionalPrimitiveIterator; +import common.iterable.SingletonIterable; /** * Interface for an ordered set of integers that allows efficient @@ -42,19 +48,16 @@ *
* Provides static helpers for wrapping a BitSet or a singleton value. */ -public interface IntSet extends Iterable +public interface IntSet extends FunctionalPrimitiveIterable.OfInt { - /** Return a PrimitiveIterator.OfInt iterator for iteration, normal order */ - public OfInt iterator(); - - /** Return a PrimitiveIterator.OfInt iterator for iteration, reversed order */ - public OfInt reversedIterator(); + /** Return a FunctionalPrimitiveIterator.OfInt iterator for iteration, reversed order */ + FunctionalPrimitiveIterator.OfInt reversedIterator(); /** Return the cardinality (number of elements) for this set */ - public int cardinality(); - - /** Return true if {@code index} is a member of this set */ - public boolean contains(int index); + default long cardinality() + { + return count(); + } /** * Return true if {@code index} is a member of this set @@ -62,7 +65,7 @@ public interface IntSet extends Iterable *

* Default implementation: Calls contains(index). */ - public default boolean get(int index) + default boolean get(int index) { return contains(index); } @@ -74,9 +77,9 @@ public default boolean get(int index) * Default implementation: * Tests via contains for all elements of other. */ - public default boolean contains(IntSet other) + default boolean contains(IntSet other) { - return other.stream().allMatch(this::contains); + return other.allMatch((IntPredicate) this::contains); } /** @@ -86,7 +89,7 @@ public default boolean contains(IntSet other) * Default implementation: * Uses contains(IntSet other). */ - public default boolean contains(BitSet other) + default boolean contains(BitSet other) { return contains(asIntSet(other)); } @@ -97,23 +100,32 @@ public default boolean contains(BitSet other) * Default implementation: * Wrap iterator() into an intStream. */ - public default IntStream stream() { + default IntStream stream() + { return StreamSupport.intStream( - () -> Spliterators.spliterator( - iterator(), cardinality(), - Spliterator.DISTINCT), + () -> spliterator(), Spliterator.SIZED | Spliterator.DISTINCT, false); } + @Override + default Spliterator.OfInt spliterator() + { + return Spliterators.spliterator( + iterator(), + cardinality(), + Spliterator.SIZED | Spliterator.DISTINCT); + } + /** Return this set as a String */ - public default String asString() + @Override + default String asString() { // can't overload toString() with a default method in interface StringBuffer sb = new StringBuffer(); sb.append("{"); boolean first = true; - for (OfInt it = iterator(); it.hasNext(); ) { + for (PrimitiveIterator.OfInt it = iterator(); it.hasNext(); ) { if (!first) sb.append(","); first = false; @@ -123,33 +135,36 @@ public default String asString() return sb.toString(); } + + /** * Wrapper class for obtaining an IntSet from a BitSet. *

* Note: The BitSet should not be modified as long as the * derived IntSet is in use. */ - public static class IntSetFromBitSet implements IntSet + static class IntSetFromBitSet implements IntSet { /** The wrapped BitSet */ - private BitSet bs; + protected BitSet bs; /** The cardinality of the underlying BitSet (cached, -1 = not yet computed) */ int cardinality = -1; /** Constructor */ public IntSetFromBitSet(BitSet bs) { + Objects.requireNonNull(bs); this.bs = bs; } @Override - public OfInt iterator() + public FunctionalPrimitiveIterator.OfInt iterator() { return IterableBitSet.getSetBits(bs).iterator(); } @Override - public OfInt reversedIterator() + public FunctionalPrimitiveIterator.OfInt reversedIterator() { return IterableBitSet.getSetBitsReversed(bs).iterator(); } @@ -161,7 +176,7 @@ public IntStream stream() } @Override - public int cardinality() + public long count() { // not yet computed? if (cardinality == -1) @@ -183,86 +198,53 @@ public String toString() } }; + + /** Convenience class for simulating a singleton set */ - public static class SingletonIntSet implements IntSet + static class SingletonIntSet extends SingletonIterable.OfInt implements IntSet { - /** The single member of this singleton set */ - private int singleMember; - /** * Constructor. * @param singleMember the single member of this set */ public SingletonIntSet(int singleMember) { - this.singleMember = singleMember; + super(singleMember); } @Override - public OfInt iterator() - { - return new OfInt() { - boolean done = false; - @Override - public boolean hasNext() - { - return !done; - } - @Override - public int nextInt() - { - done = true; - return singleMember; - } - }; - } - - @Override - public OfInt reversedIterator() + public FunctionalPrimitiveIterator.OfInt reversedIterator() { // iteration order does not matter for singleton set return iterator(); } - @Override - public int cardinality() - { - return 1; - } - - @Override - public boolean contains(int index) - { - return index == singleMember; - } - @Override public String toString() { - return "{" + singleMember + "}"; + return "{" + element + "}"; } - } /** - * Static constructor for obtaining an IntSet from a BitSet + * Factory method for obtaining an IntSet from a BitSet *

* Note: The BitSet should not be modified as long as the derived IntSet is in use. + * * @param bs The underlying BitSet */ - public static IntSet asIntSet(BitSet bs) + static IntSet asIntSet(BitSet bs) { return new IntSetFromBitSet(bs); } /** - * Static constructor for obtaining an IntSet for a singleton set. + * Factory method for obtaining an IntSet for a singleton set. + * * @param singleMember The single member of the singleton set */ - public static IntSet asIntSet(int singleMember) + static IntSet asIntSet(int singleMember) { return new SingletonIntSet(singleMember); } - } - diff --git a/prism/src/common/IterableBitSet.java b/prism/src/common/IterableBitSet.java index da2e85bfcf..8e90563a17 100644 --- a/prism/src/common/IterableBitSet.java +++ b/prism/src/common/IterableBitSet.java @@ -2,7 +2,7 @@ // // Copyright (c) 2014- // Authors: -// * Steffen Maercker (TU Dresden) +// * Steffen Maercker (TU Dresden) // * Joachim Klein (TU Dresden) // //------------------------------------------------------------------------------ @@ -30,9 +30,9 @@ import java.util.BitSet; import java.util.NoSuchElementException; import java.util.Objects; -import java.util.PrimitiveIterator.OfInt; -import common.iterable.IterableInt; +import common.iterable.FunctionalPrimitiveIterable; +import common.iterable.FunctionalPrimitiveIterator; /** * Convenience class to loop easily over the set/clear bits of a BitSet. @@ -40,7 +40,7 @@ * For example:

* for (Integer index : getSetBits(set)) { ... }
*/ -public class IterableBitSet implements IterableInt +public class IterableBitSet implements FunctionalPrimitiveIterable.OfInt { protected final BitSet set; protected final boolean clearBits; @@ -92,7 +92,7 @@ public IterableBitSet(BitSet set, Integer maxIndex, boolean clearBits, boolean r } /** Implementation of the iterator over the set bits */ - private class SetBitsIterator implements OfInt + private class SetBitsIterator implements FunctionalPrimitiveIterator.OfInt { private int current = -1; private int next = set.nextSetBit(0); @@ -130,7 +130,7 @@ public void remove() } /** Implementation of the iterator over the set bits (reverse order) */ - private class SetBitsReversedIterator implements OfInt + private class SetBitsReversedIterator implements FunctionalPrimitiveIterator.OfInt { private int current = -1; private int next; @@ -168,7 +168,7 @@ public void remove() } /** Implementation of the iterator over the cleared bits, requires that {@code maxIndex != null} */ - private class ClearBitsIterator implements OfInt + private class ClearBitsIterator implements FunctionalPrimitiveIterator.OfInt { private int current = -1; private int next = set.nextClearBit(0); @@ -206,7 +206,7 @@ public void remove() } /** Implementation of the iterator over the clear bits (reverse order), requires that {@code maxIndex != null} */ - private class ClearBitsReversedIterator implements OfInt + private class ClearBitsReversedIterator implements FunctionalPrimitiveIterator.OfInt { private int current = -1; private int next; @@ -244,7 +244,7 @@ public void remove() } @Override - public OfInt iterator() + public FunctionalPrimitiveIterator.OfInt iterator() { if (clearBits == false) { if (reversed) { diff --git a/prism/src/common/IterableStateSet.java b/prism/src/common/IterableStateSet.java index 86427129c5..d7f14e8317 100644 --- a/prism/src/common/IterableStateSet.java +++ b/prism/src/common/IterableStateSet.java @@ -3,7 +3,7 @@ // Copyright (c) 2014- // Authors: // * Joachim Klein (TU Dresden) -// * Steffen Märcker (TU Dresden) +// * Steffen Märcker (TU Dresden) // //------------------------------------------------------------------------------ // @@ -25,22 +25,23 @@ // //============================================================================== - package common; import java.util.BitSet; -import java.util.PrimitiveIterator.OfInt; -import common.iterable.*; +import common.iterable.EmptyIterable; +import common.iterable.FunctionalPrimitiveIterable; +import common.iterable.FunctionalPrimitiveIterator; +import common.iterable.Range; /** * A convenience wrapper around IterableBitSet that handles the three cases of * iterating over the set or cleared bits of a BitSet representing a set of states * as well as iterating over all states if the BitSet is {@code null}. */ -public class IterableStateSet implements IterableInt +public class IterableStateSet implements FunctionalPrimitiveIterable.OfInt { - private final IterableInt setOfStates; + protected final FunctionalPrimitiveIterable.OfInt setOfStates; /** * Constructor (iterate over all states 0..numStates-1) @@ -91,16 +92,16 @@ public IterableStateSet(BitSet setOfStates, int numStates, boolean complement, b if (setOfStates == null || (setOfStates.length() == numStates && setOfStates.cardinality() == numStates)) { // all states if (complement) { - this.setOfStates = EmptyIterable.OfInt(); + this.setOfStates = EmptyIterable.ofInt(); } else { - this.setOfStates = reversed ? new RangeIntIterable(numStates-1, 0) : new RangeIntIterable(0, numStates-1); + this.setOfStates = reversed ? new Range(numStates).reversed() : new Range(numStates); } } else if (setOfStates.isEmpty()) { // no states if (complement) { - this.setOfStates = reversed ? new RangeIntIterable(numStates-1, 0) : new RangeIntIterable(0, numStates-1); + this.setOfStates = reversed ? new Range(numStates).reversed() : new Range(numStates); } else { - this.setOfStates = EmptyIterable.OfInt(); + this.setOfStates = EmptyIterable.ofInt(); } } else { // build appropriate IterableBitSet with maxIndex = numStates-1 @@ -109,7 +110,7 @@ public IterableStateSet(BitSet setOfStates, int numStates, boolean complement, b } @Override - public OfInt iterator() + public FunctionalPrimitiveIterator.OfInt iterator() { return setOfStates.iterator(); } diff --git a/prism/src/common/IteratorTools.java b/prism/src/common/IteratorTools.java index 24a0e79847..ea4b9e4d74 100644 --- a/prism/src/common/IteratorTools.java +++ b/prism/src/common/IteratorTools.java @@ -2,7 +2,7 @@ // // Copyright (c) 2016- // Authors: -// * Steffen Maercker (TU Dresden) +// * Steffen Maercker (TU Dresden) // * Joachim Klein (TU Dresden) // //------------------------------------------------------------------------------ @@ -28,148 +28,233 @@ package common; import java.util.Iterator; -import java.util.function.DoublePredicate; -import java.util.function.IntPredicate; -import java.util.function.LongPredicate; -import java.util.function.Predicate; - -import common.iterable.FilteringIterator; -import common.iterable.MappingIterator; - +import java.util.OptionalDouble; +import java.util.OptionalInt; +import java.util.OptionalLong; import java.util.PrimitiveIterator.OfDouble; import java.util.PrimitiveIterator.OfInt; import java.util.PrimitiveIterator.OfLong; +import java.util.function.Predicate; -/** Convenience methods for performing operations on Iterators / Iterables */ +import common.iterable.Reducible; + +/** + * Convenience methods for performing operations on Iterators / Iterables + */ public class IteratorTools { - /** Count the number of elements */ - public static int count(final Iterable iterable) + /** + * Boolean AND-function: Are all elements true? + */ + public static boolean and(Iterator booleans) { - return count(iterable.iterator()); + while (booleans.hasNext()) { + if (!booleans.next()) { + return false; + } + } + return true; } - /** Count the number of elements */ - public static int count(final Iterator iterator) + /** + * Boolean OR-function: Is at least one elements true? + */ + public static boolean or(Iterator booleans) { - if (iterator instanceof OfInt) { - return count((OfInt) iterator); - } - if (iterator instanceof OfLong) { - return count((OfLong) iterator); - } - if (iterator instanceof OfDouble) { - return count((OfDouble) iterator); + while (booleans.hasNext()) { + if (booleans.next()) { + return true; + } } + return false; + } - int count=0; - for (; iterator.hasNext(); iterator.next()) { - count++; - } - return count; + /** + * Count the number of elements + */ + public static long count(Iterable iterable) + { + return Reducible.extend(iterable).count(); } - /** Count the number of elements */ - public static int count(final OfInt iterator) + /** + * Count the number of elements + */ + public static long count(Iterator iterator) { - // call nextInt to avoid unnecessary boxing - int count=0; - for (; iterator.hasNext(); iterator.nextInt()) { - count++; - } - return count; + return Reducible.extend(iterator).count(); } - /** Count the number of elements */ - public static int count(final OfLong iterator) + /** + * Count the number of elements + */ + public static long count(Iterable iterable, Predicate predicate) { - // call nextLong to avoid unnecessary boxing - int count=0; - for (; iterator.hasNext(); iterator.nextLong()) { - count++; - } - return count; + return Reducible.extend(iterable).count(predicate); } - /** Count the number of elements */ - public static int count(final OfDouble iterator) + /** + * Count the number of elements + */ + public static long count(Iterator iterator, Predicate predicate) { - // call nextDouble to avoid unnecessary boxing - int count=0; - for (; iterator.hasNext(); iterator.nextDouble()) { - count++; - } - return count; + return Reducible.extend(iterator).count(predicate); } - /** Count the number of elements matching the predicate */ - public static int count(final Iterable iterable, final Predicate predicate) + /** + * Maximum over iterator elements + */ + public static OptionalDouble max(OfDouble numbers) { - return count(iterable.iterator(), predicate); + return Reducible.extend(numbers).max(); } - /** Count the number of elements matching the predicate */ - public static int count(final Iterator iterator, final Predicate predicate) + /** + * Maximum over iterator elements + */ + public static OptionalInt max(OfInt numbers) { - if (iterator instanceof OfInt && predicate instanceof IntPredicate) { - return count(new FilteringIterator.OfInt((OfInt) iterator, (IntPredicate) predicate)); - } - if (iterator instanceof OfLong && predicate instanceof LongPredicate) { - return count(new FilteringIterator.OfLong((OfLong) iterator, (LongPredicate) predicate)); - } - if (iterator instanceof OfDouble && predicate instanceof DoublePredicate) { - return count(new FilteringIterator.OfDouble((OfDouble) iterator, (DoublePredicate) predicate)); - } + return Reducible.extend(numbers).max(); + } - return count(new FilteringIterator.Of<>(iterator, predicate)); + /** + * Maximum over iterator elements + */ + public static OptionalLong max(OfLong numbers) + { + return Reducible.extend(numbers).max(); } - /** Sum over iterator elements */ - public static int sumInt(final Iterator numbers) + /** + * Maximum over non-null iterator elements + */ + public static OptionalDouble maxDouble(Iterator numbers) { - return sum(MappingIterator.toInt(numbers)); + return Reducible.unboxDouble(Reducible.extend(numbers).nonNull()).max(); } - /** Sum over iterator elements */ - public static int sum(final OfInt numbers) + /** + * Maximum over non-null iterator elements + */ + public static OptionalInt maxInt(Iterator numbers) { - int sum = 0; - while (numbers.hasNext()) { - sum += numbers.nextInt(); - } - return sum; + return Reducible.unboxInt(Reducible.extend(numbers).nonNull()).max(); } - /** Sum over iterator elements */ - public static long sumLong(final Iterator numbers) + /** + * Maximum over non-null iterator elements + */ + public static OptionalLong maxLong(Iterator numbers) { - return sum(MappingIterator.toLong(numbers)); + return Reducible.unboxLong(Reducible.extend(numbers).nonNull()).max(); } - /** Sum over iterator elements */ - public static long sum(final OfLong numbers) + /** + * Minimum over iterator elements + */ + public static OptionalDouble min(OfDouble numbers) { - long sum = 0; - while (numbers.hasNext()) { - sum += numbers.nextLong(); - } - return sum; + return Reducible.extend(numbers).min(); } - /** Sum over iterator elements */ - public static double sumDouble(final Iterator numbers) + /** + * Minimum over iterator elements + */ + public static OptionalInt min(OfInt numbers) { - return sum(MappingIterator.toDouble(numbers)); + return Reducible.extend(numbers).min(); } - /** Sum over iterator elements */ - public static double sum(final OfDouble numbers) + /** + * Minimum over iterator elements + */ + public static OptionalLong min(OfLong numbers) { - double sum = 0; - while (numbers.hasNext()) { - sum += numbers.nextDouble(); - } - return sum; + return Reducible.extend(numbers).min(); + } + + /** + * Minimum over non-null iterator elements + */ + public static OptionalDouble minDouble(Iterator numbers) + { + return Reducible.unboxDouble(Reducible.extend(numbers).nonNull()).min(); } + /** + * Minimum over non-null iterator elements + */ + public static OptionalInt minInt(Iterator numbers) + { + return Reducible.unboxInt(Reducible.extend(numbers).nonNull()).min(); + } + + /** + * Minimum over non-null iterator elements + */ + public static OptionalLong minLong(Iterator numbers) + { + return Reducible.unboxLong(Reducible.extend(numbers).nonNull()).min(); + } + + /** + * Sum over iterator elements + */ + public static double sum(OfDouble numbers) + { + return Reducible.extend(numbers).sum(); + } + + /** + * Sum over iterator elements + */ + public static long sum(OfInt numbers) + { + return Reducible.extend(numbers).sum(); + } + + /** + * Sum over iterator elements + */ + public static long sum(OfLong numbers) + { + return Reducible.extend(numbers).sum(); + } + + /** + * Sum over non-null iterator elements + */ + public static double sumDouble(Iterator numbers) + { + return Reducible.unboxDouble(Reducible.extend(numbers).nonNull()).sum(); + } + + /** + * Sum over non-null iterator elements + */ + public static long sumInt(Iterator numbers) + { + return Reducible.unboxInt(Reducible.extend(numbers).nonNull()).sum(); + } + + /** + * Sum over non-null iterator elements + */ + public static long sumLong(Iterator numbers) + { + return Reducible.unboxLong(Reducible.extend(numbers).nonNull()).sum(); + } + + /** + * Create String "name = {e_1, e_2}". + * + * @param name name of a variable + * @param iterator the iterator to be printed + */ + public static void printIterator(String name, Iterator iterator) + { + System.out.print(name + " = "); + System.out.print(Reducible.extend(iterator).asString()); + System.out.println(); + } } diff --git a/prism/src/common/Makefile b/prism/src/common/Makefile index 115bf5b4ae..b22ca64d73 100644 --- a/prism/src/common/Makefile +++ b/prism/src/common/Makefile @@ -14,7 +14,7 @@ PRISM_DIR_REL = ../.. JNI_GEN_HEADER_DIR=$(THIS_DIR)/$(PRISM_DIR_REL)/$(PRISM_INCLUDE_DIR)/jni -JAVA_FILES_ALL = $(wildcard *.java iterable/*.java functions/primitive/*.java) +JAVA_FILES_ALL = $(wildcard *.java iterable/*.java functions/*.java) JAVA_FILES = $(subst package-info.java,,$(JAVA_FILES_ALL)) CLASS_FILES = $(JAVA_FILES:%.java=$(PRISM_DIR_REL)/$(PRISM_CLASSES_DIR)/$(THIS_DIR)/%.class) diff --git a/prism/src/common/functions/primitive/PairPredicateInt.java b/prism/src/common/functions/DoubleLongToDoubleFunction.java similarity index 74% rename from prism/src/common/functions/primitive/PairPredicateInt.java rename to prism/src/common/functions/DoubleLongToDoubleFunction.java index 4c1d8f4ae7..e60702ad91 100644 --- a/prism/src/common/functions/primitive/PairPredicateInt.java +++ b/prism/src/common/functions/DoubleLongToDoubleFunction.java @@ -1,9 +1,8 @@ //============================================================================== // -// Copyright (c) 2016- +// Copyright (c) 2020- // Authors: -// * Steffen Maercker (TU Dresden) -// * Joachim Klein (TU Dresden) +// * Steffen Maercker (TU Dresden) // //------------------------------------------------------------------------------ // @@ -25,11 +24,16 @@ // //============================================================================== -package common.functions.primitive; +package common.functions; -/** Functional interface for a predicate (int, int) -> boolean */ +/** + * Functional interface for a binary function (double, long) -> double. + */ @FunctionalInterface -public interface PairPredicateInt +public interface DoubleLongToDoubleFunction { - public abstract boolean test(int element1, int element2); + /** + * Applies this function to the given arguments. + */ + double applyAsDouble(double d, long l); } diff --git a/prism/src/common/functions/DoubleObjToDoubleFunction.java b/prism/src/common/functions/DoubleObjToDoubleFunction.java new file mode 100644 index 0000000000..5417cdc7c0 --- /dev/null +++ b/prism/src/common/functions/DoubleObjToDoubleFunction.java @@ -0,0 +1,51 @@ +//============================================================================== +// +// Copyright (c) 2020- +// Authors: +// * Steffen Maercker (TU Dresden) +// +//------------------------------------------------------------------------------ +// +// This file is part of PRISM. +// +// PRISM is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// PRISM 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 for more details. +// +// You should have received a copy of the GNU General Public License +// along with PRISM; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//============================================================================== + +package common.functions; + +import java.util.Objects; +import java.util.function.DoubleUnaryOperator; + +/** + * Functional interface for a binary function (double, T) -> double. + */ +@FunctionalInterface +public interface DoubleObjToDoubleFunction +{ + /** + * Applies this function to the given arguments. + */ + double applyAsDouble(double d, T t); + + /** + * Returns a composed function that first applies this function to + * its input, and then applies the {@code after} function to the result. + */ + default DoubleObjToDoubleFunction andThen(DoubleUnaryOperator after) { + Objects.requireNonNull(after); + return (double d, T t) -> after.applyAsDouble(applyAsDouble(d, t)); + } +} diff --git a/prism/src/common/iterable/IterableInt.java b/prism/src/common/functions/IntDoubleToIntFunction.java similarity index 74% rename from prism/src/common/iterable/IterableInt.java rename to prism/src/common/functions/IntDoubleToIntFunction.java index db8e42531e..3a3f1404c1 100644 --- a/prism/src/common/iterable/IterableInt.java +++ b/prism/src/common/functions/IntDoubleToIntFunction.java @@ -1,8 +1,8 @@ //============================================================================== // -// Copyright (c) 2016- +// Copyright (c) 2020- // Authors: -// * Steffen Maercker (TU Dresden) +// * Steffen Maercker (TU Dresden) // //------------------------------------------------------------------------------ // @@ -24,13 +24,16 @@ // //============================================================================== -package common.iterable; +package common.functions; -import java.util.PrimitiveIterator.OfInt; - -/** Iterable for a PrimitiveIterator.OfInt */ -public interface IterableInt extends Iterable +/** + * Functional interface for a binary function (int, double) -> int. + */ +@FunctionalInterface +public interface IntDoubleToIntFunction { - @Override - public OfInt iterator(); + /** + * Applies this function to the given arguments. + */ + int applyAsInt(int i, double d); } diff --git a/prism/src/common/iterable/IterableDouble.java b/prism/src/common/functions/IntLongToIntFunction.java similarity index 74% rename from prism/src/common/iterable/IterableDouble.java rename to prism/src/common/functions/IntLongToIntFunction.java index f2690013e3..fd3bf44389 100644 --- a/prism/src/common/iterable/IterableDouble.java +++ b/prism/src/common/functions/IntLongToIntFunction.java @@ -1,8 +1,8 @@ //============================================================================== // -// Copyright (c) 2016- +// Copyright (c) 2020- // Authors: -// * Steffen Maercker (TU Dresden) +// * Steffen Maercker (TU Dresden) // //------------------------------------------------------------------------------ // @@ -24,13 +24,16 @@ // //============================================================================== -package common.iterable; +package common.functions; -import java.util.PrimitiveIterator.OfDouble; - -/** Iterable for a PrimitiveIterator.OfDouble */ -public interface IterableDouble extends Iterable +/** + * Functional interface for a binary function (int, long) -> int. + */ +@FunctionalInterface +public interface IntLongToIntFunction { - @Override - public OfDouble iterator(); + /** + * Applies this function to the given arguments. + */ + int applyAsInt(int i, long l); } diff --git a/prism/src/common/functions/IntObjToIntFunction.java b/prism/src/common/functions/IntObjToIntFunction.java new file mode 100644 index 0000000000..db70e8bae7 --- /dev/null +++ b/prism/src/common/functions/IntObjToIntFunction.java @@ -0,0 +1,51 @@ +//============================================================================== +// +// Copyright (c) 2020- +// Authors: +// * Steffen Maercker (TU Dresden) +// +//------------------------------------------------------------------------------ +// +// This file is part of PRISM. +// +// PRISM is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// PRISM 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 for more details. +// +// You should have received a copy of the GNU General Public License +// along with PRISM; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//============================================================================== + +package common.functions; + +import java.util.Objects; +import java.util.function.IntUnaryOperator; + +/** + * Functional interface for a binary function (int, T) -> int. + */ +@FunctionalInterface +public interface IntObjToIntFunction +{ + /** + * Applies this function to the given arguments. + */ + int applyAsInt(int i, T t); + + /** + * Returns a composed function that first applies this function to + * its input, and then applies the {@code after} function to the result. + */ + default IntObjToIntFunction andThen(IntUnaryOperator after) { + Objects.requireNonNull(after); + return (int i, T t) -> after.applyAsInt(applyAsInt(i, t)); + } +} diff --git a/prism/src/common/iterable/IterableLong.java b/prism/src/common/functions/LongDoubleToLongFunction.java similarity index 74% rename from prism/src/common/iterable/IterableLong.java rename to prism/src/common/functions/LongDoubleToLongFunction.java index c113ef73f1..9196fce233 100644 --- a/prism/src/common/iterable/IterableLong.java +++ b/prism/src/common/functions/LongDoubleToLongFunction.java @@ -1,8 +1,8 @@ //============================================================================== // -// Copyright (c) 2016- +// Copyright (c) 2020- // Authors: -// * Steffen Maercker (TU Dresden) +// * Steffen Maercker (TU Dresden) // //------------------------------------------------------------------------------ // @@ -24,13 +24,16 @@ // //============================================================================== -package common.iterable; +package common.functions; -import java.util.PrimitiveIterator.OfLong; - -/** Iterable for a PrimitiveIterator.OfLong */ -public interface IterableLong extends Iterable +/** + * Functional interface for a binary function (int, double) -> int. + */ +@FunctionalInterface +public interface LongDoubleToLongFunction { - @Override - public OfLong iterator(); + /** + * Applies this function to the given arguments. + */ + long applyAsLong(long l, double i); } diff --git a/prism/src/common/functions/LongObjToLongFunction.java b/prism/src/common/functions/LongObjToLongFunction.java new file mode 100644 index 0000000000..3bac121046 --- /dev/null +++ b/prism/src/common/functions/LongObjToLongFunction.java @@ -0,0 +1,51 @@ +//============================================================================== +// +// Copyright (c) 2020- +// Authors: +// * Steffen Maercker (TU Dresden) +// +//------------------------------------------------------------------------------ +// +// This file is part of PRISM. +// +// PRISM is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// PRISM 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 for more details. +// +// You should have received a copy of the GNU General Public License +// along with PRISM; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//============================================================================== + +package common.functions; + +import java.util.Objects; +import java.util.function.LongUnaryOperator; + +/** + * Functional interface for a binary function (long, T) -> long. + */ +@FunctionalInterface +public interface LongObjToLongFunction +{ + /** + * Applies this function to the given arguments. + */ + long applyAsLong(long i, T t); + + /** + * Returns a composed function that first applies this function to + * its input, and then applies the {@code after} function to the result. + */ + default LongObjToLongFunction andThen(LongUnaryOperator after) { + Objects.requireNonNull(after); + return (long l, T t) -> after.applyAsLong(applyAsLong(l, t)); + } +} diff --git a/prism/src/common/functions/ObjDoubleFunction.java b/prism/src/common/functions/ObjDoubleFunction.java new file mode 100644 index 0000000000..6cdd6b307f --- /dev/null +++ b/prism/src/common/functions/ObjDoubleFunction.java @@ -0,0 +1,51 @@ +//============================================================================== +// +// Copyright (c) 2016- +// Authors: +// * Steffen Maercker (TU Dresden) +// +//------------------------------------------------------------------------------ +// +// This file is part of PRISM. +// +// PRISM is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// PRISM 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 for more details. +// +// You should have received a copy of the GNU General Public License +// along with PRISM; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//============================================================================== + +package common.functions; + +import java.util.Objects; +import java.util.function.Function; + +/** + * Functional interface for a binary function (T, double) -> R. + */ +@FunctionalInterface +public interface ObjDoubleFunction +{ + /** + * Applies this function to the given arguments. + */ + R apply(T t, double d); + + /** + * Returns a composed function that first applies this function to + * its input, and then applies the {@code after} function to the result. + */ + default ObjDoubleFunction andThen(Function after) { + Objects.requireNonNull(after); + return (T t, double d) -> after.apply(apply(t, d)); + } +} diff --git a/prism/src/common/functions/ObjIntFunction.java b/prism/src/common/functions/ObjIntFunction.java new file mode 100644 index 0000000000..33cf0fa85f --- /dev/null +++ b/prism/src/common/functions/ObjIntFunction.java @@ -0,0 +1,51 @@ +//============================================================================== +// +// Copyright (c) 2016- +// Authors: +// * Steffen Maercker (TU Dresden) +// +//------------------------------------------------------------------------------ +// +// This file is part of PRISM. +// +// PRISM is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// PRISM 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 for more details. +// +// You should have received a copy of the GNU General Public License +// along with PRISM; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//============================================================================== + +package common.functions; + +import java.util.Objects; +import java.util.function.Function; + +/** + * Functional interface for a binary function (T, int) -> R. + */ +@FunctionalInterface +public interface ObjIntFunction +{ + /** + * Applies this function to the given arguments. + */ + R apply(T t, int i); + + /** + * Returns a composed function that first applies this function to + * its input, and then applies the {@code after} function to the result. + */ + default ObjIntFunction andThen(Function after) { + Objects.requireNonNull(after); + return (T t, int i) -> after.apply(apply(t, i)); + } +} diff --git a/prism/src/common/functions/ObjLongFunction.java b/prism/src/common/functions/ObjLongFunction.java new file mode 100644 index 0000000000..b774fbce51 --- /dev/null +++ b/prism/src/common/functions/ObjLongFunction.java @@ -0,0 +1,51 @@ +//============================================================================== +// +// Copyright (c) 2016- +// Authors: +// * Steffen Maercker (TU Dresden) +// +//------------------------------------------------------------------------------ +// +// This file is part of PRISM. +// +// PRISM is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// PRISM 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 for more details. +// +// You should have received a copy of the GNU General Public License +// along with PRISM; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//============================================================================== + +package common.functions; + +import java.util.Objects; +import java.util.function.Function; + +/** + * Functional interface for a binary function (T, long) -> R. + */ +@FunctionalInterface +public interface ObjLongFunction +{ + /** + * Applies this function to the given arguments. + */ + R apply(T t, long l); + + /** + * Returns a composed function that first applies this function to + * its input, and then applies the {@code after} function to the result. + */ + default ObjLongFunction andThen(Function after) { + Objects.requireNonNull(after); + return (T t, long l) -> after.apply(apply(t, l)); + } +} diff --git a/prism/src/common/functions/PairPredicateInt.java b/prism/src/common/functions/PairPredicateInt.java new file mode 100644 index 0000000000..d1b4cb242f --- /dev/null +++ b/prism/src/common/functions/PairPredicateInt.java @@ -0,0 +1,48 @@ +//============================================================================== +// +// Copyright (c) 2016- +// Authors: +// * Steffen Maercker (TU Dresden) +// * Joachim Klein (TU Dresden) +// +//------------------------------------------------------------------------------ +// +// This file is part of PRISM. +// +// PRISM is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// PRISM 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 for more details. +// +// You should have received a copy of the GNU General Public License +// along with PRISM; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//============================================================================== + +package common.functions; + +/** + * Functional interface for a predicate (int, int) -> boolean. + */ +@FunctionalInterface +public interface PairPredicateInt +{ + /** + * Evaluates this predicate on the given arguments. + */ + boolean test(int i, int j); + + /** + * Returns a predicate that represents the logical negation of this predicate. + */ + default PairPredicateInt negate() + { + return (i, j) -> !test(i, j); + } +} diff --git a/prism/src/common/iterable/ArrayIterator.java b/prism/src/common/iterable/ArrayIterator.java new file mode 100644 index 0000000000..5182034c45 --- /dev/null +++ b/prism/src/common/iterable/ArrayIterator.java @@ -0,0 +1,280 @@ +//============================================================================== +// +// Copyright (c) 2016- +// Authors: +// * Steffen Maercker (TU Dresden) +// * Marcus Daum (Frauenhofer Institut) +// +//------------------------------------------------------------------------------ +// +// This file is part of PRISM. +// +// PRISM is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// PRISM 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 for more details. +// +// You should have received a copy of the GNU General Public License +// along with PRISM; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//============================================================================== + +package common.iterable; + +import java.util.Objects; + +/** + * Abstract base class of efficient Iterators over array slices. + * Implementations should release the underlying array after iteration. + * + * @param type of the array elements + */ +public abstract class ArrayIterator implements FunctionalIterator +{ + protected final int toIndex; + protected int nextIndex; + + /** + * Iterate over all elements in index interval [fromIndex, toIndex). + * + * @param fromIndex first index, inclusive + * @param toIndex last index, exclusive + * @param length length of the array + */ + protected ArrayIterator(int fromIndex, int toIndex, int length) + { + Objects.checkFromToIndex(fromIndex, toIndex, length); + this.nextIndex = fromIndex; + this.toIndex = toIndex; + } + + @Override + public boolean hasNext() + { + if (nextIndex < toIndex) { + return true; + } + release(); + return false; + } + + @Override + public long count() + { + return Math.max(0, toIndex - nextIndex); + } + + /** + * Get the index of the next element. + */ + public int nextIndex() + { + requireNext(); + return nextIndex; + } + + /** + * Release reference to the underlying array. + */ + @Override + public void release() + { + nextIndex = toIndex; + } + + /** + * Generic implementation of an Iterator over an array slice. + * + * @param type of the array elements + */ + public static class Of extends ArrayIterator + { + /** Placeholder array after Iterator is exhausted */ + public static final Object[] EMPTY_OBJECT = new Object[0]; + + protected E[] elements; + + /** + * Iterate over all elements. + */ + @SafeVarargs + public Of(E... elements) + { + this(elements, 0, elements.length); + } + + /** + * Iterate over all elements in index interval [fromIndex, toIndex). + * + * @param fromIndex first index, inclusive + * @param toIndex last index, exclusive + */ + public Of(E[] elements, int fromIndex, int toIndex) + { + super(fromIndex, toIndex, elements.length); + this.elements = elements; + } + + @Override + public E next() + { + requireNext(); + return elements[nextIndex++]; + } + + @SuppressWarnings("unchecked") + @Override + public void release() + { + super.release(); + elements = (E[]) EMPTY_OBJECT; + } + } + + + + /** + * Primitive specialisation for {@code double} of an Iterator over an array slice. + */ + public static class OfDouble extends ArrayIterator implements FunctionalPrimitiveIterator.OfDouble + { + /** Placeholder array after Iterator is exhausted */ + public static final double[] EMPTY_DOUBLE = new double[0]; + + protected double[] elements; + + /** + * Iterate over all elements. + */ + public OfDouble(double... elements) + { + this(elements, 0, elements.length); + } + + /** + * Iterate over all elements in index interval [fromIndex, toIndex). + * + * @param fromIndex first index, inclusive + * @param toIndex last index, exclusive + */ + public OfDouble(double[] elements, int fromIndex, int toIndex) + { + super(fromIndex, toIndex, elements.length); + this.elements = elements; + } + + @Override + public double nextDouble() + { + requireNext(); + return elements[nextIndex++]; + } + + @Override + public void release() + { + super.release(); + elements = EMPTY_DOUBLE; + } + } + + + + /** + * Primitive specialisation for {@code int} of an Iterator over an array slice. + */ + public static class OfInt extends ArrayIterator implements FunctionalPrimitiveIterator.OfInt + { + /** Placeholder array after Iterator is exhausted */ + public static final int[] EMPTY_INT = new int[0]; + + protected int[] elements; + + /** + * Iterate over all elements. + */ + public OfInt(int... elements) + { + this(elements, 0, elements.length); + } + + /** + * Iterate over all elements in index interval [fromIndex, toIndex). + * + * @param fromIndex first index, inclusive + * @param toIndex last index, exclusive + */ + public OfInt(int[] elements, int fromIndex, int toIndex) + { + super(fromIndex, toIndex, elements.length); + this.elements = elements; + } + + @Override + public int nextInt() + { + requireNext(); + return elements[nextIndex++]; + } + + @Override + public void release() + { + super.release(); + elements = EMPTY_INT; + } + } + + + + /** + * Primitive specialisation for {@code long} of an Iterator over an array slice. + */ + public static class OfLong extends ArrayIterator implements FunctionalPrimitiveIterator.OfLong + { + /** Placeholder array after Iterator is exhausted */ + public static final long[] EMPTY_LONG = new long[0]; + + protected long[] elements; + + /** + * Iterate over all elements. + */ + public OfLong(long... elements) + { + this(elements, 0, elements.length); + } + + /** + * Iterate over all elements in index interval [fromIndex, toIndex). + * + * @param fromIndex first index, inclusive + * @param toIndex last index, exclusive + */ + public OfLong(long[] elements, int fromIndex, int toIndex) + { + super(fromIndex, toIndex, elements.length); + this.elements = elements; + } + + @Override + public long nextLong() + { + requireNext(); + return elements[nextIndex++]; + } + + @Override + public void release() + { + super.release(); + elements = EMPTY_LONG; + } + } +} diff --git a/prism/src/common/iterable/CartesianProduct.java b/prism/src/common/iterable/CartesianProduct.java new file mode 100644 index 0000000000..7c573ab814 --- /dev/null +++ b/prism/src/common/iterable/CartesianProduct.java @@ -0,0 +1,212 @@ +//============================================================================== +// +// Copyright (c) 2018- +// Authors: +// * Steffen Maercker (TU Dresden) +// +//------------------------------------------------------------------------------ +// +// This file is part of PRISM. +// +// PRISM is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// PRISM 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 for more details. +// +// You should have received a copy of the GNU General Public License +// along with PRISM; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//============================================================================== + +package common.iterable; + +import java.lang.reflect.Array; +import java.util.Arrays; +import java.util.Iterator; +import java.util.function.Function; + +import common.IteratorTools; + +/** + * This class provides static methods to construct + * the Cartesian product of a set of iterables. + * The implementation computes the tuples on the fly for space efficiency. + * It relies on an efficient implementation of {@code flatMap}. + *

+ * Since Stream::flatMap preallocates memory for the complete stream, + * we have to use the alternative implementation from FunctionalIterable. + *

+ */ +public class CartesianProduct +{ + /** + * Variant of the Cartesian product with {@code Object} as common super-type of the tuple/iterable elements. + * Elements of the product are distinct and safe to store/use elsewhere. + * + * @param iterables iterables to build Cartesian product from + * @see #of(Iterable) + */ + public static FunctionalIterable of(Iterable ... iterables) + { + return of(new IterableArray.Of<>(iterables)); + } + + /** + * Typesafe generic variant of the Cartesian product. + * Elements of the product are distinct and safe to store/use elsewhere. + * + * @param type common super-type of the tuple/iterable elements + * @param iterables iterables to build Cartesian product from + * @see #of(Iterable) + */ + @SafeVarargs + public static FunctionalIterable of(Class type, Iterable ... iterables) + { + return of(type, new IterableArray.Of<>(iterables)); + } + + /** + * Variant of the Cartesian product with {@code Object} as common super-type of the tuple/iterable elements. + * Elements of the product are distinct and safe to store/use elsewhere. + * + * @param iterables iterables to build Cartesian product from + * @see #of(Iterable) + */ + public static FunctionalIterable of(Iterable> iterables) + { + return mutableOf(iterables).map(t -> Arrays.copyOf(t, t.length)); + } + + /** + * Typesafe generic variant of the Cartesian product. + * Elements of the product are distinct and safe to store/use elsewhere. + * + * @param type common super-type of the tuple/iterable elements + * @param iterables iterables to build Cartesian product from + * @see #of(Iterable) + */ + public static FunctionalIterable of(Class type, Iterable> iterables) + { + return mutableOf(type, iterables).map(t -> Arrays.copyOf(t, t.length)); + } + + /** + * Variant of the Cartesian product with {@code Object} as common super-type of the tuple/iterable elements. + * Elements of the product must be copied if stored/used elsewhere. + * + * @param type common super-type of the tuple/iterable elements + * @param iterables iterables to build Cartesian product from + * @see #of(Iterable) + */ + public static FunctionalIterable mutableOf(Iterable ... iterables) + { + return of(new IterableArray.Of<>(iterables)); + } + + /** + * Typesafe generic variant of the Cartesian product. + * Elements of the product must be copied if stored/used elsewhere. + * + * @param type common super-type of the tuple/iterable elements + * @param iterables iterables to build Cartesian product from + * @see #mutableOf(Iterator, Object[], int) + */ + @SafeVarargs + public static FunctionalIterable mutableOf(Class type, Iterable ... iterables) + { + return mutableOf(type, new IterableArray.Of<>(iterables)); + } + + /** + * Variant of the Cartesian product with {@code Object} as common super-type of the tuple/iterable elements. + * Elements of the product must be copied if stored/used elsewhere. + * + * @param iterables iterables to build Cartesian product from + * @see #mutableOf(Iterator, Object[], int); + */ + public static FunctionalIterable mutableOf(Iterable> iterables) + { + return mutableOf(Object.class, iterables); + } + + /** + * Typesafe generic variant of the Cartesian product. + * Elements of the product must be copied if stored/used elsewhere. + * + * @param type common super-type of the tuple/iterable elements + * @param iterables iterables to build Cartesian product from + * @see #mutableOf(Iterator, Object[], int); + */ + public static FunctionalIterable mutableOf(Class type, Iterable> iterables) + { + int arity = Math.toIntExact(Reducible.extend(iterables).count()); + @SuppressWarnings("unchecked") + E[] tuple = (E[]) Array.newInstance(type, arity); + return mutableOf(iterables.iterator(), tuple, 0); + } + + /** + * Build Cartesian product recursively over the provided iterables. + * For efficiency, the same tuple instance is reused for the elements of the result. + * Hence, an element has to be copied if it is stored/used elsewhere. + * + * @param iterables iterables to build Cartesian product from + * @param tuple the tuple instance to be used + * @param pos the current tuple position + * @return iterable of Cartesian product + */ + protected static FunctionalIterable mutableOf(Iterator> iterables, T[] tuple, int pos) + { + // no iterable -> empty product + if (!iterables.hasNext()) { + return EmptyIterable.of(); + } + assert pos < tuple.length : "Require slot in tuple for next element."; + FunctionalIterable elements = Reducible.extend(iterables.next()); + // one iterable -> map elements to tuples + if (!iterables.hasNext()) { + return elements.map(e -> {tuple[pos] = e; return tuple;}); + } + // more than one iterable: recurse + FunctionalIterable tuples = mutableOf(iterables, tuple, pos + 1); + // elements x tuples + return elements.flatMap(e -> {tuple[pos] = e; return tuples;}); + } + + /** + * Test method. + * + * @param args command-line arguments (ignored) + */ + public static void main(final String[] args) + { + // declare type of function explicitly to circumvent class format error due to faulty type inference + Function toString = Arrays::toString; + + FunctionalIterable product = of(); + IteratorTools.printIterator("empty product ", product.iterator()); + System.out.println(); + + product = of(Arrays.asList(1, 2, 3)); + IteratorTools.printIterator("single product ", product.map(toString).iterator()); + System.out.println(); + + product = of(Arrays.asList(1, 2, 3), Arrays.asList('a', 'b')); + IteratorTools.printIterator("binary product ", product.map(toString).iterator()); + System.out.println(); + + product = of(Arrays.asList(1, 2, 3), Arrays.asList('a', 'b'), Arrays.asList(0.5)); + IteratorTools.printIterator("ternary product", product.map(toString).iterator()); + System.out.println(); + + product = mutableOf(Arrays.asList(1, 2, 3), Arrays.asList('a', 'b'), Arrays.asList(0.5)); + IteratorTools.printIterator("ternary product", product.map(toString).iterator()); + System.out.println(); + } +} diff --git a/prism/src/common/iterable/ChainedIterable.java b/prism/src/common/iterable/ChainedIterable.java new file mode 100644 index 0000000000..28b6868dbd --- /dev/null +++ b/prism/src/common/iterable/ChainedIterable.java @@ -0,0 +1,151 @@ +//============================================================================== +// +// Copyright (c) 2016- +// Authors: +// * Steffen Maercker (TU Dresden) +// +//------------------------------------------------------------------------------ +// +// This file is part of PRISM. +// +// PRISM is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// PRISM 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 for more details. +// +// You should have received a copy of the GNU General Public License +// along with PRISM; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//============================================================================== + +package common.iterable; + +import java.util.Objects; + +/** + * Abstract base class for Iterables that chain a sequence of Iterables. + * + * @param type of the Iterator's elements + * @param type of the underlying Iterables + */ +public abstract class ChainedIterable> implements FunctionalIterable +{ + /** The Iterable over the sequence of Iterables that are chained */ + protected final FunctionalIterable iterables; + + /** + * Constructor for an Iterable that chains Iterables provided in an Iterable. + * + * @param iterables an Iterable of Iterables to be chained + */ + public ChainedIterable(Iterable iterables) + { + Objects.requireNonNull(iterables); + this.iterables = Reducible.extend(iterables); + } + + + + /** + * Generic implementation of a chained Iterable. + * + * @param type of the Iterable's elements + */ + public static class Of extends ChainedIterable> + { + /** + * Constructor for an Iterable that chains Iterables provided in an Iterable. + * + * @param iterables an Iterable of Iterables to be chained + */ + @SuppressWarnings("unchecked") + public Of(Iterable> iterables) + { + super((Iterable>) iterables); + } + + @Override + public FunctionalIterator iterator() + { + return new ChainedIterator.Of<>(iterables.map(Iterable::iterator).iterator()); + } + } + + + + /** + * Primitive specialisation for {@code double} of a chained Iterable. + */ + public static class OfDouble extends ChainedIterable implements FunctionalPrimitiveIterable.OfDouble + { + /** + * Constructor for an Iterable that chains Iterables provided in an Iterable. + * + * @param iterables an Iterable of Iterables to be chained + */ + public OfDouble(Iterable iterables) + { + super(iterables); + } + + @Override + public FunctionalPrimitiveIterator.OfDouble iterator() + { + return new ChainedIterator.OfDouble(iterables.map(PrimitiveIterable.OfDouble::iterator).iterator()); + } + } + + + + /** + * Primitive specialisation for {@code int} of a chained Iterable. + */ + public static class OfInt extends ChainedIterable implements FunctionalPrimitiveIterable.OfInt + { + /** + * Constructor for an Iterable that chains Iterables provided in an Iterable. + * + * @param iterables an Iterable of Iterables to be chained + */ + public OfInt(Iterable iterables) + { + super(iterables); + } + + @Override + public FunctionalPrimitiveIterator.OfInt iterator() + { + return new ChainedIterator.OfInt(iterables.map(PrimitiveIterable.OfInt::iterator).iterator()); + } + } + + + + /** + * Primitive specialisation for {@code long} of a chained Iterable. + */ + public static class OfLong extends ChainedIterable implements FunctionalPrimitiveIterable.OfLong + { + /** + * Constructor for an Iterable that chains Iterables provided in an Iterable. + * + * @param iterables an Iterable of Iterables to be chained + */ + public OfLong(Iterable iterables) + { + super(iterables); + } + + @Override + public FunctionalPrimitiveIterator.OfLong iterator() + { + return new ChainedIterator.OfLong(iterables.map(PrimitiveIterable.OfLong::iterator).iterator()); + } + } +} \ No newline at end of file diff --git a/prism/src/common/iterable/ChainedIterator.java b/prism/src/common/iterable/ChainedIterator.java new file mode 100644 index 0000000000..ddc009a060 --- /dev/null +++ b/prism/src/common/iterable/ChainedIterator.java @@ -0,0 +1,426 @@ +//============================================================================== +// +// Copyright (c) 2015- +// Authors: +// * Steffen Maercker (TU Dresden) +// * Joachim Klein (TU Dresden) +// +//------------------------------------------------------------------------------ +// +// This file is part of PRISM. +// +// PRISM is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// PRISM 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 for more details. +// +// You should have received a copy of the GNU General Public License +// along with PRISM; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//============================================================================== + +package common.iterable; + +import java.util.Iterator; +import java.util.Objects; +import java.util.OptionalDouble; +import java.util.OptionalInt; +import java.util.OptionalLong; +import java.util.PrimitiveIterator; + +/** + * Abstract base class implementing an Iterator that chains a sequence of Iterators. + * Returns all the elements of the first Iterator, then the elements of the + * second Iterator and so on. + *

+ * The calls to {@code next()} of the underlying Iterator happen on-the-fly, + * i.e., only when {@code next()} is called for this Iterator. + *

+ * Implementations should release the underlying Iterators after iteration. + *

+ * This Iterator does not support the {@code remove()} method, even if the underlying + * Iterators support it. + * + * @param type of the {@link Iterator}'s elements + * @param common super type of {@link FunctionalIterator} for all Iterators in the chain + */ +public abstract class ChainedIterator> implements FunctionalIterator +{ + /** The Iterator over the sequence of Iterators that are chained */ + protected FunctionalIterator iterators; + /** The current Iterator in the sequence of Iterators */ + protected I current; + + /** + * Constructor for an Iterator that chains Iterators provided in an Iterator. + * + * @param iterators an Iterator over Iterators to be chained + */ + public ChainedIterator(Iterator>iterators) + { + this(EmptyIterator.of(), iterators); + } + + /** + * Constructor for chaining an Iterator and a number of Iterators provided in an Iterator. + * + * @param iterator an Iterator to prepend the chain + * @param iterators an Iterator over Iterators to be chained + */ + @SuppressWarnings({ "unchecked"}) + public ChainedIterator(Iterator iterator, Iterator> iterators) + { + Objects.requireNonNull(iterator); + Objects.requireNonNull(iterators); + this.current = (I) Reducible.extend(iterator); + this.iterators = (FunctionalIterator) Reducible.extend(iterators).map(Reducible::extend); + hasNext(); + } + + @Override + public boolean hasNext() + { + if (current.hasNext()) { + // the current iterator has another element + return true; + } + + // the current iterator has no more elements, + // search for the next iterator that as an element + while (iterators.hasNext()) { + // consider the next iterator + current = iterators.next(); + if (current.hasNext()) { + // iterator has element, keep current and return true + return true; + } + } + // there are no more iterators / elements + release(); + return false; + } + + @Override + public long count() + { + long count = current.count() + iterators.mapToLong(FunctionalIterator::count).sum(); + release(); + return count; + } + + @Override + public void release() + { + iterators = EmptyIterator.of(); + } + + + + /** + * Generic implementation of a chained Iterator. + * + * @param type of the Iterator's elements + */ + public static class Of extends ChainedIterator> + { + /** + * Constructor for an Iterator that chains Iterators provided in an Iterator. + * + * @param iterators an Iterator over Iterators to be chained + */ + @SuppressWarnings("unchecked") + public Of(Iterator> iterators) + { + super((Iterator>) iterators); + } + + /** + * Constructor for chaining an Iterator and a number of Iterators provided in an Iterator. + * + * @param iterator an Iterator to prepend the chain + * @param iterators an Iterator over Iterators to be chained + */ + @SuppressWarnings("unchecked") + public Of(Iterator iterator, Iterator> iterators) + { + super((Iterator) iterator, (Iterator>) iterators); + } + + @Override + public E next() + { + requireNext(); + return current.next(); + } + + @Override + public boolean contains(Object obj) + { + boolean contains = current.contains(obj) || iterators.anyMatch(it -> it.contains(obj)); + release(); + return contains; + } + + @Override + public void release() + { + super.release(); + current = EmptyIterator.of(); + } + } + + + + /** + * Primitive specialisation for {@code double} of a chained Iterator. + */ + public static class OfDouble extends ChainedIterator implements FunctionalPrimitiveIterator.OfDouble + { + /** + * Constructor for an Iterator that chains Iterators provided in an Iterator. + * + * @param iterators an Iterator over Iterators to be chained + */ + public OfDouble(Iterator iterators) + { + super(iterators); + } + + /** + * Constructor for chaining an Iterator and a number of Iterators provided in an Iterator. + * + * @param iterator an Iterator to prepend the chain + * @param iterators an Iterator over Iterators to be chained + */ + public OfDouble(PrimitiveIterator.OfDouble iterator, Iterator iterators) + { + super(iterator, iterators); + } + + @Override + public double nextDouble() + { + requireNext(); + return current.nextDouble(); + } + + @Override + public boolean contains(double d) + { + boolean result = current.contains(d) || iterators.anyMatch(it -> it.contains(d)); + release(); + return result; + } + + @Override + public OptionalDouble max() + { + if (!hasNext()) { + return OptionalDouble.empty(); + } + double max = current.max().getAsDouble(); + max = iterators.reduce(max, (m, it) -> Math.max(m, it.max().orElse(m))); + release(); + return OptionalDouble.of(max); + } + + @Override + public OptionalDouble min() + { + if (!hasNext()) { + return OptionalDouble.empty(); + } + double min = current.min().getAsDouble(); + min = iterators.reduce(min, (m, it) -> Math.min(m, it.min().orElse(m))); + release(); + return OptionalDouble.of(min); + } + + @Override + public double sum() + { + double sum = iterators.reduce(current.sum(), (s, it) -> s + it.sum()); + release(); + return sum; + } + + @Override + public void release() + { + super.release(); + current = EmptyIterator.ofDouble(); + } + } + + + + /** + * Primitive specialisation for {@code int} of a chained Iterator. + */ + public static class OfInt extends ChainedIterator implements FunctionalPrimitiveIterator.OfInt + { + /** + * Constructor for an Iterator that chains Iterators provided in an Iterator. + * + * @param iterators an Iterator over Iterators to be chained + */ + public OfInt(Iterator iterators) + { + super(iterators); + } + + /** + * Constructor for chaining an Iterator and a number of Iterators provided in an Iterator. + * + * @param iterator an Iterator to prepend the chain + * @param iterators an Iterator over Iterators to be chained + */ + public OfInt(PrimitiveIterator.OfInt iterator, Iterator iterators) + { + super(iterator, iterators); + } + + @Override + public int nextInt() + { + requireNext(); + return current.nextInt(); + } + + @Override + public boolean contains(int i) + { + boolean result = current.contains(i) || iterators.anyMatch(it -> it.contains(i)); + release(); + return result; + } + + @Override + public OptionalInt max() + { + if (!hasNext()) { + return OptionalInt.empty(); + } + int max = current.max().getAsInt(); + max = iterators.reduce(max, (int m, FunctionalPrimitiveIterator.OfInt it) -> Math.max(m, it.max().orElse(m))); + release(); + return OptionalInt.of(max); + } + + @Override + public OptionalInt min() + { + if (!hasNext()) { + return OptionalInt.empty(); + } + int min = current.min().getAsInt(); + min = iterators.reduce(min, (int m, FunctionalPrimitiveIterator.OfInt it) -> Math.min(m, it.min().orElse(m))); + release(); + return OptionalInt.of(min); + } + + @Override + public long sum() + { + long sum = iterators.reduce(current.sum(), (long s, FunctionalPrimitiveIterator.OfInt it) -> s + it.sum()); + release(); + return sum; + } + + @Override + public void release() + { + super.release(); + current = EmptyIterator.ofInt(); + } + } + + + + /** + * Primitive specialisation for {@code long} of a chained iterator. + */ + public static class OfLong extends ChainedIterator implements FunctionalPrimitiveIterator.OfLong + { + /** + * Constructor for an Iterator that chains Iterators provided in an Iterator. + * + * @param iterators an Iterator over Iterators to be chained + */ + public OfLong(Iterator iterators) + { + super(iterators); + } + + /** + * Constructor for chaining an Iterator and a number of Iterators provided in an Iterator. + * + * @param iterator an Iterator to prepend the chain + * @param iterators an Iterator over Iterators to be chained + */ + public OfLong(PrimitiveIterator.OfLong iterator, Iterator iterators) + { + super(iterator, iterators); + } + + @Override + public long nextLong() + { + requireNext(); + return current.nextLong(); + } + + @Override + public boolean contains(long l) + { + boolean result = current.contains(l) || iterators.anyMatch(it -> it.contains(l)); + release(); + return result; + } + + @Override + public OptionalLong max() + { + if (!hasNext()) { + return OptionalLong.empty(); + } + long max = current.max().getAsLong(); + max = iterators.reduce(max, (long m, FunctionalPrimitiveIterator.OfLong it) -> Math.max(m, it.max().orElse(m))); + release(); + return OptionalLong.of(max); + } + + @Override + public OptionalLong min() + { + if (!hasNext()) { + return OptionalLong.empty(); + } + long min = current.min().getAsLong(); + min = iterators.reduce(min, (long m, FunctionalPrimitiveIterator.OfLong it) -> Math.min(m, it.min().orElse(m))); + release(); + return OptionalLong.of(min); + } + + @Override + public long sum() + { + long sum = iterators.reduce(current.sum(), (long s, FunctionalPrimitiveIterator.OfLong it) -> s + it.sum()); + release(); + return sum; + } + + @Override + public void release() + { + super.release(); + current = EmptyIterator.ofLong(); + } + } +} diff --git a/prism/src/common/iterable/Distinct.java b/prism/src/common/iterable/Distinct.java new file mode 100644 index 0000000000..7ca672f3ea --- /dev/null +++ b/prism/src/common/iterable/Distinct.java @@ -0,0 +1,164 @@ +//============================================================================== +// +// Copyright (c) 2020- +// Authors: +// * Steffen Maercker (TU Dresden) +// +//------------------------------------------------------------------------------ +// +// This file is part of PRISM. +// +// PRISM is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// PRISM 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 for more details. +// +// You should have received a copy of the GNU General Public License +// along with PRISM; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//============================================================================== + +package common.iterable; + +import java.util.HashSet; +import java.util.Set; +import java.util.function.DoublePredicate; +import java.util.function.IntPredicate; +import java.util.function.LongPredicate; +import java.util.function.Predicate; + +/** + * Mutable predicate that tells whether it encounters an element the first time or not. + * + * @param the type of the objects this predicate tests + */ +public abstract class Distinct +{ + protected final Set seen = new HashSet<>(); + + /** + * Answer whether the element has not been seen yet. + * + * @param element the element to be tested + * @return true iff the element has not been seen yet + */ + protected boolean isUnseen(E element) + { + return seen.add(element); + } + + /** + * Answer the elements that have already been seen. + */ + public abstract FunctionalIterable getSeen(); + + + + /** + * Mutable predicate for {@code Object} that tells whether it encounters an element the first time or not. + * Elements are identified in terms of {@link Object#equals(Object)} which requires to be accompanied by a matching {@link Object#hashCode()} implementation. + * This implementation uses a {@code HashSet} to store the elements it has already seen. + * + * @param the type of the objects this predicate tests + */ + public static class Of extends Distinct implements Predicate + { + @Override + public boolean test(E element) + { + return super.isUnseen(element); + } + + @Override + public FunctionalIterable getSeen() + { + return Reducible.extend(seen); + } + + } + + + + /** + * Mutable predicate for {@code double} that tells whether it encounters an element the first time or not. + * Elements are identified in terms of {@link ==} except for {@code NaN} for which all instances are consider equal, although {@code Double.NaN != Double.NaN}. + * This implementation uses a {@code HashSet} to store the elements it has already seen. + */ + public static class OfDouble extends Distinct implements DoublePredicate + { + boolean zeroSeen = false; + + @Override + public boolean test(double value) + { + if (value == 0.0) { + // Circumvent HashSet considering +0.0 != -0.0 + if (zeroSeen) { + return false; + } else { + zeroSeen = true; + seen.add(value); + return true; + } + } + // HashSet considers two Double.NaN instances to be equal + return super.isUnseen(value); + } + + @Override + public FunctionalPrimitiveIterable.OfDouble getSeen() + { + return Reducible.unboxDouble(seen); + } + } + + + + /** + * Mutable predicate for {@code int} that tells whether it encounters an element the first time or not. + * Elements are identified in terms of {@link ==}. + * This implementation uses a {@code HashSet} to store the elements it has already seen. + */ + public static class OfInt extends Distinct implements IntPredicate + { + @Override + public boolean test(int value) + { + return super.isUnseen(value); + } + + @Override + public FunctionalPrimitiveIterable.OfInt getSeen() + { + return Reducible.unboxInt(seen); + } + } + + + + /** + * Mutable predicate for {@code long} that tells whether it encounters an element the first time or not. + * Elements are identified in terms of {@link ==}. + * This implementation uses a {@code HashSet} to store the elements it has already seen. + */ + public static class OfLong extends Distinct implements LongPredicate + { + @Override + public boolean test(long value) + { + return super.isUnseen(value); + } + + @Override + public FunctionalPrimitiveIterable.OfLong getSeen() + { + return Reducible.unboxLong(seen); + } + } +} diff --git a/prism/src/common/iterable/EmptyIterable.java b/prism/src/common/iterable/EmptyIterable.java index 31b66316e7..5cef8008bc 100644 --- a/prism/src/common/iterable/EmptyIterable.java +++ b/prism/src/common/iterable/EmptyIterable.java @@ -2,7 +2,7 @@ // // Copyright (c) 2016- // Authors: -// * Steffen Maercker (TU Dresden) +// * Steffen Maercker (TU Dresden) // * Joachim Klein (TU Dresden) // //------------------------------------------------------------------------------ @@ -25,75 +25,139 @@ // //============================================================================== - package common.iterable; -import java.util.Iterator; - /** - * Base class for Iterables returning empty iterators, - * static helpers for common primitive iterators. + * Abstract base class for empty Iterables. + * The four natural implementations (generic, double, int, and long) + * are implemented as Singletons and their instances accessible by a static method. + * + * @param type of the Iterable's elements */ -public abstract class EmptyIterable implements Iterable +public abstract class EmptyIterable implements FunctionalIterable { - private static final Of OF = new Of<>(); - private static final OfInt OF_INT = new OfInt(); - private static final OfDouble OF_DOUBLE = new OfDouble(); - + /** + * Get unique instance for elements of a generic type. + * + * @param type of the Iterable's elements + */ @SuppressWarnings("unchecked") - public static Of Of() { - return (Of) OF; + public static Of of() + { + return (Of) Of.OF; } - public static OfInt OfInt() { - return OF_INT; + /** + * Get unique instance for {@code double} elements. + */ + public static OfDouble ofDouble() + { + return OfDouble.OF_DOUBLE; } - public static OfDouble OfDouble() { - return OF_DOUBLE; + /** + * Get unique instance for {@code int} elements. + */ + public static OfInt ofInt() + { + return OfInt.OF_INT; } - public static class Of extends EmptyIterable + /** + * Get unique instance for {@code long} elements. + */ + public static OfLong ofLong() { - private Of() {}; + return OfLong.OF_LONG; + } + + + + /** + * Generic implementation of an empty Iterable as Singleton. + * + * @param type of the Iterable's elements + */ + public static class Of extends EmptyIterable + { + /** Singleton instance elements of a generic type */ + private static final Of OF = new Of<>(); + + /** + * Private constructor for the Singleton instance. + */ + private Of() {} @Override - public Iterator iterator() + public EmptyIterator.Of iterator() { - return EmptyIterator.Of(); + return EmptyIterator.of(); } } - public static class OfInt extends EmptyIterable implements IterableInt + + + /** + * Primitive specialisation for {@code double} of an empty Iterable as Singleton. + */ + public static class OfDouble extends EmptyIterable implements FunctionalPrimitiveIterable.OfDouble { - private OfInt() {}; + /** Singleton instance for {@code double} elements */ + private static final EmptyIterable.OfDouble OF_DOUBLE = new EmptyIterable.OfDouble(); + /** + * Private constructor for the Singleton instance. + */ + private OfDouble() {} + @Override - public EmptyIterator.OfInt iterator() + public EmptyIterator.OfDouble iterator() { - return EmptyIterator.OfInt(); + return EmptyIterator.ofDouble(); } } - public static class OfLong extends EmptyIterable implements IterableLong + + + /** + * Primitive specialisation for {@code int} of an empty Iterable as Singleton. + */ + public static class OfInt extends EmptyIterable implements FunctionalPrimitiveIterable.OfInt { - private OfLong() {}; + /** Singleton instance for {@code int} elements */ + private static final EmptyIterable.OfInt OF_INT = new EmptyIterable.OfInt(); + + /** + * Private constructor for the Singleton instance. + */ + private OfInt() {} @Override - public EmptyIterator.OfLong iterator() + public EmptyIterator.OfInt iterator() { - return EmptyIterator.OfLong(); + return EmptyIterator.ofInt(); } } - public static class OfDouble extends EmptyIterable implements IterableDouble + + + /** + * Primitive specialisation for {@code long} of an empty Iterable as Singleton. + */ + public static class OfLong extends EmptyIterable implements FunctionalPrimitiveIterable.OfLong { - private OfDouble() {}; + /** Singleton instance for {@code long} elements*/ + private static final EmptyIterable.OfLong OF_LONG = new EmptyIterable.OfLong(); + + /** + * Private constructor for the Singleton instance. + */ + private OfLong() {} @Override - public EmptyIterator.OfDouble iterator() + public EmptyIterator.OfLong iterator() { - return EmptyIterator.OfDouble(); + return EmptyIterator.ofLong(); } } -} +} \ No newline at end of file diff --git a/prism/src/common/iterable/EmptyIterator.java b/prism/src/common/iterable/EmptyIterator.java index c468648e4d..2c0e3d5673 100644 --- a/prism/src/common/iterable/EmptyIterator.java +++ b/prism/src/common/iterable/EmptyIterator.java @@ -2,7 +2,7 @@ // // Copyright (c) 2016- // Authors: -// * Steffen Maercker (TU Dresden) +// * Steffen Maercker (TU Dresden) // * Joachim Klein (TU Dresden) // //------------------------------------------------------------------------------ @@ -27,36 +27,53 @@ package common.iterable; -import java.util.Iterator; import java.util.NoSuchElementException; -import java.util.PrimitiveIterator; +import java.util.OptionalDouble; +import java.util.OptionalInt; +import java.util.OptionalLong; /** - * Base class for empty Iterators, - * static helpers for common primitive iterators. + * Abstract base class for empty Iterators. + * The four natural implementations (generic, double, int, and long) + * are implemented as Singletons and their instances accessible by a static method. + * + * @param type of the Iterator's elements */ -public abstract class EmptyIterator implements Iterator +public abstract class EmptyIterator implements FunctionalIterator { - private static final Of OF = new Of<>(); - private static final OfInt OF_INT = new OfInt(); - private static final OfLong OF_LONG = new OfLong(); - private static final OfDouble OF_DOUBLE = new OfDouble(); - + /** + * Get unique instance for elements of a generic type. + * + * @param type of the Iterator's elements + */ @SuppressWarnings("unchecked") - public static Of Of() { - return (Of) OF; + public static Of of() + { + return (Of) Of.OF; } - public static OfInt OfInt() { - return OF_INT; + /** + * Get unique instance for {@code double} elements. + */ + public static OfDouble ofDouble() + { + return OfDouble.OF_DOUBLE; } - public static OfLong OfLong() { - return OF_LONG; + /** + * Get unique instance for {@code int} elements. + */ + public static OfInt ofInt() + { + return OfInt.OF_INT; } - public static OfDouble OfDouble() { - return OF_DOUBLE; + /** + * Get unique instance for {@code long} elements. + */ + public static OfLong ofLong() + { + return OfLong.OF_LONG; } @Override @@ -65,47 +82,195 @@ public boolean hasNext() return false; } - public static class Of extends EmptyIterator + @Override + public EmptyIterator dedupe() + { + return this; + } + + @Override + public EmptyIterator distinct() { - private Of() {}; + return this; + } + + + + /** + * Generic implementation of an empty Iterator as Singleton. + * + * @param type of the Iterator's elements + */ + public static class Of extends EmptyIterator + { + /** Singleton instance elements of a generic type */ + private static final Of OF = new Of<>(); + + /** + * Private constructor for the Singleton instance. + */ + private Of() {} @Override - public T next() + public E next() { throw new NoSuchElementException(); } } - public static class OfInt extends EmptyIterator implements PrimitiveIterator.OfInt + + + /** + * Primitive specialisation for {@code double} of an empty Iterator as Singleton. + */ + public static class OfDouble extends EmptyIterator implements FunctionalPrimitiveIterator.OfDouble { - private OfInt() {}; + /** Singleton instance for {@code double} elements */ + private static final EmptyIterator.OfDouble OF_DOUBLE = new EmptyIterator.OfDouble(); + + /** + * Private constructor for the Singleton instance. + */ + private OfDouble() {} @Override - public int nextInt() + public double nextDouble() { throw new NoSuchElementException(); } + + @Override + public EmptyIterator.OfDouble dedupe() + { + return this; + } + + @Override + public EmptyIterator.OfDouble distinct() + { + return this; + } + + @Override + public OptionalDouble max() + { + return OptionalDouble.empty(); + } + + @Override + public OptionalDouble min() + { + return max(); + } + + @Override + public double sum() + { + return 0.0; + } } - public static class OfLong extends EmptyIterator implements PrimitiveIterator.OfLong + + + /** + * Primitive specialisation for {@code int} of an empty Iterator as Singleton. + */ + public static class OfInt extends EmptyIterator implements FunctionalPrimitiveIterator.OfInt { - private OfLong() {}; + /** Singleton instance for {@code int} elements */ + private static final EmptyIterator.OfInt OF_INT = new EmptyIterator.OfInt(); + + /** + * Private constructor for the Singleton instance. + */ + private OfInt() {} @Override - public long nextLong() + public int nextInt() { throw new NoSuchElementException(); } + + @Override + public EmptyIterator.OfInt dedupe() + { + return this; + } + + @Override + public EmptyIterator.OfInt distinct() + { + return this; + } + + @Override + public OptionalInt max() + { + return OptionalInt.empty(); + } + + @Override + public OptionalInt min() + { + return max(); + } + + @Override + public long sum() + { + return 0; + } } - public static class OfDouble extends EmptyIterator implements PrimitiveIterator.OfDouble + + + /** + * Primitive specialisation for {@code long} of an empty Iterator as Singleton. + */ + public static class OfLong extends EmptyIterator implements FunctionalPrimitiveIterator.OfLong { - private OfDouble() {}; + /** Singleton instance for {@code long} elements*/ + private static final EmptyIterator.OfLong OF_LONG = new EmptyIterator.OfLong(); + + /** + * Private constructor for the Singleton instance. + */ + private OfLong() {} @Override - public double nextDouble() + public long nextLong() { throw new NoSuchElementException(); } + + @Override + public EmptyIterator.OfLong dedupe() + { + return this; + } + + @Override + public EmptyIterator.OfLong distinct() + { + return this; + } + + @Override + public OptionalLong max() + { + return OptionalLong.empty(); + } + + @Override + public OptionalLong min() + { + return max(); + } + + @Override + public long sum() + { + return 0; + } } } diff --git a/prism/src/common/iterable/FilteringIterable.java b/prism/src/common/iterable/FilteringIterable.java index b161b2e9c3..c3300c9bfd 100644 --- a/prism/src/common/iterable/FilteringIterable.java +++ b/prism/src/common/iterable/FilteringIterable.java @@ -2,7 +2,7 @@ // // Copyright (c) 2016- // Authors: -// * Steffen Maercker (TU Dresden) +// * Steffen Maercker (TU Dresden) // * Joachim Klein (TU Dresden) // //------------------------------------------------------------------------------ @@ -27,138 +27,162 @@ package common.iterable; -import java.util.Iterator; -import java.util.PrimitiveIterator; +import java.util.Objects; import java.util.function.DoublePredicate; import java.util.function.IntPredicate; import java.util.function.LongPredicate; import java.util.function.Predicate; /** - * Base class for Iterables around FilteringIterators, - * static constructors for deduplicating entries. */ -public abstract class FilteringIterable implements Iterable + * Abstract base class for Iterables that filter elements by a predicate. + * Returns only those elements for which the filter predicate evaluates to {@code true}. + * + * @param type of the Iterable's elements + * @param type of the underlying Iterable + */ +public abstract class FilteringIterable> implements FunctionalIterable { - protected final Iterable iterable; - - public FilteringIterable(final Iterable iterable) + /** The Iterable which elements are filtered */ + protected final I iterable; + + /** + * Constructor for a filtering Iterable without a predicate. + * + * @param iterable an Iterable to be filtered + */ + public FilteringIterable(I iterable) { + Objects.requireNonNull(iterable); this.iterable = iterable; } - public static class Of extends FilteringIterable - { - private Predicate predicate; - public Of(Iterable iterable, Predicate predicate) - { - super(iterable); - this.predicate = predicate; - } - @Override - public Iterator iterator() - { - return new FilteringIterator.Of<>(iterable, predicate); - } - } - - public static class OfInt extends FilteringIterable implements IterableInt + /** + * Generic implementation of a filtering Iterable. + * + * @param type of the Iterable's elements + */ + public static class Of extends FilteringIterable> { - private IntPredicate predicate; - - public OfInt(IterableInt iterable, IntPredicate predicate) + /** The predicate the Iterable uses to filter the elements */ + protected final Predicate filter; + + /** + * Constructor for an Iterable that filters elements by a predicate. + *

+ * Attention! If the predicate is stateful, subsequent iterations may yield different elements. + * + * @param iterable an Iterable to be filtered + * @param predicate a predicate used to filter the elements + */ + public Of(Iterable iterable, Predicate predicate) { super(iterable); - this.predicate = predicate; + Objects.requireNonNull(predicate); + this.filter = predicate; } @Override - public PrimitiveIterator.OfInt iterator() + public FunctionalIterator iterator() { - return new FilteringIterator.OfInt((IterableInt) iterable, predicate); + return new FilteringIterator.Of<>(iterable.iterator(), filter); } } - public static class OfLong extends FilteringIterable implements IterableLong - { - private LongPredicate predicate; - public OfLong(IterableLong iterable, LongPredicate predicate) + + /** + * Primitive specialisation for {@code double} of a filtering Iterable. + */ + public static class OfDouble extends FilteringIterable implements FunctionalPrimitiveIterable.OfDouble + { + /** The predicate the Iterable uses to filter the elements */ + protected final DoublePredicate filter; + + /** + * Constructor for an Iterable that filters elements by a predicate. + *

+ * Attention! If the predicate is stateful, subsequent iterations may yield different elements. + * + * @param iterable an Iterable to be filtered + * @param predicate a predicate used to filter the elements + */ + public OfDouble(PrimitiveIterable.OfDouble iterable, DoublePredicate predicate) { super(iterable); - this.predicate = predicate; + Objects.requireNonNull(predicate); + this.filter = predicate; } @Override - public PrimitiveIterator.OfLong iterator() + public FunctionalPrimitiveIterator.OfDouble iterator() { - return new FilteringIterator.OfLong((IterableLong) iterable, predicate); + return new FilteringIterator.OfDouble(iterable.iterator(), filter); } } - public static class OfDouble extends FilteringIterable implements IterableDouble - { - private DoublePredicate predicate; - public OfDouble(IterableDouble iterable, DoublePredicate predicate) + + /** + * Primitive specialisation for {@code int} of a filtering Iterable. + */ + public static class OfInt extends FilteringIterable implements FunctionalPrimitiveIterable.OfInt + { + /** The predicate the Iterable uses to filter the elements */ + protected final IntPredicate filter; + + /** + * Constructor for an Iterable that filters elements by a predicate. + *

+ * Attention! If the predicate is stateful, subsequent iterations may yield different elements. + * + * @param iterable an Iterable to be filtered + * @param predicate a predicate used to filter the elements + */ + public OfInt(PrimitiveIterable.OfInt iterable, IntPredicate predicate) { super(iterable); - this.predicate = predicate; + Objects.requireNonNull(predicate); + this.filter = predicate; } @Override - public PrimitiveIterator.OfDouble iterator() + public FunctionalPrimitiveIterator.OfInt iterator() { - return new FilteringIterator.OfDouble((IterableDouble) iterable, predicate); + return new FilteringIterator.OfInt(iterable.iterator(), filter); } } - public static IterableInt dedupe(IterableInt iterable) - { - return new IterableInt() - { - @Override - public PrimitiveIterator.OfInt iterator() - { - return FilteringIterator.dedupe(iterable.iterator()); - } - }; - } - public static IterableLong dedupe(IterableLong iterable) - { - return new IterableLong() - { - @Override - public PrimitiveIterator.OfLong iterator() - { - return FilteringIterator.dedupe(iterable.iterator()); - } - }; - } - public static IterableDouble dedupe(IterableDouble iterable) + /** + * Primitive specialisation for {@code long} of a filtering Iterable. + */ + public static class OfLong extends FilteringIterable implements FunctionalPrimitiveIterable.OfLong { - return new IterableDouble() + /** The predicate the Iterable uses to filter the elements */ + protected final LongPredicate filter; + + /** + * Constructor for an Iterable that filters elements by a predicate. + *

+ * Attention! If the predicate is stateful, subsequent iterations may yield different elements. + * + * @param iterable an Iterable to be filtered + * @param predicate a predicate used to filter the elements + */ + public OfLong(PrimitiveIterable.OfLong iterable, LongPredicate predicate) { - @Override - public PrimitiveIterator.OfDouble iterator() - { - return FilteringIterator.dedupe(iterable.iterator()); - } - }; - } + super(iterable); + Objects.requireNonNull(predicate); + this.filter = predicate; + } - public static Iterable dedupe(Iterable iterable) - { - return new Iterable() + @Override + public FunctionalPrimitiveIterator.OfLong iterator() { - @Override - public Iterator iterator() - { - return FilteringIterator.dedupe(iterable.iterator()); - } - }; + return new FilteringIterator.OfLong(iterable.iterator(), filter); + } } } diff --git a/prism/src/common/iterable/FilteringIterator.java b/prism/src/common/iterable/FilteringIterator.java index f5e1904e97..5b8ae4fdc5 100644 --- a/prism/src/common/iterable/FilteringIterator.java +++ b/prism/src/common/iterable/FilteringIterator.java @@ -2,7 +2,7 @@ // // Copyright (c) 2016- // Authors: -// * Steffen Maercker (TU Dresden) +// * Steffen Maercker (TU Dresden) // * Joachim Klein (TU Dresden) // //------------------------------------------------------------------------------ @@ -27,46 +27,44 @@ package common.iterable; -import java.util.HashSet; import java.util.Iterator; -import java.util.NoSuchElementException; import java.util.Objects; import java.util.PrimitiveIterator; -import java.util.Set; import java.util.function.DoublePredicate; import java.util.function.IntPredicate; import java.util.function.LongPredicate; import java.util.function.Predicate; /** - * Base class for filtering iterators, - * static helpers for common filtering task (deduping). + * Abstract base class implementing an Iterator that filters elements by a predicate. + * Returns only those elements for which the filter predicate evaluates to {@code true}. + *

+ * The calls to {@code next()} of the underlying Iterator happen on-the-fly, + * i.e., only when {@code next()} is called for this Iterator. + *

+ * Implementations should release the underlying Iterator after iteration. + *

+ * This Iterator does not support the {@code remove()} method, even if the underlying + * Iterator support it. + * + * @param type of the Iterator's elements + * @param type of the underlying Iterator */ -public abstract class FilteringIterator implements Iterator +public abstract class FilteringIterator> implements FunctionalIterator { - protected final Iterator iterator; + /** The Iterator which elements are filtered */ + protected I iterator; + /** A flag indicating whether another element exists */ protected boolean hasNext; - public static Iterator nonNull(Iterable iterable) - { - return nonNull(iterable.iterator()); - } - - public static Iterator nonNull(Iterator iterator) - { - if (iterator instanceof PrimitiveIterator) { - return iterator; - } - return new FilteringIterator.Of<>(iterator, Objects::nonNull); - } - - public FilteringIterator(final Iterable iterable) - { - this(iterable.iterator()); - } - - public FilteringIterator(final Iterator iterator) + /** + * Constructor for a FilteringIterator without a predicate. + * + * @param iterator an Iterator to be filtered + */ + public FilteringIterator(I iterator) { + Objects.requireNonNull(iterator); this.iterator = iterator; } @@ -76,166 +74,184 @@ public boolean hasNext() return hasNext; } - protected void requireNext() + @Override + public void release() { - if (!hasNext) { - throw new NoSuchElementException(); - } + hasNext = false; } /** - * Obtain filtering iterator for the given iterator, - * filtering duplicate elements (via HashSet, requires - * that {@code equals()} and {@code hashCode()} are properly - * implemented). + * Seek and store the next element for which the filter evaluates to {@code true}. */ - public static Iterator dedupe(final Iterator iterator) - { - final Set elements = new HashSet<>(); - return new FilteringIterator.Of<>(iterator, (Predicate) elements::add); - } + protected abstract void seekNext(); + - /** - * Obtain filtering iterator for the given primitive int iterator, - * filtering duplicate elements (via HashSet). - */ - public static OfInt dedupe(final PrimitiveIterator.OfInt iterator) - { - // TODO: use BitSet? Evaluate performance in practice... - final Set elements = new HashSet<>(); - return new FilteringIterator.OfInt(iterator, (IntPredicate) elements::add); - } - /** - * Obtain filtering iterator for the given primitive long iterator, - * filtering duplicate elements (via HashSet). - */ - public static OfLong dedupe(final PrimitiveIterator.OfLong iterator) - { - final Set elements = new HashSet<>(); - return new FilteringIterator.OfLong(iterator, (LongPredicate) elements::add); - } /** - * Obtain filtering iterator for the given primitive double iterator, - * filtering duplicate elements (via HashSet). + * Generic implementation of a FilteringIterator. + * + * @param type of the Iterable's elements */ - public static OfDouble dedupe(final PrimitiveIterator.OfDouble iterator) - { - final Set elements = new HashSet<>(); - return new FilteringIterator.OfDouble(iterator, (DoublePredicate) elements::add); - } - - public static class Of extends FilteringIterator + public static class Of extends FilteringIterator> { - protected final Predicate predicate; - private T next; - - public Of(Iterable iterable, Predicate predicate) - { - this(iterable.iterator(), predicate); - } - - public Of(Iterator iterator, Predicate predicate) + /** The predicate the Iterator uses to filter the elements */ + protected final Predicate filter; + /** The next element for which the filter predicates evaluates to {@code true} */ + protected E next; + + /** + * Constructor for an Iterator that filters elements by a predicate. + * + * @param iterator an Iterator to be filtered + * @param predicate a predicate used to filter the elements + */ + @SuppressWarnings("unchecked") + public Of(Iterator iterator, Predicate predicate) { super(iterator); - this.predicate = predicate; + Objects.requireNonNull(predicate); + this.filter = (Predicate) predicate; seekNext(); } @Override - public T next() + public E next() { requireNext(); - T current = next; + E current = next; seekNext(); return current; } - private void seekNext() + @Override + public void release() + { + super.release(); + iterator = EmptyIterator.of(); + next = null; + } + + @Override + protected void seekNext() { while (iterator.hasNext()) { next = iterator.next(); - if (predicate.test(next)) { + if (filter.test(next)) { hasNext = true; return; } } - hasNext = false; - next = null; + release(); } } - public static class OfInt extends FilteringIterator implements PrimitiveIterator.OfInt - { - protected final IntPredicate predicate; - private int next; - public OfInt(IterableInt iterable, IntPredicate predicate) - { - this(iterable.iterator(), predicate); - } - public OfInt(PrimitiveIterator.OfInt iterator, IntPredicate predicate) + /** + * Primitive specialisation for {@code double} of a FilteringIterator. + */ + public static class OfDouble extends FilteringIterator implements FunctionalPrimitiveIterator.OfDouble + { + /** The predicate the Iterator uses to filter the elements */ + protected final DoublePredicate filter; + /** The next element for which the filter predicates evaluates to {@code true} */ + protected double next; + + /** + * Constructor for an Iterator that filters elements by a predicate. + * + * @param iterator an Iterator to be filtered + * @param predicate a predicate used to filter the elements + */ + public OfDouble(PrimitiveIterator.OfDouble iterator, DoublePredicate predicate) { super(iterator); - this.predicate = predicate; + Objects.requireNonNull(predicate); + this.filter = predicate; seekNext(); } @Override - public int nextInt() + public double nextDouble() { requireNext(); - int current = next; + double current = next; seekNext(); return current; } - private void seekNext() + @Override + public void release() + { + super.release(); + iterator = EmptyIterator.ofDouble(); + next = 0.0; + } + + @Override + protected void seekNext() { while (iterator.hasNext()) { - next = ((PrimitiveIterator.OfInt) iterator).nextInt(); - if (predicate.test(next)) { + next = iterator.nextDouble(); + if (filter.test(next)) { hasNext = true; return; } } - hasNext = false; + release(); } } - public static class OfLong extends FilteringIterator implements PrimitiveIterator.OfLong - { - protected final LongPredicate predicate; - private long next; - public OfLong(IterableLong iterable, LongPredicate predicate) - { - this(iterable.iterator(), predicate); - } - public OfLong(PrimitiveIterator.OfLong iterator, LongPredicate predicate) + /** + * Primitive specialisation for {@code int} of a FilteringIterator. + */ + public static class OfInt extends FilteringIterator implements FunctionalPrimitiveIterator.OfInt + { + /** The predicate the Iterator uses to filter the elements */ + protected final IntPredicate filter; + /** The next element for which the filter predicates evaluates to {@code true} */ + protected int next; + + /** + * Constructor for an Iterator that filters elements by a predicate. + * + * @param iterator an Iterator to be filtered + * @param predicate a predicate used to filter the elements + */ + public OfInt(PrimitiveIterator.OfInt iterator, IntPredicate predicate) { super(iterator); - this.predicate = predicate; + Objects.requireNonNull(predicate); + this.filter = predicate; seekNext(); } @Override - public long nextLong() + public int nextInt() { requireNext(); - long current = next; + int current = next; seekNext(); return current; } - private void seekNext() + @Override + public void release() + { + super.release(); + iterator = EmptyIterator.ofInt(); + next = 0; + } + + @Override + protected void seekNext() { while (iterator.hasNext()) { - next = ((PrimitiveIterator.OfLong) iterator).nextLong(); - if (predicate.test(next)) { + next = iterator.nextInt(); + if (filter.test(next)) { hasNext = true; return; } @@ -244,37 +260,54 @@ private void seekNext() } } - public static class OfDouble extends FilteringIterator implements PrimitiveIterator.OfDouble - { - protected final DoublePredicate predicate; - private double next; - public OfDouble(IterableDouble iterable, DoublePredicate predicate) - { - this(iterable.iterator(), predicate); - } - - public OfDouble(PrimitiveIterator.OfDouble iterator, DoublePredicate predicate) + /** + * Primitive specialisation for {@code long} of a FilteringIterator. + */ + public static class OfLong extends FilteringIterator implements FunctionalPrimitiveIterator.OfLong + { + /** The predicate the Iterator uses to filter the elements */ + protected final LongPredicate filter; + /** The next element for which the filter predicates evaluates to {@code true} */ + protected long next; + + /** + * Constructor for an Iterator that filters elements by a predicate. + * + * @param iterator an Iterator to be filtered + * @param predicate a predicate used to filter the elements + */ + public OfLong(PrimitiveIterator.OfLong iterator, LongPredicate predicate) { super(iterator); - this.predicate = predicate; + Objects.requireNonNull(predicate); + this.filter = predicate; seekNext(); } @Override - public double nextDouble() + public long nextLong() { requireNext(); - double current = next; + long current = next; seekNext(); return current; } - private void seekNext() + @Override + public void release() + { + super.release(); + iterator = EmptyIterator.ofLong(); + next = 0; + } + + @Override + protected void seekNext() { while (iterator.hasNext()) { - next = ((PrimitiveIterator.OfDouble) iterator).nextDouble(); - if (predicate.test(next)) { + next = iterator.nextLong(); + if (filter.test(next)) { hasNext = true; return; } diff --git a/prism/src/common/iterable/FunctionalIterable.java b/prism/src/common/iterable/FunctionalIterable.java new file mode 100644 index 0000000000..0c3a157a6a --- /dev/null +++ b/prism/src/common/iterable/FunctionalIterable.java @@ -0,0 +1,271 @@ +//============================================================================== +// +// Copyright (c) 2016- +// Authors: +// * Steffen Maercker (TU Dresden) +// +//------------------------------------------------------------------------------ +// +// This file is part of PRISM. +// +// PRISM is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// PRISM 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 for more details. +// +// You should have received a copy of the GNU General Public License +// along with PRISM; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//============================================================================== + +package common.iterable; + +import common.functions.DoubleObjToDoubleFunction; +import common.functions.IntObjToIntFunction; +import common.functions.LongObjToLongFunction; + +import java.util.Optional; +import java.util.function.*; + +/** + * A base type that implements the transformation and accumulation operations from {@link Reducible} for {@link Iterable}s. + * Additionally, it provides the methods {@link FunctionalIterable#flatMap} and its primitive specializations + * {@link FunctionalIterable#flatMapToDouble}, {@link FunctionalIterable#flatMapToInt} and {@link FunctionalIterable#flatMapToLong}. + * + * @param the type of elements returned by this Iterable + */ +public interface FunctionalIterable extends Reducible>, Iterable +{ + // Bridging methods to Iterator-based code + + /** + * Create a FunctionalIterable over the given elements. + * + * @param elements the elements + * @param the type of the elements + * @return a FunctionalIterable over the elements + */ + @SafeVarargs + static FunctionalIterable of(E ... elements) + { + switch (elements.length) { + case 0: return EmptyIterable.of(); + case 1: return new SingletonIterable.Of<>(elements[0]); + default: return new IterableArray.Of<>(elements); + } + } + + /** + * Create a FunctionalPrimitiveIterable.OfDouble over the given doubles. + * + * @param numbers the doubles + * @return a FunctionalPrimitiveIterable.OfDouble over the doubles + */ + static FunctionalPrimitiveIterable.OfDouble ofDouble(double ... numbers) + { + switch (numbers.length) { + case 0: return EmptyIterable.ofDouble(); + case 1: return new SingletonIterable.OfDouble(numbers[0]); + default: return new IterableArray.OfDouble(numbers); + } + } + + /** + * Create a FunctionalPrimitiveIterable.OfInt over the given ints. + * + * @param numbers the ints + * @return a FunctionalPrimitiveIterable.OfInt over the ints + */ + static FunctionalPrimitiveIterable.OfInt ofInt(int ... numbers) + { + switch (numbers.length) { + case 0: return EmptyIterable.ofInt(); + case 1: return new SingletonIterable.OfInt(numbers[0]); + default: return new IterableArray.OfInt(numbers); + } + } + + /** + * Create a FunctionalPrimitiveIterable.OfLong over the given longs. + * + * @param numbers the longs + * @return a FunctionalPrimitiveIterable.OfLong over the longs + */ + static FunctionalPrimitiveIterable.OfLong ofLong(long ... numbers) + { + switch (numbers.length) { + case 0: return EmptyIterable.ofLong(); + case 1: return new SingletonIterable.OfLong(numbers[0]); + default: return new IterableArray.OfLong(numbers); + } + } + + + + // Fundamental methods + + @Override + FunctionalIterator iterator(); + + @Override + default void forEach(Consumer action) + { + iterator().forEach(action); + } + + @Override + default boolean isEmpty() + { + return !iterator().hasNext(); + } + + + + // Transforming Methods + + @Override + default FunctionalIterable concat(Iterable iterable) + { + return new ChainedIterable.Of<>(new IterableArray.Of<>(this, iterable)); + } + + @Override + default FunctionalIterable dedupe() + { + return (FunctionalIterable) Reducible.super.dedupe(); + } + + @Override + default FunctionalIterable distinct() + { + return (FunctionalIterable) Reducible.super.distinct(); + } + + @Override + default FunctionalIterable filter(Predicate predicate) + { + return new FilteringIterable.Of<>(this, predicate); + } + + /** + * Map each element to an Iterable and concatenate the obtained Iterables. + * + * @param function a function that maps each element to an {@link Iterable} + */ + default FunctionalIterable flatMap(Function> function) + { + return new ChainedIterable.Of<>(map(function)); + } + + /** + * Map each element to an FunctionalPrimitiveIterable.OfDouble and concatenate the obtained Iterables. + * + * @param function a function that maps each element to an {@link FunctionalPrimitiveIterable.OfDouble} + */ + default FunctionalPrimitiveIterable.OfDouble flatMapToDouble(Function function) + { + return new ChainedIterable.OfDouble(map(function)); + } + + /** + * Map each element to an FunctionalPrimitiveIterable.OfInt and concatenate the obtained Iterables. + * + * @param function a function that maps each element to an {@link FunctionalPrimitiveIterable.OfInt} + */ + default FunctionalPrimitiveIterable.OfInt flatMapToInt(Function function) + { + return new ChainedIterable.OfInt(map(function)); + } + + /** + * Map each element to an FunctionalPrimitiveIterable.OfLong and concatenate the obtained Iterables. + * + * @param function a function that maps each element to an {@link FunctionalPrimitiveIterable.OfLong} + */ + default FunctionalPrimitiveIterable.OfLong flatMapToLong(Function function) + { + return new ChainedIterable.OfLong(map(function)); + } + + @Override + default FunctionalIterable map(Function function) + { + return new MappingIterable.ObjToObj<>(this, function); + } + + @Override + default FunctionalPrimitiveIterable.OfDouble mapToDouble(ToDoubleFunction function) + { + return new MappingIterable.ObjToDouble<>(this, function); + } + + @Override + default FunctionalPrimitiveIterable.OfInt mapToInt(ToIntFunction function) + { + return new MappingIterable.ObjToInt<>(this, function); + } + + @Override + default FunctionalPrimitiveIterable.OfLong mapToLong(ToLongFunction function) + { + return new MappingIterable.ObjToLong<>(this, function); + } + + @Override + default FunctionalIterable nonNull() + { + return (FunctionalIterable) Reducible.super.nonNull(); + } + + + + // Accumulations Methods (Consuming) + + @Override + default FunctionalIterable consume() + { + return (FunctionalIterable) Reducible.super.consume(); + } + + @Override + default E detect(Predicate predicate) + { + return iterator().detect(predicate); + } + + @Override + default Optional reduce(BinaryOperator accumulator) + { + return iterator().reduce(accumulator); + } + + @Override + default T reduce(T init, BiFunction accumulator) + { + return iterator().reduce(init, accumulator); + } + + @Override + default double reduce(double init, DoubleObjToDoubleFunction accumulator) + { + return iterator().reduce(init, accumulator); + } + + @Override + default int reduce(int init, IntObjToIntFunction accumulator) + { + return iterator().reduce(init, accumulator); + } + + @Override + default long reduce(long init, LongObjToLongFunction accumulator) + { + return iterator().reduce(init, accumulator); + } +} diff --git a/prism/src/common/iterable/FunctionalIterator.java b/prism/src/common/iterable/FunctionalIterator.java new file mode 100644 index 0000000000..552c6945b7 --- /dev/null +++ b/prism/src/common/iterable/FunctionalIterator.java @@ -0,0 +1,336 @@ +//============================================================================== +// +// Copyright (c) 2016- +// Authors: +// * Steffen Maercker (TU Dresden) +// +//------------------------------------------------------------------------------ +// +// This file is part of PRISM. +// +// PRISM is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// PRISM 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 for more details. +// +// You should have received a copy of the GNU General Public License +// along with PRISM; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//============================================================================== + +package common.iterable; + +import common.functions.DoubleObjToDoubleFunction; +import common.functions.IntObjToIntFunction; +import common.functions.LongObjToLongFunction; + +import java.util.*; +import java.util.function.*; + +/** + * A base type that implements the transformation and accumulation operations from {@link Reducible} for {@link Iterator}s. + * Additionally, it provides the methods {@link FunctionalIterator#flatMap} and its primitive specializations + * {@link FunctionalIterator#flatMapToDouble}, {@link FunctionalIterator#flatMapToInt} and {@link FunctionalIterator#flatMapToLong}. + * + * @param the type of elements returned by this Iterator + */ +public interface FunctionalIterator extends Reducible>, Iterator +{ + // Bridging methods to Iterator-based code + + /** + * Create a FunctionalIterator over the given elements. + * + * @param elements the elements + * @param the type of the elements + * @return a FunctionalIterator over the elements + */ + @SafeVarargs + static FunctionalIterator of(E ... elements) + { + switch (elements.length) { + case 0: return EmptyIterator.of(); + case 1: return new SingletonIterator.Of<>(elements[0]); + default: return new ArrayIterator.Of<>(elements); + } + } + + /** + * Create a FunctionalPrimitiveIterator.OfDouble over the given doubles. + * + * @param numbers the doubles + * @return a FunctionalPrimitiveIterator.OfDouble over the doubles + */ + static FunctionalPrimitiveIterator.OfDouble ofDouble(double ... numbers) + { + switch (numbers.length) { + case 0: return EmptyIterator.ofDouble(); + case 1: return new SingletonIterator.OfDouble(numbers[0]); + default: return new ArrayIterator.OfDouble(numbers); + } + } + + /** + * Create a FunctionalPrimitiveIterator.OfInt over the given ints. + * + * @param numbers the ints + * @return a FunctionalPrimitiveIterator.OfInt over the ints + */ + static FunctionalPrimitiveIterator.OfInt ofInt(int ... numbers) + { + switch (numbers.length) { + case 0: return EmptyIterator.ofInt(); + case 1: return new SingletonIterator.OfInt(numbers[0]); + default: return new ArrayIterator.OfInt(numbers); + } + } + + /** + * Create a FunctionalPrimitiveIterator.OfLong over the given longs. + * + * @param numbers the longs + * @return a FunctionalPrimitiveIterator.OfLong over the longs + */ + static FunctionalPrimitiveIterator.OfLong ofLong(long ... numbers) + { + switch (numbers.length) { + case 0: return EmptyIterator.ofLong(); + case 1: return new SingletonIterator.OfLong(numbers[0]); + default: return new ArrayIterator.OfLong(numbers); + } + } + + + + // Fundamental methods + + @Override + default void forEach(Consumer action) + { + unwrap().forEachRemaining(action); + release(); + } + + @Override + default boolean isEmpty() + { + return ! hasNext(); + } + + /** + * Unwrap a nested iterator if this instance is an adapting wrapper. + * Use to avoid repeated indirections, especially in loops. + * + * @return {@code this} instance + */ + default Iterator unwrap() + { + return this; + } + + /** + * Release resources such as wrapped Iterators making this Iterator empty. + * Should be called internally after an Iterator is exhausted. + */ + default void release() + { + // no-op + } + + /** + * Check that there is a next element, throw if not. + * + * @throws NoSuchElementException if Iterator is exhausted + */ + default void requireNext() + { + if (!hasNext()) { + throw new NoSuchElementException(); + } + } + + + + // Transforming Methods + + @Override + default FunctionalIterator concat(Iterator iterator) + { + return new ChainedIterator.Of<>(unwrap(), new ArrayIterator.Of<>(iterator)); + } + + @Override + default FunctionalIterator dedupe() + { + return (FunctionalIterator) Reducible.super.dedupe(); + } + + @Override + default FunctionalIterator distinct() + { + return (FunctionalIterator) Reducible.super.distinct(); + } + + @Override + default FunctionalIterator filter(Predicate predicate) + { + return new FilteringIterator.Of<>(unwrap(), predicate); + } + + /** + * Map each element to an Iterator and concatenate the obtained Iterators. + * + * @param function a function that maps each element to an {@link Iterator} + */ + default FunctionalIterator flatMap(Function> function) + { + return new ChainedIterator.Of<>(map(function)); + } + + /** + * Map each element to a PrimitiveIterator over {@code double} and concatenate the obtained Iterators. + * + * @param function a function that maps each element to an {@link PrimitiveIterator.OfDouble} + */ + default FunctionalPrimitiveIterator.OfDouble flatMapToDouble(Function function) + { + return new ChainedIterator.OfDouble(map(function)); + } + + /** + * Map each element to a PrimitiveIterator over {@code int} and concatenate the obtained Iterators. + * + * @param function a function that maps each element to an {@link PrimitiveIterator.OfInt} + */ + default FunctionalPrimitiveIterator.OfInt flatMapToInt(Function function) + { + return new ChainedIterator.OfInt(map(function)); + } + + /** + * Map each element to a PrimitiveIterator over {@code long} and concatenate the obtained Iterators. + * + * @param function a function that maps each element to an {@link PrimitiveIterator.OfLong} + */ + default FunctionalPrimitiveIterator.OfLong flatMapToLong(Function function) + { + return new ChainedIterator.OfLong(map(function)); + } + + @Override + default FunctionalIterator map(Function function) + { + return new MappingIterator.ObjToObj<>(unwrap(), function); + } + + @Override + default FunctionalPrimitiveIterator.OfDouble mapToDouble(ToDoubleFunction function) + { + return new MappingIterator.ObjToDouble<>(unwrap(), function); + } + + @Override + default FunctionalPrimitiveIterator.OfInt mapToInt(ToIntFunction function) + { + return new MappingIterator.ObjToInt<>(unwrap(), function); + } + @Override + default FunctionalPrimitiveIterator.OfLong mapToLong(ToLongFunction function) + { + return new MappingIterator.ObjToLong<>(unwrap(), function); + } + + @Override + default FunctionalIterator nonNull() + { + return (FunctionalIterator) Reducible.super.nonNull(); + } + + + + // Accumulations Methods (Consuming) + + @Override + default FunctionalIterator consume() + { + return (FunctionalIterator) Reducible.super.consume(); + } + + @Override + default E detect(Predicate predicate) + { + return filter(predicate).next(); + } + + @Override + default Optional reduce(BinaryOperator accumulator) + { + Objects.requireNonNull(accumulator); + if (! hasNext()) { + return Optional.empty(); + } + return Optional.of(reduce(next(), accumulator)); + } + + @Override + default T reduce(T init, BiFunction accumulator) + { + Objects.requireNonNull(accumulator); + // avoid redirection in wrappers + Iterator local = unwrap(); + T result = init; + while (local.hasNext()) { + result = accumulator.apply(result, local.next()); + } + release(); + return result; + } + + @Override + default double reduce(double init, DoubleObjToDoubleFunction accumulator) + { + Objects.requireNonNull(accumulator); + // avoid redirection in wrappers + Iterator local = unwrap(); + double result = init; + while (local.hasNext()) { + result = accumulator.applyAsDouble(result, local.next()); + } + release(); + return result; + } + + @Override + default int reduce(int init, IntObjToIntFunction accumulator) + { + Objects.requireNonNull(accumulator); + // avoid redirection in wrappers + Iterator local = unwrap(); + int result = init; + while (local.hasNext()) { + result = accumulator.applyAsInt(result, local.next()); + } + release(); + return result; + } + + @Override + default long reduce(long init, LongObjToLongFunction accumulator) + { + Objects.requireNonNull(accumulator); + // avoid redirection in wrappers + Iterator local = unwrap(); + long result = init; + while (local.hasNext()) { + result = accumulator.applyAsLong(result, local.next()); + } + release(); + return result; + } +} diff --git a/prism/src/common/iterable/FunctionalPrimitiveIterable.java b/prism/src/common/iterable/FunctionalPrimitiveIterable.java new file mode 100644 index 0000000000..cd90e42cfd --- /dev/null +++ b/prism/src/common/iterable/FunctionalPrimitiveIterable.java @@ -0,0 +1,570 @@ +//============================================================================== +// +// Copyright (c) 2016- +// Authors: +// * Steffen Maercker (TU Dresden) +// +//------------------------------------------------------------------------------ +// +// This file is part of PRISM. +// +// PRISM is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// PRISM 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 for more details. +// +// You should have received a copy of the GNU General Public License +// along with PRISM; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//============================================================================== + +package common.iterable; + +import common.functions.*; + +import java.util.OptionalDouble; +import java.util.OptionalInt; +import java.util.OptionalLong; +import java.util.function.*; + +/** + * A base type for primitive specializations of the methods provided by {@link FunctionalIterable}. + * Specialized sub interfaces are provided for {@code double}, {@code int} and {@code long}: + *

    + *
  • {@link PrimitiveIterable.OfDouble double}
  • + *
  • {@link PrimitiveIterable.OfInt int}
  • + *
  • {@link PrimitiveIterable.OfLong long}
  • + *
+ * + * @param the type of elements hold by this PrimitiveIterable + * @param the type of primitive consumer + */ +public interface FunctionalPrimitiveIterable extends PrimitiveReducible, E_CONS>, FunctionalIterable, PrimitiveIterable +{ + @Override + FunctionalPrimitiveIterator iterator(); + + @Override + default void forEach(E_CONS action) + { + iterator().forEach(action); + } + + + /** + * Specialisation for {@code double} of a FunctionalPrimitiveIterable. + */ + interface OfDouble extends FunctionalPrimitiveIterable, PrimitiveReducible.OfDouble>, PrimitiveIterable.OfDouble + { + @Override + FunctionalPrimitiveIterator.OfDouble iterator(); + + + // Transforming Methods + + @Override + default FunctionalIterable concat(Iterable iterable) + { + if (iterable instanceof PrimitiveIterable.OfDouble) { + return concat((PrimitiveIterable.OfDouble) iterable); + } + return FunctionalPrimitiveIterable.super.concat(iterable); + } + + /** + * Primitive specialisation of {@code concat} for {@code double}. + * + * @param iterable the {@link PrimitiveIterable.OfDouble} to append + * @return an {@link Iterable} that iterates over the elements of the receiver and the argument + */ + default FunctionalPrimitiveIterable.OfDouble concat(PrimitiveIterable.OfDouble iterable) + { + return new ChainedIterable.OfDouble(new IterableArray.Of<>(this, iterable)); + } + + @Override + default FunctionalPrimitiveIterable.OfDouble dedupe() + { + return (FunctionalPrimitiveIterable.OfDouble) PrimitiveReducible.OfDouble.super.dedupe(); + } + + @Override + default FunctionalPrimitiveIterable.OfDouble distinct() + { + return (FunctionalPrimitiveIterable.OfDouble) PrimitiveReducible.OfDouble.super.distinct(); + } + + @Override + default FunctionalPrimitiveIterable.OfDouble filter(DoublePredicate predicate) + { + return new FilteringIterable.OfDouble(this, predicate); + } + + /** + * Primitive specialisation of {@code flatMap} for {@code double}. + * + * @see FunctionalIterable#flatMap(java.util.function.Function) + */ + default FunctionalIterable flatMap(DoubleFunction> function) + { + return new ChainedIterable.Of<>(map(function)); + } + + /** + * Primitive specialisation of {@code flatMapToDouble} for {@code double}. + * + * @see FunctionalIterable#flatMapToDouble(java.util.function.Function) + */ + default FunctionalPrimitiveIterable.OfDouble flatMapToDouble(DoubleFunction function) + { + return new ChainedIterable.OfDouble(map(function)); + } + + /** + * Primitive specialisation of {@code flatMapToInt} for {@code double}. + * + * @see FunctionalIterable#flatMapToInt(java.util.function.Function) + */ + default FunctionalPrimitiveIterable.OfInt flatMapToInt(DoubleFunction function) + { + return new ChainedIterable.OfInt(map(function)); + } + + /** + * Primitive specialisation of {@code flatMapToLong} for {@code double}. + * + * @see FunctionalIterable#flatMapToLong(java.util.function.Function) + */ + default FunctionalPrimitiveIterable.OfLong flatMapToLong(DoubleFunction function) + { + return new ChainedIterable.OfLong(map(function)); + } + + @Override + default FunctionalIterable map(DoubleFunction function) + { + return new MappingIterable.DoubleToObj<>(this, function); + } + + @Override + default FunctionalPrimitiveIterable.OfDouble mapToDouble(DoubleUnaryOperator function) + { + return new MappingIterable.DoubleToDouble(this, function); + } + + @Override + default FunctionalPrimitiveIterable.OfInt mapToInt(DoubleToIntFunction function) + { + return new MappingIterable.DoubleToInt(this, function); + } + + @Override + default FunctionalPrimitiveIterable.OfLong mapToLong(DoubleToLongFunction function) + { + return new MappingIterable.DoubleToLong(this, function); + } + + @Override + default FunctionalPrimitiveIterable.OfDouble nonNull() + { + return this; + } + + + + // Accumulations Methods (Consuming) + + @Override + default FunctionalPrimitiveIterable.OfDouble consume() + { + return (FunctionalPrimitiveIterable.OfDouble) PrimitiveReducible.OfDouble.super.consume(); + } + + @Override + default double detect(DoublePredicate predicate) + { + return iterator().detect(predicate); + } + + @Override + default OptionalDouble reduce(DoubleBinaryOperator accumulator) + { + return iterator().reduce(accumulator); + } + + @Override + default T reduce(T init, ObjDoubleFunction accumulator) + { + return iterator().reduce(init, accumulator); + } + + @Override + default double reduce(double init, DoubleBinaryOperator accumulator) + { + return iterator().reduce(init, accumulator); + } + + @Override + default int reduce(int init, IntDoubleToIntFunction accumulator) + { + return iterator().reduce(init, accumulator); + } + + @Override + default long reduce(long init, LongDoubleToLongFunction accumulator) + { + return iterator().reduce(init, accumulator); + } + } + + + /** + * Specialisation for {@code int} of a FunctionalPrimitiveIterable. + */ + interface OfInt extends FunctionalPrimitiveIterable, PrimitiveReducible.OfInt>, PrimitiveIterable.OfInt + { + @Override + FunctionalPrimitiveIterator.OfInt iterator(); + + + // Transforming Methods + + @Override + default FunctionalIterable concat(Iterable iterable) + { + if (iterable instanceof PrimitiveIterable.OfInt) { + return concat((PrimitiveIterable.OfInt) iterable); + } + return FunctionalPrimitiveIterable.super.concat(iterable); + } + + /** + * Primitive specialisation of {@code concat} for {@code int}. + * + * @param iterable the {@link PrimitiveIterable.OfInt} to append + * @return an {@link Iterable} that iterates over the elements of the receiver and the argument + */ + default FunctionalPrimitiveIterable.OfInt concat(PrimitiveIterable.OfInt iterable) + { + return new ChainedIterable.OfInt(new IterableArray.Of<>(this, iterable)); + } + + @Override + default FunctionalPrimitiveIterable.OfInt dedupe() + { + return (FunctionalPrimitiveIterable.OfInt) PrimitiveReducible.OfInt.super.dedupe(); + } + + @Override + default FunctionalPrimitiveIterable.OfInt distinct() + { + return (FunctionalPrimitiveIterable.OfInt) PrimitiveReducible.OfInt.super.distinct(); + } + + @Override + default FunctionalPrimitiveIterable.OfInt filter(IntPredicate predicate) + { + return new FilteringIterable.OfInt(this, predicate); + } + + /** + * Primitive specialisation of {@code flatMap} for {@code int}. + * + * @see FunctionalIterable#flatMap(java.util.function.Function) + */ + default FunctionalIterable flatMap(IntFunction> function) + { + return new ChainedIterable.Of<>(map(function)); + } + + /** + * Primitive specialisation of {@code flatMapToDouble} for {@code int}. + * + * @see FunctionalIterable#flatMapToDouble(java.util.function.Function) + */ + default FunctionalPrimitiveIterable.OfDouble flatMapToDouble(IntFunction function) + { + return new ChainedIterable.OfDouble(map(function)); + } + + /** + * Primitive specialisation of {@code flatMapToInt} for {@code int}. + * + * @see FunctionalIterable#flatMapToInt(java.util.function.Function) + */ + default FunctionalPrimitiveIterable.OfInt flatMapToInt(IntFunction function) + { + return new ChainedIterable.OfInt(map(function)); + } + + /** + * Primitive specialisation of {@code flatMapToLong} for {@code int}. + * + * @see FunctionalIterable#flatMapToLong(java.util.function.Function) + */ + default FunctionalPrimitiveIterable.OfLong flatMapToLong(IntFunction function) + { + return new ChainedIterable.OfLong(map(function)); + } + + @Override + default FunctionalIterable map(IntFunction function) + { + return new MappingIterable.IntToObj<>(this, function); + } + + @Override + default FunctionalPrimitiveIterable.OfDouble mapToDouble(IntToDoubleFunction function) + { + return new MappingIterable.IntToDouble(this, function); + } + + @Override + default FunctionalPrimitiveIterable.OfInt mapToInt(IntUnaryOperator function) + { + return new MappingIterable.IntToInt(this, function); + } + + @Override + default FunctionalPrimitiveIterable.OfLong mapToLong(IntToLongFunction function) + { + return new MappingIterable.IntToLong(this, function); + } + + @Override + default FunctionalPrimitiveIterable.OfInt nonNull() + { + return this; + } + + + + // Accumulations Methods (Consuming) + + @Override + default FunctionalPrimitiveIterable.OfInt consume() + { + return (FunctionalPrimitiveIterable.OfInt) PrimitiveReducible.OfInt.super.consume(); + } + + @Override + default int detect(IntPredicate predicate) + { + return iterator().detect(predicate); + } + + @Override + default OptionalDouble reduce(DoubleBinaryOperator accumulator) + { + return iterator().reduce(accumulator); + } + + @Override + default OptionalInt reduce(IntBinaryOperator accumulator) + { + return iterator().reduce(accumulator); + } + + @Override + default OptionalLong reduce(LongBinaryOperator accumulator) + { + return iterator().reduce(accumulator); + } + + @Override + default T reduce(T init, ObjIntFunction accumulator) + { + return iterator().reduce(init, accumulator); + } + + @Override + default double reduce(double init, DoubleBinaryOperator accumulator) + { + return iterator().reduce(init, accumulator); + } + + @Override + default int reduce(int init, IntBinaryOperator accumulator) + { + return iterator().reduce(init, accumulator); + } + + @Override + default long reduce(long init, LongBinaryOperator accumulator) + { + return iterator().reduce(init, accumulator); + } + } + + + /** + * Specialisation for {@code long} of a FunctionalPrimitiveIterable. + */ + interface OfLong extends FunctionalPrimitiveIterable, PrimitiveReducible.OfLong>, PrimitiveIterable.OfLong + { + @Override + FunctionalPrimitiveIterator.OfLong iterator(); + + + + // Transforming Methods + + @Override + default FunctionalIterable concat(Iterable iterable) + { + if (iterable instanceof PrimitiveIterable.OfLong) { + return concat((PrimitiveIterable.OfLong) iterable); + } + return FunctionalPrimitiveIterable.super.concat(iterable); + } + + /** + * Primitive specialisation of {@code concat} for {@code long}. + * + * @param iterable the {@link PrimitiveIterable.OfLong} to append + * @return an {@link Iterable} that iterates over the elements of the receiver and the argument + */ + default FunctionalPrimitiveIterable.OfLong concat(PrimitiveIterable.OfLong iterable) + { + return new ChainedIterable.OfLong(new IterableArray.Of<>(this, iterable)); + } + + @Override + default FunctionalPrimitiveIterable.OfLong dedupe() + { + return (FunctionalPrimitiveIterable.OfLong) PrimitiveReducible.OfLong.super.dedupe(); + } + @Override + default FunctionalPrimitiveIterable.OfLong distinct() + { + return (FunctionalPrimitiveIterable.OfLong) PrimitiveReducible.OfLong.super.distinct(); + } + @Override + default FunctionalPrimitiveIterable.OfLong filter(LongPredicate predicate) + { + return new FilteringIterable.OfLong(this, predicate); + } + + /** + * Primitive specialisation of {@code flatMap} for {@code long}. + * + * @see FunctionalIterable#flatMap(java.util.function.Function) + */ + default FunctionalIterable flatMap(LongFunction> function) + { + return new ChainedIterable.Of<>(map(function)); + } + + /** + * Primitive specialisation of {@code flatMapToDouble} for {@code long}. + * + * @see FunctionalIterable#flatMapToDouble(java.util.function.Function) + */ + default FunctionalPrimitiveIterable.OfDouble flatMapToDouble(LongFunction function) + { + return new ChainedIterable.OfDouble(map(function)); + } + + /** + * Primitive specialisation of {@code flatMapToInt} for {@code long}. + * + * @see FunctionalIterable#flatMapToInt(java.util.function.Function) + */ + default FunctionalPrimitiveIterable.OfInt flatMapToInt(LongFunction function) + { + return new ChainedIterable.OfInt(map(function)); + } + + /** + * Primitive specialisation of {@code flatMapToLong} for {@code long}. + * + * @see FunctionalIterable#flatMapToLong(java.util.function.Function) + */ + default FunctionalPrimitiveIterable.OfLong flatMapToLong(LongFunction function) + { + return new ChainedIterable.OfLong(map(function)); + } + + @Override + default FunctionalIterable map(LongFunction function) + { + return new MappingIterable.LongToObj<>(this, function); + } + + @Override + default FunctionalPrimitiveIterable.OfDouble mapToDouble(LongToDoubleFunction function) + { + return new MappingIterable.LongToDouble(this, function); + } + + @Override + default FunctionalPrimitiveIterable.OfInt mapToInt(LongToIntFunction function) + { + return new MappingIterable.LongToInt(this, function); + } + + @Override + default FunctionalPrimitiveIterable.OfLong mapToLong(LongUnaryOperator function) + { + return new MappingIterable.LongToLong(this, function); + } + + @Override + default FunctionalPrimitiveIterable.OfLong nonNull() + { + return this; + } + + + + // Accumulations Methods (Consuming) + + @Override + default FunctionalPrimitiveIterable.OfLong consume() + { + return (FunctionalPrimitiveIterable.OfLong) PrimitiveReducible.OfLong.super.consume(); + } + + @Override + default long detect(LongPredicate predicate) + { + return iterator().detect(predicate); + } + + @Override + default OptionalLong reduce(LongBinaryOperator accumulator) + { + return iterator().reduce(accumulator); + } + + @Override + default T reduce(T init, ObjLongFunction accumulator) + { + return iterator().reduce(init, accumulator); + } + + @Override + default double reduce(double init, DoubleLongToDoubleFunction accumulator) + { + return iterator().reduce(init, accumulator); + } + + @Override + default int reduce(int init, IntLongToIntFunction accumulator) + { + return iterator().reduce(init, accumulator); + } + + @Override + default long reduce(long init, LongBinaryOperator accumulator) + { + return iterator().reduce(init, accumulator); + } + } +} diff --git a/prism/src/common/iterable/FunctionalPrimitiveIterator.java b/prism/src/common/iterable/FunctionalPrimitiveIterator.java new file mode 100644 index 0000000000..69ba04e8b6 --- /dev/null +++ b/prism/src/common/iterable/FunctionalPrimitiveIterator.java @@ -0,0 +1,749 @@ +//============================================================================== +// +// Copyright (c) 2016- +// Authors: +// * Steffen Maercker (TU Dresden) +// +//------------------------------------------------------------------------------ +// +// This file is part of PRISM. +// +// PRISM is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// PRISM 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 for more details. +// +// You should have received a copy of the GNU General Public License +// along with PRISM; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//============================================================================== + +package common.iterable; + +import common.functions.*; + +import java.util.*; +import java.util.function.*; + +/** + * A base type for primitive specializations of the methods provided by {@link FunctionalIterator}. + * Specialized sub interfaces are provided for {@code double}, {@code int} and {@code long}: + *
    + *
  • {@link PrimitiveIterator.OfDouble double}
  • + *
  • {@link PrimitiveIterator.OfInt int}
  • + *
  • {@link PrimitiveIterator.OfLong long}
  • + *
+ * + * @param the type of elements returned by this PrimitiveIterator + * @param the type of primitive consumer + */ +public interface FunctionalPrimitiveIterator extends PrimitiveReducible, E_CONS>,FunctionalIterator, PrimitiveIterator +{ + @Override + default void forEach(E_CONS action) + { + unwrap().forEachRemaining(action); + release(); + } + + @Override + PrimitiveIterator unwrap(); + + + + /** + * Specialisation for {@code double} of a FunctionalPrimitiveIterator. + */ + interface OfDouble extends FunctionalPrimitiveIterator, PrimitiveReducible.OfDouble>, PrimitiveIterator.OfDouble + { + @Override + default PrimitiveIterator.OfDouble unwrap() + { + return this; + } + + + + // Transforming Methods + + @Override + default FunctionalIterator concat(Iterator iterator) + { + if (iterator instanceof PrimitiveIterator.OfDouble) { + return concat((PrimitiveIterator.OfDouble) iterator); + } + return FunctionalPrimitiveIterator.super.concat(iterator); + } + + /** + * Primitive specialisation of {@code concat} for {@code double}. + * + * @param iterator the {@link PrimitiveIterator.OfDouble} to append + * @return an {@link Iterator} that iterates over the elements of the receiver and the argument + */ + default FunctionalPrimitiveIterator.OfDouble concat(PrimitiveIterator.OfDouble iterator) + { + return new ChainedIterator.OfDouble(unwrap(), new ArrayIterator.Of<>(iterator)); + } + + @Override + default FunctionalPrimitiveIterator.OfDouble dedupe() + { + return (FunctionalPrimitiveIterator.OfDouble) PrimitiveReducible.OfDouble.super.dedupe(); + } + + @Override + default FunctionalPrimitiveIterator.OfDouble distinct() + { + return (FunctionalPrimitiveIterator.OfDouble) PrimitiveReducible.OfDouble.super.distinct(); + } + + @Override + default FunctionalPrimitiveIterator.OfDouble filter(DoublePredicate predicate) + { + return new FilteringIterator.OfDouble(unwrap(), predicate); + } + + /** + * Primitive specialisation of {@code flatMap} for {@code double}. + * + * @see FunctionalIterator#flatMap(java.util.function.Function) + */ + default FunctionalIterator flatMap(DoubleFunction> function) + { + return new ChainedIterator.Of<>(map(function)); + } + + /** + * Primitive specialisation of {@code flatMapToDouble} for {@code double}. + * + * @see FunctionalIterator#flatMapToDouble(java.util.function.Function) + */ + default FunctionalPrimitiveIterator.OfDouble flatMapToDouble(DoubleFunction function) + { + return new ChainedIterator.OfDouble(map(function)); + } + + /** + * Primitive specialisation of {@code flatMapToInt} for {@code double}. + * + * @see FunctionalIterator#flatMapToInt(java.util.function.Function) + */ + default FunctionalPrimitiveIterator.OfInt flatMapToInt(DoubleFunction function) + { + return new ChainedIterator.OfInt(map(function)); + } + + /** + * Primitive specialisation of {@code flatMapToLong} for {@code double}. + * + * @see FunctionalIterator#flatMapToLong(java.util.function.Function) + */ + default FunctionalPrimitiveIterator.OfLong flatMapToLong(DoubleFunction function) + { + return new ChainedIterator.OfLong(map(function)); + } + + @Override + default FunctionalIterator map(DoubleFunction function) + { + return new MappingIterator.DoubleToObj<>(unwrap(), function); + } + + @Override + default FunctionalPrimitiveIterator.OfDouble mapToDouble(DoubleUnaryOperator function) + { + return new MappingIterator.DoubleToDouble(unwrap(), function); + } + + @Override + default FunctionalPrimitiveIterator.OfInt mapToInt(DoubleToIntFunction function) + { + return new MappingIterator.DoubleToInt(unwrap(), function); + } + + @Override + default FunctionalPrimitiveIterator.OfLong mapToLong(DoubleToLongFunction function) + { + return new MappingIterator.DoubleToLong(unwrap(), function); + } + + @Override + default FunctionalPrimitiveIterator.OfDouble nonNull() + { + return this; + } + + + + // Accumulations Methods (Consuming) + + @Override + default FunctionalPrimitiveIterator.OfDouble consume() + { + return (FunctionalPrimitiveIterator.OfDouble) PrimitiveReducible.OfDouble.super.consume(); + } + + @Override + default boolean contains(Object obj) + { + boolean found = PrimitiveReducible.OfDouble.super.contains(obj); + release(); + return found; + } + + @Override + default double detect(DoublePredicate predicate) + { + return filter(predicate).nextDouble(); + } + + @Override + default OptionalDouble reduce(DoubleBinaryOperator accumulator) + { + Objects.requireNonNull(accumulator); + if (! hasNext()) { + return OptionalDouble.empty(); + } + return OptionalDouble.of(reduce(nextDouble(), accumulator)); + } + + @Override + default T reduce(T init, ObjDoubleFunction accumulator) + { + Objects.requireNonNull(accumulator); + // avoid redirection in wrappers + PrimitiveIterator.OfDouble local = unwrap(); + T result = init; + while (local.hasNext()) { + result = accumulator.apply(result, local.nextDouble()); + } + release(); + return result; + } + + @Override + default double reduce(double init, DoubleBinaryOperator accumulator) + { + Objects.requireNonNull(accumulator); + // avoid redirection in wrappers + PrimitiveIterator.OfDouble local = unwrap(); + double result = init; + while (local.hasNext()) { + result = accumulator.applyAsDouble(result, local.nextDouble()); + } + release(); + return result; + } + + @Override + default int reduce(int init, IntDoubleToIntFunction accumulator) + { + Objects.requireNonNull(accumulator); + // avoid redirection in wrappers + PrimitiveIterator.OfDouble local = unwrap(); + int result = init; + while (local.hasNext()) { + result = accumulator.applyAsInt(result, local.nextDouble()); + } + release(); + return result; + } + + @Override + default long reduce(long init, LongDoubleToLongFunction accumulator) + { + Objects.requireNonNull(accumulator); + // avoid redirection in wrappers + PrimitiveIterator.OfDouble local = unwrap(); + long result = init; + while (local.hasNext()) { + result = accumulator.applyAsLong(result, local.nextDouble()); + } + release(); + return result; + } + } + + + + /** + * Specialisation for {@code int} of a FunctionalPrimitiveIterator. + */ + interface OfInt extends FunctionalPrimitiveIterator, PrimitiveReducible.OfInt>, PrimitiveIterator.OfInt + { + @Override + default PrimitiveIterator.OfInt unwrap() + { + return this; + } + + + + // Transforming Methods + + @Override + default FunctionalIterator concat(Iterator iterator) + { + if (iterator instanceof PrimitiveIterator.OfInt) { + return concat((PrimitiveIterator.OfInt) iterator); + } + return FunctionalPrimitiveIterator.super.concat(iterator); + } + + /** + * Primitive specialisation of {@code concat} for {@code int}. + * + * @param iterator the {@link PrimitiveIterator.OfInt} to append + * @return an {@link Iterator} that iterates over the elements of the receiver and the argument + */ + default FunctionalPrimitiveIterator.OfInt concat(PrimitiveIterator.OfInt iterator) + { + return new ChainedIterator.OfInt(unwrap(), new ArrayIterator.Of<>(iterator)); + } + + @Override + default FunctionalPrimitiveIterator.OfInt dedupe() + { + return (FunctionalPrimitiveIterator.OfInt) PrimitiveReducible.OfInt.super.dedupe(); + } + + @Override + default FunctionalPrimitiveIterator.OfInt distinct() + { + return (FunctionalPrimitiveIterator.OfInt) PrimitiveReducible.OfInt.super.distinct(); + } + + @Override + default FunctionalPrimitiveIterator.OfInt filter(IntPredicate predicate) + { + return new FilteringIterator.OfInt(unwrap(), predicate); + } + + /** + * Primitive specialisation of {@code flatMap} for {@code int}. + * + * @see FunctionalIterator#flatMap(java.util.function.Function) + */ + default FunctionalIterator flatMap(IntFunction> function) + { + return new ChainedIterator.Of<>(map(function)); + } + + /** + * Primitive specialisation of {@code flatMapToDouble} for {@code int}. + * + * @see FunctionalIterator#flatMapToDouble(java.util.function.Function) + */ + default FunctionalPrimitiveIterator.OfDouble flatMapToDouble(IntFunction function) + { + return new ChainedIterator.OfDouble(map(function)); + } + + /** + * Primitive specialisation of {@code flatMapToInt} for {@code int}. + * + * @see FunctionalIterator#flatMapToInt(java.util.function.Function) + */ + default FunctionalPrimitiveIterator.OfInt flatMapToInt(IntFunction function) + { + return new ChainedIterator.OfInt(map(function)); + } + + /** + * Primitive specialisation of {@code flatMapToLong} for {@code int}. + * + * @see FunctionalIterator#flatMapToLong(java.util.function.Function) + */ + default FunctionalPrimitiveIterator.OfLong flatMapToLong(IntFunction function) + { + return new ChainedIterator.OfLong(map(function)); + } + + @Override + default FunctionalIterator map(IntFunction function) + { + return new MappingIterator.IntToObj<>(unwrap(), function); + } + + @Override + default FunctionalPrimitiveIterator.OfDouble mapToDouble(IntToDoubleFunction function) + { + return new MappingIterator.IntToDouble(unwrap(), function); + } + + @Override + default FunctionalPrimitiveIterator.OfInt mapToInt(IntUnaryOperator function) + { + return new MappingIterator.IntToInt(unwrap(), function); + } + + /** + * Primitive specialisation of {@code mapToLong} for {@code int}. + * + * @see FunctionalIterator#mapToLong(java.util.function.ToLongFunction) + */ + @Override + default FunctionalPrimitiveIterator.OfLong mapToLong(IntToLongFunction function) + { + return new MappingIterator.IntToLong(unwrap(), function); + } + + @Override + default FunctionalPrimitiveIterator.OfInt nonNull() + { + return this; + } + + + + // Accumulations Methods (Consuming) + + @Override + default FunctionalPrimitiveIterator.OfInt consume() + { + return (FunctionalPrimitiveIterator.OfInt) PrimitiveReducible.OfInt.super.consume(); + } + + @Override + default boolean contains(Object obj) + { + boolean found = PrimitiveReducible.OfInt.super.contains(obj); + release(); + return found; + } + + @Override + default int detect(IntPredicate predicate) + { + return filter(predicate).nextInt(); + } + + @Override + default OptionalDouble reduce(DoubleBinaryOperator accumulator) + { + Objects.requireNonNull(accumulator); + if (! hasNext()) { + return OptionalDouble.empty(); + } + return OptionalDouble.of(reduce(nextInt(), accumulator)); + } + + @Override + default OptionalInt reduce(IntBinaryOperator accumulator) + { + Objects.requireNonNull(accumulator); + if (! hasNext()) { + return OptionalInt.empty(); + } + return OptionalInt.of(reduce(nextInt(), accumulator)); + } + + @Override + default OptionalLong reduce(LongBinaryOperator accumulator) + { + Objects.requireNonNull(accumulator); + if (! hasNext()) { + return OptionalLong.empty(); + } + return OptionalLong.of(reduce(nextInt(), accumulator)); + } + + @Override + default T reduce(T init, ObjIntFunction accumulator) + { + Objects.requireNonNull(accumulator); + // avoid redirection in wrappers + PrimitiveIterator.OfInt local = unwrap(); + T result = init; + while (local.hasNext()) { + result = accumulator.apply(result, local.nextInt()); + } + release(); + return result; + } + + @Override + default double reduce(double init, DoubleBinaryOperator accumulator) + { + Objects.requireNonNull(accumulator); + // avoid redirection in wrappers + PrimitiveIterator.OfInt local = unwrap(); + double result = init; + while (local.hasNext()) { + result = accumulator.applyAsDouble(result, local.nextInt()); + } + release(); + return result; + } + + @Override + default int reduce(int init, IntBinaryOperator accumulator) + { + Objects.requireNonNull(accumulator); + // avoid redirection in wrappers + PrimitiveIterator.OfInt local = unwrap(); + int result = init; + while (local.hasNext()) { + result = accumulator.applyAsInt(result, local.nextInt()); + } + release(); + return result; + } + + @Override + default long reduce(long init, LongBinaryOperator accumulator) + { + Objects.requireNonNull(accumulator); + // avoid redirection in wrappers + PrimitiveIterator.OfInt local = unwrap(); + long result = init; + while (local.hasNext()) { + result = accumulator.applyAsLong(result, local.nextInt()); + } + release(); + return result; + } + } + + + + /** + * Specialisation for {@code long} of a FunctionalPrimitiveIterator. + */ + interface OfLong extends FunctionalPrimitiveIterator, PrimitiveReducible.OfLong>, PrimitiveIterator.OfLong + { + @Override + default PrimitiveIterator.OfLong unwrap() + { + return this; + } + + + + // Transforming Methods + + @Override + default FunctionalIterator concat(Iterator iterator) + { + if (iterator instanceof PrimitiveIterator.OfLong) { + return concat((PrimitiveIterator.OfLong) iterator); + } + return FunctionalPrimitiveIterator.super.concat(iterator); + } + + /** + * Primitive specialisation of {@code concat} for {@code long}. + * + * @param iterator the {@link PrimitiveIterator.OfLong} to append + * @return an {@link Iterator} that iterates over the elements of the receiver and the argument + */ + default FunctionalPrimitiveIterator.OfLong concat(PrimitiveIterator.OfLong iterator) + { + return new ChainedIterator.OfLong(unwrap(), new ArrayIterator.Of<>(iterator)); + } + + @Override + default FunctionalPrimitiveIterator.OfLong dedupe() + { + return (FunctionalPrimitiveIterator.OfLong) PrimitiveReducible.OfLong.super.dedupe(); + } + + @Override + default FunctionalPrimitiveIterator.OfLong distinct() + { + return (FunctionalPrimitiveIterator.OfLong) PrimitiveReducible.OfLong.super.distinct(); + } + + @Override + default FunctionalPrimitiveIterator.OfLong filter(LongPredicate predicate) + { + return new FilteringIterator.OfLong(unwrap(), predicate); + } + + /** + * Primitive specialisation of {@code flatMap} for {@code long}. + * + * @see FunctionalIterator#flatMap(java.util.function.Function) + */ + default FunctionalIterator flatMap(LongFunction> function) + { + return new ChainedIterator.Of<>(map(function)); + } + + /** + * Primitive specialisation of {@code flatMapToDouble} for {@code long}. + * + * @see FunctionalIterator#flatMapToDouble(java.util.function.Function) + */ + default FunctionalPrimitiveIterator.OfDouble flatMapToDouble(LongFunction function) + { + return new ChainedIterator.OfDouble(map(function)); + } + + /** + * Primitive specialisation of {@code flatMapToInt} for {@code long}. + * + * @see FunctionalIterator#flatMapToInt(java.util.function.Function) + */ + default FunctionalPrimitiveIterator.OfInt flatMapToInt(LongFunction function) + { + return new ChainedIterator.OfInt(map(function)); + } + + /** + * Primitive specialisation of {@code flatMapToLong} for {@code long}. + * + * @see FunctionalIterator#flatMapToLong(java.util.function.Function) + */ + default FunctionalPrimitiveIterator.OfLong flatMapToLong(LongFunction function) + { + return new ChainedIterator.OfLong(map(function)); + } + + /** + * Primitive specialisation of {@code map} for {@code long}. + * + * @see FunctionalIterator#map(java.util.function.Function) + */ + @Override + default FunctionalIterator map(LongFunction function) + { + return new MappingIterator.LongToObj<>(unwrap(), function); + } + + /** + * Primitive specialisation of {@code map} for {@code long}. + * + * @see FunctionalIterator#mapToDouble(java.util.function.ToDoubleFunction) + */ + @Override + default FunctionalPrimitiveIterator.OfDouble mapToDouble(LongToDoubleFunction function) + { + return new MappingIterator.LongToDouble(unwrap(), function); + } + + /** + * Primitive specialisation of {@code map} for {@code long}. + * + * @see FunctionalIterator#mapToInt(java.util.function.ToIntFunction) + */ + @Override + default FunctionalPrimitiveIterator.OfInt mapToInt(LongToIntFunction function) + { + return new MappingIterator.LongToInt(unwrap(), function); + } + + /** + * Primitive specialisation of {@code map} for {@code long}. + * + * @see FunctionalIterator#mapToLong(java.util.function.ToLongFunction) + */ + @Override + default FunctionalPrimitiveIterator.OfLong mapToLong(LongUnaryOperator function) + { + return new MappingIterator.LongToLong(unwrap(), function); + } + + @Override + default FunctionalPrimitiveIterator.OfLong nonNull() + { + return this; + } + + + + // Accumulations Methods (Consuming) + + @Override + default FunctionalPrimitiveIterator.OfLong consume() + { + return (FunctionalPrimitiveIterator.OfLong) PrimitiveReducible.OfLong.super.consume(); + } + + @Override + default boolean contains(Object obj) + { + boolean found = PrimitiveReducible.OfLong.super.contains(obj); + release(); + return found; + } + + @Override + default long detect(LongPredicate predicate) + { + return filter(predicate).nextLong(); + } + + default OptionalLong reduce(LongBinaryOperator accumulator) + { + Objects.requireNonNull(accumulator); + if (! hasNext()) { + return OptionalLong.empty(); + } + return OptionalLong.of(reduce(nextLong(), accumulator)); + } + + @Override + default T reduce(T init, ObjLongFunction accumulator) + { + Objects.requireNonNull(accumulator); + // avoid redirection in wrappers + PrimitiveIterator.OfLong local = unwrap(); + T result = init; + while (local.hasNext()) { + result = accumulator.apply(result, local.nextLong()); + } + release(); + return result; + } + + @Override + default double reduce(double init, DoubleLongToDoubleFunction accumulator) + { + Objects.requireNonNull(accumulator); + // avoid redirection in wrappers + PrimitiveIterator.OfLong local = unwrap(); + double result = init; + while (local.hasNext()) { + result = accumulator.applyAsDouble(result, local.nextLong()); + } + release(); + return result; + } + + @Override + default int reduce(int init, IntLongToIntFunction accumulator) + { + Objects.requireNonNull(accumulator); + // avoid redirection in wrappers + PrimitiveIterator.OfLong local = unwrap(); + int result = init; + while (local.hasNext()) { + result = accumulator.applyAsInt(result, local.nextLong()); + } + release(); + return result; + } + + @Override + default long reduce(long init, LongBinaryOperator accumulator) + { + Objects.requireNonNull(accumulator); + // avoid redirection in wrappers + PrimitiveIterator.OfLong local = unwrap(); + long result = init; + while (local.hasNext()) { + result = accumulator.applyAsLong(result, local.nextLong()); + } + release(); + return result; + } + } +} diff --git a/prism/src/common/iterable/IterableAdaptor.java b/prism/src/common/iterable/IterableAdaptor.java new file mode 100644 index 0000000000..ac9d927e83 --- /dev/null +++ b/prism/src/common/iterable/IterableAdaptor.java @@ -0,0 +1,165 @@ +//============================================================================== +// +// Copyright (c) 2016- +// Authors: +// * Steffen Maercker (TU Dresden) +// +//------------------------------------------------------------------------------ +// +// This file is part of PRISM. +// +// PRISM is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// PRISM 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 for more details. +// +// You should have received a copy of the GNU General Public License +// along with PRISM; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//============================================================================== + +package common.iterable; + +import java.util.Objects; +import java.util.PrimitiveIterator; +import java.util.function.Consumer; +import java.util.function.DoubleConsumer; +import java.util.function.IntConsumer; +import java.util.function.LongConsumer; + +/** + * An adaptor that extends non-functional Iterables with the methods provided by {@link FunctionalIterable}. + * + * @param type of the {@link Iterable}'s elements + * @param type of the Iterable to extend + */ +public abstract class IterableAdaptor> implements FunctionalIterable +{ + /** the Iterable that is extended */ + protected final I iterable; + + /** + * Generic constructor that wraps an Iterable. + * + * @param iterable the {@link Iterable} to be extended + */ + public IterableAdaptor(I iterable) + { + Objects.requireNonNull(iterable); + this.iterable = iterable; + } + + @Override + public void forEach(Consumer action) + { + iterable.forEach(action); + } + + + + public static class Of extends IterableAdaptor> + { + /** + * Generic constructor that wraps an Iterable. + * + * @param iterable the {@link Iterable} to be extended + */ + public Of(Iterable iterable) + { + super(iterable); + } + + @Override + public IteratorAdaptor.Of iterator() + { + return new IteratorAdaptor.Of<>(iterable.iterator()); + } + } + + + + public static class OfDouble extends IterableAdaptor implements FunctionalPrimitiveIterable.OfDouble + { + /** + * Constructor that wraps a PrimitiveIterator.OfDouble. + * + * @param iterator the {@link PrimitiveIterator.OfDouble} to be extended + */ + public OfDouble(PrimitiveIterable.OfDouble iterator) + { + super(iterator); + } + + @Override + public IteratorAdaptor.OfDouble iterator() + { + return new IteratorAdaptor.OfDouble(iterable.iterator()); + } + + @Override + public void forEach(DoubleConsumer action) + { + iterable.forEach(action); + } + } + + + + public static class OfInt extends IterableAdaptor implements FunctionalPrimitiveIterable.OfInt + { + /** + * Constructor that wraps a PrimitiveIterator.OfInt. + * + * @param iterator the {@link PrimitiveIterator.OfLong} to be extended + */ + public OfInt(PrimitiveIterable.OfInt iterator) + { + super(iterator); + } + + @Override + public IteratorAdaptor.OfInt iterator() + { + return new IteratorAdaptor.OfInt(iterable.iterator()); + } + + @Override + public void forEach(IntConsumer action) + { + iterable.forEach(action); + } +} + + + + public static class OfLong extends IterableAdaptor implements FunctionalPrimitiveIterable.OfLong + { + /** + * Constructor that wraps a PrimitiveIterator.OfLong. + * + * @param iterator the {@link PrimitiveIterator.OfLong} to be extended + */ + public OfLong(PrimitiveIterable.OfLong iterator) + { + super(iterator); + } + + @Override + public IteratorAdaptor.OfLong iterator() + { + return new IteratorAdaptor.OfLong(iterable.iterator()); + } + + @Override + public void forEach(LongConsumer action) + { + iterable.forEach(action); + } + } +} diff --git a/prism/src/common/iterable/IterableArray.java b/prism/src/common/iterable/IterableArray.java new file mode 100644 index 0000000000..5b8c50c8bc --- /dev/null +++ b/prism/src/common/iterable/IterableArray.java @@ -0,0 +1,213 @@ +//============================================================================== +// +// Copyright (c) 2016- +// Authors: +// * Steffen Maercker (TU Dresden) +// * Marcus Daum (Frauenhofer Institut) +// +//------------------------------------------------------------------------------ +// +// This file is part of PRISM. +// +// PRISM is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// PRISM 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 for more details. +// +// You should have received a copy of the GNU General Public License +// along with PRISM; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//============================================================================== + +package common.iterable; + +import java.util.Objects; + +/** + * Abstract base class of efficient Iterables over array slices. + * + * @param type of the array elements + */ +public abstract class IterableArray implements FunctionalIterable +{ + protected final int fromIndex; + protected final int toIndex; + + /** + * Iterable slice of array in index interval [fromIndex, toIndex). + * + * @param fromIndex first index, inclusive + * @param toIndex last index, exclusive + * @param length length of the array + */ + protected IterableArray(int fromIndex, int toIndex, int length) + { + Objects.checkFromToIndex(fromIndex, toIndex, length); + this.fromIndex = fromIndex; + this.toIndex = toIndex; + } + + @Override + public long count() + { + return size(); + } + + @Override + public abstract ArrayIterator iterator(); + + /** + * Get the number of elements. + */ + public int size() + { + return Math.max(0, toIndex - fromIndex); + } + + + + /** + * Generic implementation of an Iterable over an array slice. + * + * @param type of the array elements + */ + public static class Of extends IterableArray + { + protected final E[] elements; + + /** + * Iterable slice of array over all elements. + */ + @SafeVarargs + public Of(E... elements) + { + this(elements,0, elements.length); + } + + /** + * Iterable slice of array in index interval [fromIndex, toIndex). + * + * @param fromIndex first index, inclusive + * @param toIndex last index, exclusive + */ + public Of(E[] elements, int fromIndex, int toIndex) + { + super(fromIndex, toIndex, elements.length); + this.elements = elements; + } + + @Override + public ArrayIterator.Of iterator() + { + return new ArrayIterator.Of<>(elements, fromIndex, toIndex); + } + } + + + + /** + * Primitive specialisation for {@code double} of an Iterable over an array slice. + */ + public static class OfInt extends IterableArray implements FunctionalPrimitiveIterable.OfInt + { + protected final int[] elements; + + /** + * Iterable slice of array over all elements. + */ + public OfInt(int... elements) + { + this(elements, 0, elements.length); + } + + public OfInt(int[] elements, int fromIndex, int toIndex) + { + super(fromIndex, toIndex, elements.length); + this.elements = elements; + } + + @Override + public ArrayIterator.OfInt iterator() + { + return new ArrayIterator.OfInt(elements, fromIndex, toIndex); + } + } + + + + /** + * Primitive specialisation for {@code int} of an Iterable over an array slice. + */ + public static class OfDouble extends IterableArray implements FunctionalPrimitiveIterable.OfDouble + { + protected final double[] elements; + + /** + * Iterable slice of array over all elements. + */ + public OfDouble(double... elements) + { + this(elements,0, elements.length); + } + + /** + * Iterable slice of array in index interval [fromIndex, toIndex). + * + * @param fromIndex first index, inclusive + * @param toIndex last index, exclusive + */ + public OfDouble(double[] elements, int fromIndex, int toIndex) + { + super(fromIndex, toIndex, elements.length); + this.elements = elements; + } + + @Override + public ArrayIterator.OfDouble iterator() + { + return new ArrayIterator.OfDouble(elements, fromIndex, toIndex); + } + } + + + + /** + * Primitive specialisation for {@code long} of an Iterable over an array slice. + */ + public static class OfLong extends IterableArray implements FunctionalPrimitiveIterable.OfLong + { + protected final long[] elements; + + /** + * Iterable slice of array over all elements. + */ + public OfLong(long... elements) + { + this(elements,0, elements.length); + } + + /** + * Iterable slice of array in index interval [fromIndex, toIndex). + * + * @param fromIndex first index, inclusive + * @param toIndex last index, exclusive + */ + public OfLong(long[] elements, int fromIndex, int toIndex) + { + super(fromIndex, toIndex, elements.length); + this.elements = elements; + } + + @Override + public ArrayIterator.OfLong iterator() + { + return new ArrayIterator.OfLong(elements, fromIndex, toIndex); + } + } +} diff --git a/prism/src/common/iterable/IteratorAdaptor.java b/prism/src/common/iterable/IteratorAdaptor.java new file mode 100644 index 0000000000..3b7b060831 --- /dev/null +++ b/prism/src/common/iterable/IteratorAdaptor.java @@ -0,0 +1,226 @@ +//============================================================================== +// +// Copyright (c) 2016- +// Authors: +// * Steffen Maercker (TU Dresden) +// +//------------------------------------------------------------------------------ +// +// This file is part of PRISM. +// +// PRISM is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// PRISM 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 for more details. +// +// You should have received a copy of the GNU General Public License +// along with PRISM; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//============================================================================== + +package common.iterable; + +import java.util.Iterator; +import java.util.Objects; +import java.util.PrimitiveIterator; +import java.util.function.Consumer; +import java.util.function.DoubleConsumer; +import java.util.function.IntConsumer; +import java.util.function.LongConsumer; + +/** + * Abstract base class of adaptors that extend non-functional Iterators with the methods provided by {@link FunctionalIterator}. + * Implementations should release the underlying Iterator after iteration. + * + * @param type of the {@link Iterator}'s elements + * @param type of the Iterator to extend + */ +public abstract class IteratorAdaptor> implements FunctionalIterator +{ + /** the Iterator that is extended */ + protected I iterator; + + /** + * Generic constructor that wraps an Iterator. + * + * @param iterator the {@link Iterator} to be extended + */ + public IteratorAdaptor(I iterator) + { + Objects.requireNonNull(iterator); + this.iterator = iterator; + } + + @Override + public boolean hasNext() + { + if (iterator.hasNext()) { + return true; + } + release(); + return false; + } + + @Override + public E next() + { + return iterator.next(); + } + + @Override + public void forEachRemaining(Consumer action) + { + iterator.forEachRemaining(action); + release(); + } + + /** + * Unwrap a nested iterator if this instance is an adaptor wrapping an Iterator. + * Use to avoid repeated indirections, especially in loops. + * + * @return the wrapped iterator. + */ + @Override + public I unwrap() + { + return iterator; + } + + + + /** + * Generic implementation of an {@link IteratorAdaptor}. + * + * @param type of the Iterator's elements + */ + public static class Of extends IteratorAdaptor> + { + public Of(Iterator iterator) + { + super(iterator); + } + + @Override + public void release() + { + iterator = EmptyIterator.of(); + } + } + + + + /** + * Primitive specialisation for {@code double} of an {@link IteratorAdaptor}. + */ + public static class OfDouble extends IteratorAdaptor implements FunctionalPrimitiveIterator.OfDouble + { + /** + * Constructor that wraps a PrimitiveIterator.OfDouble. + * + * @param iterator the {@link PrimitiveIterator.OfDouble} to be extended + */ + public OfDouble(PrimitiveIterator.OfDouble iterator) + { + super(iterator); + } + + @Override + public double nextDouble() + { + return iterator.nextDouble(); + } + + @Override + public void forEachRemaining(DoubleConsumer action) + { + iterator.forEachRemaining(action); + release(); + } + + @Override + public void release() + { + iterator = EmptyIterator.ofDouble(); + } + } + + + + /** + * Primitive specialisation for {@code int} of an {@link IteratorAdaptor}. + */ + public static class OfInt extends IteratorAdaptor implements FunctionalPrimitiveIterator.OfInt + { + /** + * Constructor that wraps a PrimitiveIterator.OfInt. + * + * @param iterator the {@link PrimitiveIterator.OfInt} to be extended + */ + public OfInt(PrimitiveIterator.OfInt iterator) + { + super(iterator); + } + + @Override + public int nextInt() + { + return iterator.nextInt(); + } + + @Override + public void forEachRemaining(IntConsumer action) + { + iterator.forEachRemaining(action); + release(); + } + + @Override + public void release() + { + iterator = EmptyIterator.ofInt(); + } + } + + + + /** + * Primitive specialisation for {@code long} of an {@link IteratorAdaptor}. + */ + public static class OfLong extends IteratorAdaptor implements FunctionalPrimitiveIterator.OfLong + { + /** + * Constructor that wraps a PrimitiveIterator.OfLong. + * + * @param iterator the {@link PrimitiveIterator.OfLong} to be extended + */ + public OfLong(PrimitiveIterator.OfLong iterator) + { + super(iterator); + } + + @Override + public long nextLong() + { + return iterator.nextLong(); + } + + @Override + public void forEachRemaining(LongConsumer action) + { + iterator.forEachRemaining(action); + release(); + } + + @Override + public void release() + { + iterator = EmptyIterator.ofLong(); + } + } +} diff --git a/prism/src/common/iterable/MappingIterable.java b/prism/src/common/iterable/MappingIterable.java new file mode 100644 index 0000000000..f1e12f6222 --- /dev/null +++ b/prism/src/common/iterable/MappingIterable.java @@ -0,0 +1,566 @@ +//============================================================================== +// +// Copyright (c) 2016- +// Authors: +// * Steffen Maercker (TU Dresden) +// +//------------------------------------------------------------------------------ +// +// This file is part of PRISM. +// +// PRISM is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// PRISM 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 for more details. +// +// You should have received a copy of the GNU General Public License +// along with PRISM; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//============================================================================== + +package common.iterable; + +import java.util.Objects; +import java.util.function.DoubleFunction; +import java.util.function.DoubleToIntFunction; +import java.util.function.DoubleToLongFunction; +import java.util.function.DoubleUnaryOperator; +import java.util.function.Function; +import java.util.function.IntFunction; +import java.util.function.IntToDoubleFunction; +import java.util.function.IntToLongFunction; +import java.util.function.IntUnaryOperator; +import java.util.function.LongFunction; +import java.util.function.LongToDoubleFunction; +import java.util.function.LongToIntFunction; +import java.util.function.LongUnaryOperator; +import java.util.function.ToDoubleFunction; +import java.util.function.ToIntFunction; +import java.util.function.ToLongFunction; + +/** + * Abstract base class for Iterables that map elements using a function {@code f: S -> E}. + * Yields the result of applying {@code f} to each each element of the underlying Iterable: + * Iterable(S) -{@code f}-> Iterable(E) + * + * @param type of the underlying Iterable's elements + * @param type of the Iterable's elements after mapping + * @param type of the underlying Iterable + */ +public abstract class MappingIterable> implements FunctionalIterable +{ + /** The Iterable which elements are mapped */ + protected final I iterable; + + /** + * Constructor for a mapping Iterable without a mapping function. + * + * @param iterable an Iterable to be mapped + */ + public MappingIterable(I iterable) + { + Objects.requireNonNull(iterable); + this.iterable = iterable; + } + + + + /** + * Generic implementation using a function {@code f: S -> E}. + * + * @param type of the underlying Iterable's elements + * @param type of the Iterable's elements after mapping + */ + public static class ObjToObj extends MappingIterable> + { + /** The function the Iterable uses to map the elements */ + protected final Function function; + + /** + * Constructor for an Iterable that maps elements using a function. + * + * @param iterable an Iterable to be mapped + * @param function a function used to map the elements + */ + public ObjToObj(Iterable iterable, Function function) + { + super(iterable); + Objects.requireNonNull(function); + this.function = function; + } + + @Override + public FunctionalIterator iterator() + { + return new MappingIterator.ObjToObj<>(iterable.iterator(), function); + } + } + + + + /** + * Primitive specialisation of a mapping Iterable using a function {@code f: S -> double}. + * + * @param type of the underlying Iterable's elements + */ + public static class ObjToDouble extends MappingIterable> implements FunctionalPrimitiveIterable.OfDouble + { + /** The function the Iterable uses to map the elements */ + protected final ToDoubleFunction function; + + /** + * Constructor for an Iterable that maps elements using a function. + * + * @param iterable an Iterable to be mapped + * @param function a function used to map the elements + */ + public ObjToDouble(Iterable iterable, ToDoubleFunction function) + { + super(iterable); + Objects.requireNonNull(function); + this.function = function; + } + + @Override + public FunctionalPrimitiveIterator.OfDouble iterator() + { + return new MappingIterator.ObjToDouble<>(iterable.iterator(), function); + } + } + + + + /** + * Primitive specialisation of a mapping Iterable using a function {@code f: S -> int}. + * + * @param type of the underlying Iterable's elements + */ + public static class ObjToInt extends MappingIterable> implements FunctionalPrimitiveIterable.OfInt + { + /** The function the Iterable uses to map the elements */ + protected final ToIntFunction function; + + /** + * Constructor for an Iterable that maps elements using a function. + * + * @param iterable an Iterable to be mapped + * @param function a function used to map the elements + */ + public ObjToInt(Iterable iterable, ToIntFunction function) + { + super(iterable); + Objects.requireNonNull(function); + this.function = function; + } + + @Override + public FunctionalPrimitiveIterator.OfInt iterator() + { + return new MappingIterator.ObjToInt<>(iterable.iterator(), function); + } + } + + + + /** + * Primitive specialisation of a mapping Iterable using a function {@code f: S -> long}. + * + * @param type of the underlying Iterable's elements + */ + public static class ObjToLong extends MappingIterable> implements FunctionalPrimitiveIterable.OfLong + { + /** The function the Iterable uses to map the elements */ + protected final ToLongFunction function; + + /** + * Constructor for an Iterable that maps elements using a function. + * + * @param iterable an Iterable to be mapped + * @param function a function used to map the elements + */ + public ObjToLong(Iterable iterable, ToLongFunction function) + { + super(iterable); + Objects.requireNonNull(function); + this.function = function; + } + + @Override + public FunctionalPrimitiveIterator.OfLong iterator() + { + return new MappingIterator.ObjToLong<>(iterable.iterator(), function); + } + } + + + + /** + * Primitive specialisation of a mapping Iterable using a function {@code f: double -> E}. + * + * @param type of the Iterable's elements after mapping + */ + public static class DoubleToObj extends MappingIterable + { + /** The function the Iterable uses to map the elements */ + protected final DoubleFunction function; + + /** + * Constructor for an Iterable that maps elements using a function. + * + * @param iterable an Iterable to be mapped + * @param function a function used to map the elements + */ + public DoubleToObj(PrimitiveIterable.OfDouble iterable, DoubleFunction function) + { + super(iterable); + Objects.requireNonNull(function); + this.function = function; + } + + @Override + public FunctionalIterator iterator() + { + return new MappingIterator.DoubleToObj<>(iterable.iterator(), function); + } + } + + + + /** + * Primitive specialisation of a mapping Iterable using a function {@code f: double -> double}. + */ + public static class DoubleToDouble extends MappingIterable implements FunctionalPrimitiveIterable.OfDouble + { + /** The function the Iterable uses to map the elements */ + protected final DoubleUnaryOperator function; + + /** + * Constructor for an Iterable that maps elements using a function. + * + * @param iterable an Iterable to be mapped + * @param function a function used to map the elements + */ + public DoubleToDouble(PrimitiveIterable.OfDouble iterable, DoubleUnaryOperator function) + { + super(iterable); + Objects.requireNonNull(function); + this.function = function; + } + + @Override + public FunctionalPrimitiveIterator.OfDouble iterator() + { + return new MappingIterator.DoubleToDouble(iterable.iterator(), function); + } + } + + + + /** + * Primitive specialisation of a mapping Iterable using a function {@code f: double -> int}. + */ + public static class DoubleToInt extends MappingIterable implements FunctionalPrimitiveIterable.OfInt + { + /** The function the Iterable uses to map the elements */ + protected final DoubleToIntFunction function; + + /** + * Constructor for an Iterable that maps elements using a function. + * + * @param iterable an Iterable to be mapped + * @param function a function used to map the elements + */ + public DoubleToInt(PrimitiveIterable.OfDouble iterable, DoubleToIntFunction function) + { + super(iterable); + Objects.requireNonNull(function); + this.function = function; + } + + @Override + public FunctionalPrimitiveIterator.OfInt iterator() + { + return new MappingIterator.DoubleToInt(iterable.iterator(), function); + } + } + + + + /** + * Primitive specialisation of a mapping Iterable using a function {@code f: double -> long}. + */ + public static class DoubleToLong extends MappingIterable implements FunctionalPrimitiveIterable.OfLong + { + /** The function the Iterable uses to map the elements */ + protected final DoubleToLongFunction function; + + /** + * Constructor for an Iterable that maps elements using a function. + * + * @param iterable an Iterable to be mapped + * @param function a function used to map the elements + */ + public DoubleToLong(PrimitiveIterable.OfDouble iterable, DoubleToLongFunction function) + { + super(iterable); + Objects.requireNonNull(function); + this.function = function; + } + + @Override + public FunctionalPrimitiveIterator.OfLong iterator() + { + return new MappingIterator.DoubleToLong(iterable.iterator(), function); + } + } + + + + /** + * Primitive specialisation of a mapping Iterable using a function {@code f: int -> E}. + * + * @param type of the Iterable's elements after mapping + */ + public static class IntToObj extends MappingIterable + { + /** The function the Iterable uses to map the elements */ + protected final IntFunction function; + + /** + * Constructor for an Iterable that maps elements using a function. + * + * @param iterable an Iterable to be mapped + * @param function a function used to map the elements + */ + public IntToObj(PrimitiveIterable.OfInt iterable, IntFunction function) + { + super(iterable); + Objects.requireNonNull(function); + this.function = function; + } + + @Override + public FunctionalIterator iterator() + { + return new MappingIterator.IntToObj<>(iterable.iterator(), function); + } + } + + + + /** + * Primitive specialisation of a mapping Iterable using a function {@code f: int -> double}. + */ + public static class IntToDouble extends MappingIterable implements FunctionalPrimitiveIterable.OfDouble + { + /** The function the Iterable uses to map the elements */ + protected final IntToDoubleFunction function; + + /** + * Constructor for an Iterable that maps elements using a function. + * + * @param iterable an Iterable to be mapped + * @param function a function used to map the elements + */ + public IntToDouble(PrimitiveIterable.OfInt iterable, IntToDoubleFunction function) + { + super(iterable); + Objects.requireNonNull(function); + this.function = function; + } + + @Override + public FunctionalPrimitiveIterator.OfDouble iterator() + { + return new MappingIterator.IntToDouble(iterable.iterator(), function); + } + } + + + + /** + * Primitive specialisation of a mapping Iterable using a function {@code f: int -> int}. + */ + public static class IntToInt extends MappingIterable implements FunctionalPrimitiveIterable.OfInt + { + /** The function the Iterable uses to map the elements */ + protected final IntUnaryOperator function; + + /** + * Constructor for an Iterable that maps elements using a function. + * + * @param iterable an Iterable to be mapped + * @param function a function used to map the elements + */ + public IntToInt(PrimitiveIterable.OfInt iterable, IntUnaryOperator function) + { + super(iterable); + Objects.requireNonNull(function); + this.function = function; + } + + @Override + public FunctionalPrimitiveIterator.OfInt iterator() + { + return new MappingIterator.IntToInt(iterable.iterator(), function); + } + } + + + + /** + * Primitive specialisation of a mapping Iterable using a function {@code f: int -> long}. + */ + public static class IntToLong extends MappingIterable implements FunctionalPrimitiveIterable.OfLong + { + /** The function the Iterable uses to map the elements */ + protected final IntToLongFunction function; + + /** + * Constructor for an Iterable that maps elements using a function. + * + * @param iterable an Iterable to be mapped + * @param function a function used to map the elements + */ + public IntToLong(PrimitiveIterable.OfInt iterable, IntToLongFunction function) + { + super(iterable); + Objects.requireNonNull(function); + this.function = function; + } + + @Override + public FunctionalPrimitiveIterator.OfLong iterator() + { + return new MappingIterator.IntToLong(iterable.iterator(), function); + } + } + + + + /** + * Primitive specialisation of a mapping Iterable using a function {@code f: long -> E}. + * + * @param type of the Iterable's elements after mapping + */ + public static class LongToObj extends MappingIterable + { + /** The function the Iterable uses to map the elements */ + protected final LongFunction function; + + /** + * Constructor for an Iterable that maps elements using a function. + * + * @param iterable an Iterable to be mapped + * @param function a function used to map the elements + */ + public LongToObj(PrimitiveIterable.OfLong iterable, LongFunction function) + { + super(iterable); + Objects.requireNonNull(function); + this.function = function; + } + + @Override + public FunctionalIterator iterator() + { + return new MappingIterator.LongToObj<>(iterable.iterator(), function); + } + } + + + + /** + * Primitive specialisation of a mapping Iterable using a function {@code f: long -> double}. + */ + public static class LongToDouble extends MappingIterable implements FunctionalPrimitiveIterable.OfDouble + { + /** The function the Iterable uses to map the elements */ + protected final LongToDoubleFunction function; + + /** + * Constructor for an Iterable that maps elements using a function. + * + * @param iterable an Iterable to be mapped + * @param function a function used to map the elements + */ + public LongToDouble(PrimitiveIterable.OfLong iterable, LongToDoubleFunction function) + { + super(iterable); + Objects.requireNonNull(function); + this.function = function; + } + + @Override + public FunctionalPrimitiveIterator.OfDouble iterator() + { + return new MappingIterator.LongToDouble(iterable.iterator(), function); + } + } + + + + /** + * Primitive specialisation of a mapping Iterable using a function {@code f: long -> int}. + */ + public static class LongToInt extends MappingIterable implements FunctionalPrimitiveIterable.OfInt + { + /** The function the Iterable uses to map the elements */ + protected final LongToIntFunction function; + + /** + * Constructor for an Iterable that maps elements using a function. + * + * @param iterable an Iterable to be mapped + * @param function a function used to map the elements + */ + public LongToInt(PrimitiveIterable.OfLong iterable, LongToIntFunction function) + { + super(iterable); + Objects.requireNonNull(function); + this.function = function; + } + + @Override + public FunctionalPrimitiveIterator.OfInt iterator() + { + return new MappingIterator.LongToInt(iterable.iterator(), function); + } + } + + + + /** + * Primitive specialisation of a mapping Iterable using a function {@code f: long -> long}. + */ + public static class LongToLong extends MappingIterable implements FunctionalPrimitiveIterable.OfLong + { + /** The function the Iterable uses to map the elements */ + protected final LongUnaryOperator function; + + /** + * Constructor for an Iterable that maps elements using a function. + * + * @param iterable an Iterable to be mapped + * @param function a function used to map the elements + */ + public LongToLong(PrimitiveIterable.OfLong iterable, LongUnaryOperator function) + { + super(iterable); + Objects.requireNonNull(function); + this.function = function; + } + + @Override + public FunctionalPrimitiveIterator.OfLong iterator() + { + return new MappingIterator.LongToLong(iterable.iterator(), function); + } + } +} \ No newline at end of file diff --git a/prism/src/common/iterable/MappingIterator.java b/prism/src/common/iterable/MappingIterator.java index 8f81d74f44..f4195a195e 100644 --- a/prism/src/common/iterable/MappingIterator.java +++ b/prism/src/common/iterable/MappingIterator.java @@ -1,6 +1,34 @@ +//============================================================================== +// +// Copyright (c) 2016- +// Authors: +// * Steffen Maercker (TU Dresden) +// +//------------------------------------------------------------------------------ +// +// This file is part of PRISM. +// +// PRISM is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// PRISM 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 for more details. +// +// You should have received a copy of the GNU General Public License +// along with PRISM; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//============================================================================== + package common.iterable; import java.util.Iterator; +import java.util.Objects; +import java.util.PrimitiveIterator; import java.util.PrimitiveIterator.OfDouble; import java.util.PrimitiveIterator.OfInt; import java.util.PrimitiveIterator.OfLong; @@ -21,443 +49,657 @@ import java.util.function.ToIntFunction; import java.util.function.ToLongFunction; -/** Helpers for mapping Iterators to another Iterator, performing some mapping on the elements */ -public abstract class MappingIterator implements Iterator +/** + * Abstract base class for Iterators that map elements using a function {@code f: S -> E}. + * Yields the result of applying {@code f} to each each element of the underlying Iterator: + * Iterator(S) -{@code f}-> Iterator(E) + *

+ * The calls to {@code next()} of the underlying Iterator happen on-the-fly, + * i.e., only when {@code next()} is called for this Iterator. + *

+ * Implementations should release the underlying Iterator after iteration. + * + * @param type of the underlying Iterator's elements + * @param type of the Iterator's elements after mapping + * @param type of the underlying Iterator + */ +public abstract class MappingIterator> implements FunctionalIterator { - protected final Iterator iterator; - - public MappingIterator(Iterable iterable) - { - this(iterable.iterator()); - } - - public MappingIterator(Iterator iterator) + /** The Iterator which elements are mapped */ + protected I iterator; + + /** + * Constructor for a MappingIterator without a mapping function. + * + * @param iterator an Iterator to be mapped + */ + public MappingIterator(I iterator) { + Objects.requireNonNull(iterator); this.iterator = iterator; } @Override public boolean hasNext() { - return iterator.hasNext(); + if (iterator.hasNext()) { + return true; + } + release(); + return false; } @Override - public void remove() + public long count() { - iterator.remove(); + // do not apply mapping, just count elements of underlying iterator + return Reducible.extend(iterator).count(); } - /** Map an Iterator to an Iterator using the given mapping function */ - public static class From extends MappingIterator - { - protected final Function function; - public From(Iterable iterable, Function function) - { - this(iterable.iterator(), function); - } - public From(Iterator iterator, Function function) + /** + * Generic implementation of a MappingIterator using a function {@code f: S -> E}. + * + * @param type of the underlying Iterator's elements + * @param type of the Iterator's elements after mapping + */ + public static class ObjToObj extends MappingIterator> + { + /** The function the Iterator uses to map the elements */ + protected final Function function; + + /** + * Constructor for an Iterator that maps elements using a function. + * + * @param iterator an Iterator to be mapped + * @param function a function used to map the elements + */ + public ObjToObj(Iterator iterator, Function function) { super(iterator); + Objects.requireNonNull(function); this.function = function; } @Override - public T next() + public E next() { + requireNext(); return function.apply(iterator.next()); } - } - - /** Map an Iterable to a PrimitiveIterator.OfInt */ - public static OfInt toInt(Iterable iterable) - { - return toInt(iterable.iterator()); - } - /** Map an Iterator to a PrimitiveIterator.OfInt */ - public static OfInt toInt(Iterator iterator) - { - if (iterator instanceof OfInt) { - return (OfInt) iterator; + @Override + public void release() + { + iterator = EmptyIterator.of(); } - return new ToInt<>(iterator, Integer::intValue); } - /** Map an Iterator to a PrimitiveIterator.OfInt using the given mapping function */ - public static class ToInt extends MappingIterator implements OfInt + + + /** + * Primitive specialisation of a MappingIterator using a function {@code f: S -> double}. + * + * @param type of the underlying Iterator's elements + */ + public static class ObjToDouble extends MappingIterator> implements FunctionalPrimitiveIterator.OfDouble { - protected ToIntFunction function; + /** The function the Iterator uses to map the elements */ + protected final ToDoubleFunction function; - public ToInt(Iterable iterable, ToIntFunction function) + /** + * Constructor for an Iterator that maps elements using a function. + * + * @param iterator an Iterator to be mapped + * @param function a function used to map the elements + */ + public ObjToDouble(Iterator iterator, ToDoubleFunction function) { - this(iterable.iterator(), function); + super(iterator); + Objects.requireNonNull(function); + this.function = function; } - public ToInt(Iterator iterator, ToIntFunction function) + @Override + public double nextDouble() { - super(iterator); - this.function = function; + requireNext(); + return function.applyAsDouble(iterator.next()); } @Override - public int nextInt() + public void release() { - return function.applyAsInt(iterator.next()); + iterator = EmptyIterator.of(); } } - /** Map an Iterable to a PrimitiveIterator.OfDouble */ - public static OfDouble toDouble(Iterable iterable) - { - return toDouble(iterable.iterator()); - } - /** Map an Iterator to a PrimitiveIterator.OfDouble */ - public static OfDouble toDouble(Iterator iterator) - { - if (iterator instanceof OfDouble) { - return (OfDouble) iterator; - } - return new ToDouble<>(iterator, Double::doubleValue); - } - /** Map an Iterator to a PrimitiveIterator.OfDouble using the given mapping function */ - public static class ToDouble extends MappingIterator implements OfDouble + /** + * Primitive specialisation of a MappingIterator using a function {@code f: S -> int}. + * + * @param type of the underlying Iterator's elements + */ + public static class ObjToInt extends MappingIterator> implements FunctionalPrimitiveIterator.OfInt { - protected ToDoubleFunction function; + /** The function the Iterator uses to map the elements */ + protected final ToIntFunction function; - public ToDouble(Iterable iterable, ToDoubleFunction function) + /** + * Constructor for an Iterator that maps elements using a function. + * + * @param iterator an Iterator to be mapped + * @param function a function used to map the elements + */ + public ObjToInt(Iterator iterator, ToIntFunction function) { - this(iterable.iterator(), function); + super(iterator); + Objects.requireNonNull(function); + this.function = function; } - public ToDouble(Iterator iterator, ToDoubleFunction function) + @Override + public int nextInt() { - super(iterator); - this.function = function; + requireNext(); + return function.applyAsInt(iterator.next()); } @Override - public double nextDouble() + public void release() { - return function.applyAsDouble(iterator.next()); + iterator = EmptyIterator.of(); } } - /** Map an Iterable to a PrimitiveIterator.OfLong */ - public static OfLong toLong(Iterable iterable) - { - return toLong(iterable.iterator()); - } - /** Map an Iterator to a PrimitiveIterator.OfLong */ - public static OfLong toLong(Iterator iterator) - { - if (iterator instanceof OfLong) { - return (OfLong) iterator; - } - return new ToLong<>(iterator, Long::longValue); - } - /** Map an Iterator to a PrimitiveIterator.OfLong using the given mapping function */ - public static class ToLong extends MappingIterator implements OfLong + /** + * Primitive specialisation of a MappingIterator using a function {@code f: S -> long}. + * + * @param type of the underlying Iterator's elements + */ + public static class ObjToLong extends MappingIterator> implements FunctionalPrimitiveIterator.OfLong { - protected ToLongFunction function; - - public ToLong(Iterable iterable, ToLongFunction function) - { - this(iterable.iterator(), function); - } + /** The function the Iterator uses to map the elements */ + protected final ToLongFunction function; - public ToLong(Iterator iterator, ToLongFunction function) + /** + * Constructor for an Iterator that maps elements using a function. + * + * @param iterator an Iterator to be mapped + * @param function a function used to map the elements + */ + public ObjToLong(Iterator iterator, ToLongFunction function) { super(iterator); + Objects.requireNonNull(function); this.function = function; } @Override public long nextLong() { + requireNext(); return function.applyAsLong(iterator.next()); } + + @Override + public void release() + { + iterator = EmptyIterator.of(); + } } - /** Map an iterator over integers to an iterator over T */ - public static class FromInt extends MappingIterator + + + /** + * Primitive specialisation of a MappingIterator using a function {@code f: double -> E}. + * + * @param type of the Iterator's elements after mapping + */ + public static class DoubleToObj extends MappingIterator { - protected IntFunction function; + /** The function the Iterator uses to map the elements */ + protected final DoubleFunction function; - public FromInt(IterableInt iterable, IntFunction function) + /** + * Constructor for an Iterator that maps elements using a function. + * + * @param iterator an Iterator to be mapped + * @param function a function used to map the elements + */ + public DoubleToObj(OfDouble iterator, DoubleFunction function) { - this(iterable.iterator(), function); + super(iterator); + Objects.requireNonNull(function); + this.function = function; } - public FromInt(OfInt iterator, IntFunction function) + @Override + public E next() { - super(iterator); - this.function = function; + requireNext(); + return function.apply(iterator.nextDouble()); } @Override - public T next() + public void release() { - return function.apply(((OfInt) iterator).nextInt()); + iterator = EmptyIterator.ofDouble(); } } - /** Map an iterator over integers to another iterator over integers */ - public static class FromIntToInt extends MappingIterator implements OfInt + + + /** + * Primitive specialisation of a MappingIterator using a function {@code f: double -> double}. + */ + public static class DoubleToDouble extends MappingIterator implements FunctionalPrimitiveIterator.OfDouble { - protected IntUnaryOperator function; + /** The function the Iterator uses to map the elements */ + protected final DoubleUnaryOperator function; - public FromIntToInt(IterableInt iterable, IntUnaryOperator function) + /** + * Constructor for an Iterator that maps elements using a function. + * + * @param iterator an Iterator to be mapped + * @param function a function used to map the elements + */ + public DoubleToDouble(PrimitiveIterator.OfDouble iterator, DoubleUnaryOperator function) { - this(iterable.iterator(), function); + super(iterator); + Objects.requireNonNull(function); + this.function = function; } - public FromIntToInt(OfInt iterator, IntUnaryOperator function) + @Override + public double nextDouble() { - super(iterator); - this.function = function; + requireNext(); + return function.applyAsDouble(iterator.nextDouble()); } @Override - public int nextInt() + public void release() { - return function.applyAsInt(((OfInt) iterator).nextInt()); + iterator = EmptyIterator.ofDouble(); } } - /** Map an iterator over integers to iterator over doubles */ - public static class FromIntToDouble extends MappingIterator implements OfDouble + + + /** + * Primitive specialisation of a MappingIterator using a function {@code f: double -> int}. + */ + public static class DoubleToInt extends MappingIterator implements FunctionalPrimitiveIterator.OfInt { - protected IntToDoubleFunction function; + /** The function the Iterator uses to map the elements */ + protected final DoubleToIntFunction function; - public FromIntToDouble(IterableInt iterable, IntToDoubleFunction function) + /** + * Constructor for an Iterator that maps elements using a function. + * + * @param iterator an Iterator to be mapped + * @param function a function used to map the elements + */ + public DoubleToInt(PrimitiveIterator.OfDouble iterator, DoubleToIntFunction function) { - this(iterable.iterator(), function); + super(iterator); + Objects.requireNonNull(function); + this.function = function; } - public FromIntToDouble(OfInt iterator, IntToDoubleFunction function) + @Override + public int nextInt() { - super(iterator); - this.function = function; + requireNext(); + return function.applyAsInt(iterator.nextDouble()); } @Override - public double nextDouble() + public void release() { - return function.applyAsDouble(((OfInt) iterator).nextInt()); + iterator = EmptyIterator.ofDouble(); } } - /** Map an iterator over integers to iterator over longs */ - public static class FromIntToLong extends MappingIterator implements OfLong - { - protected IntToLongFunction function; - public FromIntToLong(IterableInt iterable, IntToLongFunction function) - { - this(iterable.iterator(), function); - } - public FromIntToLong(OfInt iterator, IntToLongFunction function) + /** + * Primitive specialisation of a MappingIterator using a function {@code f: double -> long}. + */ + public static class DoubleToLong extends MappingIterator implements FunctionalPrimitiveIterator.OfLong + { + /** The function the Iterator uses to map the elements */ + protected final DoubleToLongFunction function; + + /** + * Constructor for an Iterator that maps elements using a function. + * + * @param iterator an Iterator to be mapped + * @param function a function used to map the elements + */ + public DoubleToLong(PrimitiveIterator.OfDouble iterator, DoubleToLongFunction function) { super(iterator); + Objects.requireNonNull(function); this.function = function; } @Override public long nextLong() { - return function.applyAsLong(((OfInt) iterator).nextInt()); + requireNext(); + return function.applyAsLong(iterator.nextDouble()); + } + + @Override + public void release() + { + iterator = EmptyIterator.ofDouble(); } } - /** Map an iterator over doubles to an iterator over T */ - public static class FromDouble extends MappingIterator + + + /** + * Primitive specialisation of a MappingIterator using a function {@code f: int -> E}. + * + * @param type of the Iterator's elements after mapping + */ + public static class IntToObj extends MappingIterator { - protected DoubleFunction function; + /** The function the Iterator uses to map the elements */ + protected final IntFunction function; - public FromDouble(IterableDouble iterable, DoubleFunction function) + /** + * Constructor for an Iterator that maps elements using a function. + * + * @param iterator an Iterator to be mapped + * @param function a function used to map the elements + */ + public IntToObj(OfInt iterator, IntFunction function) { - this(iterable.iterator(), function); + super(iterator); + Objects.requireNonNull(function); + this.function = function; } - public FromDouble(OfDouble iterator, DoubleFunction function) + @Override + public E next() { - super(iterator); - this.function = function; + requireNext(); + return function.apply(iterator.nextInt()); } @Override - public T next() + public void release() { - return function.apply(((OfDouble) iterator).nextDouble()); + iterator = EmptyIterator.ofInt(); } } - /** Map an iterator over doubles to an iterator over integers */ - public static class FromDoubleToInt extends MappingIterator implements OfInt + + + /** + * Primitive specialisation of a MappingIterator using a function {@code f: int -> double}. + */ + public static class IntToDouble extends MappingIterator implements FunctionalPrimitiveIterator.OfDouble { - protected DoubleToIntFunction function; + /** The function the Iterator uses to map the elements */ + protected final IntToDoubleFunction function; - public FromDoubleToInt(IterableDouble iterable, DoubleToIntFunction function) + /** + * Constructor for an Iterator that maps elements using a function. + * + * @param iterator an Iterator to be mapped + * @param function a function used to map the elements + */ + public IntToDouble(PrimitiveIterator.OfInt iterator, IntToDoubleFunction function) { - this(iterable.iterator(), function); + super(iterator); + Objects.requireNonNull(function); + this.function = function; } - public FromDoubleToInt(OfDouble iterator, DoubleToIntFunction function) + @Override + public double nextDouble() { - super(iterator); - this.function = function; + requireNext(); + return function.applyAsDouble(iterator.nextInt()); } @Override - public int nextInt() + public void release() { - return function.applyAsInt(((OfDouble) iterator).nextDouble()); + iterator = EmptyIterator.ofInt(); } } - /** Map an iterator over doubles to another iterator over doubles */ - public static class FromDoubleToDouble extends MappingIterator implements OfDouble + + + /** + * Primitive specialisation of a MappingIterator using a function {@code f: int -> int}. + */ + public static class IntToInt extends MappingIterator implements FunctionalPrimitiveIterator.OfInt { - protected DoubleUnaryOperator function; + /** The function the Iterator uses to map the elements */ + protected final IntUnaryOperator function; - public FromDoubleToDouble(IterableDouble iterable, DoubleUnaryOperator function) + /** + * Constructor for an Iterator that maps elements using a function. + * + * @param iterator an Iterator to be mapped + * @param function a function used to map the elements + */ + public IntToInt(PrimitiveIterator.OfInt iterator, IntUnaryOperator function) { - this(iterable.iterator(), function); + super(iterator); + Objects.requireNonNull(function); + this.function = function; } - public FromDoubleToDouble(OfDouble iterator, DoubleUnaryOperator function) + @Override + public int nextInt() { - super(iterator); - this.function = function; + requireNext(); + return function.applyAsInt(iterator.nextInt()); } @Override - public double nextDouble() + public void release() { - return function.applyAsDouble(((OfDouble) iterator).nextDouble()); + iterator = EmptyIterator.ofInt(); } } - /** Map an iterator over doubles to an iterator over longs */ - public static class FromDoubleToLong extends MappingIterator implements OfLong - { - protected DoubleToLongFunction function; - public FromDoubleToLong(IterableDouble iterable, DoubleToLongFunction function) - { - this(iterable.iterator(), function); - } - public FromDoubleToLong(OfDouble iterator, DoubleToLongFunction function) + /** + * Primitive specialisation of a MappingIterator using a function {@code f: int -> long}. + */ + public static class IntToLong extends MappingIterator implements FunctionalPrimitiveIterator.OfLong + { + /** The function the Iterator uses to map the elements */ + protected final IntToLongFunction function; + + /** + * Constructor for an Iterator that maps elements using a function. + * + * @param iterator an Iterator to be mapped + * @param function a function used to map the elements + */ + public IntToLong(PrimitiveIterator.OfInt iterator, IntToLongFunction function) { super(iterator); + Objects.requireNonNull(function); this.function = function; } @Override public long nextLong() { - return function.applyAsLong(((OfDouble) iterator).nextDouble()); + requireNext(); + return function.applyAsLong(iterator.nextInt()); + } + + @Override + public void release() + { + iterator = EmptyIterator.ofInt(); } } - /** Map an iterator over longs to an iterator over T */ - public static class FromLong extends MappingIterator + + + /** + * Primitive specialisation of a MappingIterator using a function {@code f: long -> E}. + * + * @param type of the Iterator's elements after mapping + */ + public static class LongToObj extends MappingIterator { - protected LongFunction function; + /** The function the Iterator uses to map the elements */ + protected final LongFunction function; - public FromLong(IterableLong iterable, LongFunction function) + /** + * Constructor for an Iterator that maps elements using a function. + * + * @param iterator an Iterator to be mapped + * @param function a function used to map the elements + */ + public LongToObj(OfLong iterator, LongFunction function) { - this(iterable.iterator(), function); + super(iterator); + Objects.requireNonNull(function); + this.function = function; } - public FromLong(OfLong iterator, LongFunction function) + @Override + public E next() { - super(iterator); - this.function = function; + requireNext(); + return function.apply(iterator.nextLong()); } @Override - public T next() + public void release() { - return function.apply(((OfLong) iterator).nextLong()); + iterator = EmptyIterator.ofLong(); } } - /** Map an iterator over longs to an iterator over integers */ - public static class FromLongToInt extends MappingIterator implements OfInt + + + /** + * Primitive specialisation of a MappingIterator using a function {@code f: long -> double}. + */ + public static class LongToDouble extends MappingIterator implements FunctionalPrimitiveIterator.OfDouble { - protected LongToIntFunction function; + /** The function the Iterator uses to map the elements */ + protected final LongToDoubleFunction function; - public FromLongToInt(IterableLong iterable, LongToIntFunction function) + /** + * Constructor for an Iterator that maps elements using a function. + * + * @param iterator an Iterator to be mapped + * @param function a function used to map the elements + */ + public LongToDouble(PrimitiveIterator.OfLong iterator, LongToDoubleFunction function) { - this(iterable.iterator(), function); + super(iterator); + Objects.requireNonNull(function); + this.function = function; } - public FromLongToInt(OfLong iterator, LongToIntFunction function) + @Override + public double nextDouble() { - super(iterator); - this.function = function; + requireNext(); + return function.applyAsDouble(iterator.nextLong()); } @Override - public int nextInt() + public void release() { - return function.applyAsInt(((OfLong) iterator).nextLong()); + iterator = EmptyIterator.ofLong(); } } - /** Map an iterator over longs to an iterator over doubles */ - public static class FromLongToDouble extends MappingIterator implements OfDouble + + + /** + * Primitive specialisation of a MappingIterator using a function {@code f: long -> int}. + */ + public static class LongToInt extends MappingIterator implements FunctionalPrimitiveIterator.OfInt { - protected LongToDoubleFunction function; + /** The function the Iterator uses to map the elements */ + protected final LongToIntFunction function; - public FromLongToDouble(IterableLong iterable, LongToDoubleFunction function) + /** + * Constructor for an Iterator that maps elements using a function. + * + * @param iterator an Iterator to be mapped + * @param function a function used to map the elements + */ + public LongToInt(PrimitiveIterator.OfLong iterator, LongToIntFunction function) { - this(iterable.iterator(), function); + super(iterator); + Objects.requireNonNull(function); + this.function = function; } - public FromLongToDouble(OfLong iterator, LongToDoubleFunction function) + @Override + public int nextInt() { - super(iterator); - this.function = function; + requireNext(); + return function.applyAsInt(iterator.nextLong()); } @Override - public double nextDouble() + public void release() { - return function.applyAsDouble(((OfLong) iterator).nextLong()); + iterator = EmptyIterator.ofLong(); } } - /** Map an iterator over longs to another iterator over longs */ - public static class FromLongToLong extends MappingIterator implements OfLong - { - protected LongUnaryOperator function; - public FromLongToLong(IterableLong iterable, LongUnaryOperator function) - { - this(iterable.iterator(), function); - } - public FromLongToLong(OfLong iterator, LongUnaryOperator function) + /** + * Primitive specialisation of a MappingIterator using a function {@code f: long -> long}. + */ + public static class LongToLong extends MappingIterator implements FunctionalPrimitiveIterator.OfLong + { + /** The function the Iterator uses to map the elements */ + protected final LongUnaryOperator function; + + /** + * Constructor for an Iterator that maps elements using a function. + * + * @param iterator an Iterator to be mapped + * @param function a function used to map the elements + */ + public LongToLong(PrimitiveIterator.OfLong iterator, LongUnaryOperator function) { super(iterator); + Objects.requireNonNull(function); this.function = function; } @Override public long nextLong() { - return function.applyAsLong(((OfLong) iterator).nextLong()); + requireNext(); + return function.applyAsLong(iterator.nextLong()); + } + + @Override + public void release() + { + iterator = EmptyIterator.ofLong(); } } -} +} \ No newline at end of file diff --git a/prism/src/common/iterable/PrimitiveIterable.java b/prism/src/common/iterable/PrimitiveIterable.java new file mode 100644 index 0000000000..6939c2732f --- /dev/null +++ b/prism/src/common/iterable/PrimitiveIterable.java @@ -0,0 +1,234 @@ +//============================================================================== +// +// Copyright (c) 2016- +// Authors: +// * Steffen Maercker (TU Dresden) +// +//------------------------------------------------------------------------------ +// +// This file is part of PRISM. +// +// PRISM is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// PRISM 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 for more details. +// +// You should have received a copy of the GNU General Public License +// along with PRISM; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//============================================================================== + +package common.iterable; + +import java.util.Iterator; +import java.util.Objects; +import java.util.PrimitiveIterator; +import java.util.function.DoubleConsumer; +import java.util.function.IntConsumer; +import java.util.function.LongConsumer; + +/** + * A base interface for primitive specializations of {@code Iterable}. + * Specialized sub interfaces are provided for the types {@link OfInt int}, {@link OfLong long} and {@link OfDouble double}. + * + * @param the type of elements hold by this PrimitiveIterable + * @param the type of primitive consumer + * + * @see Iterable + * @see PrimitiveIterator + */ +public interface PrimitiveIterable extends Iterable +{ + /** + * Convert an Iterable<Double> to a PrimitiveIterable.OfDouble by unboxing each element. + * If the argument's Iterator yields {@code null}, a {@link NullPointerException} is thrown when iterating. + * Answer the Iterable if it already implements of PrimitiveIterable.OfDouble. + * + * @param iterable the {@link Iterable}<Double> to extend + * @return a {@link PrimitiveIterable.OfDouble} that is either the argument or an adaptor on the argument + */ + static PrimitiveIterable.OfDouble unboxDouble(Iterable iterable) + { + Objects.requireNonNull(iterable); + + return () -> unboxDouble(iterable.iterator()); + } + + /** + * Convert an Iterator<Double> to a PrimitiveIterator.OfDouble by unboxing each element. + * If the Iterator yields {@code null}, a {@link NullPointerException} is thrown when iterating. + * Answer the Iterator if it already implements of PrimitiveIterator.OfDouble. + * + * @param iterator the {@link Iterator}<Double> to extend + * @return a {@link PrimitiveIterator.OfDouble} that is either the argument or an adaptor on the argument + */ + static PrimitiveIterator.OfDouble unboxDouble(Iterator iterator) + { + Objects.requireNonNull(iterator); + + if (iterator instanceof PrimitiveIterator.OfDouble) { + return (PrimitiveIterator.OfDouble) iterator; + } + + return new PrimitiveIterator.OfDouble() + { + @Override + public boolean hasNext() + { + return iterator.hasNext(); + } + + @Override + public double nextDouble() + { + return iterator.next(); + } + }; + } + + /** + * Convert an Iterable<Integer> to a PrimitiveIterable.OfInt by unboxing each element. + * If the argument's Iterator yields {@code null}, a {@link NullPointerException} is thrown when iterating. + * Answer the Iterable if it already implements of PrimitiveIterable.OfInt. + * + * @param iterable the {@link Iterable}<Integer> to extend + * @return a {@link PrimitiveIterable.OfInt} that is either the argument or an adaptor on the argument + */ + static PrimitiveIterable.OfInt unboxInt(Iterable iterable) + { + Objects.requireNonNull(iterable); + + return () -> unboxInt(iterable.iterator()); + } + + /** + * Convert an Iterator<Integer> to a PrimitiveIterator.OfInt by unboxing each element. + * If the Iterator yields {@code null}, a {@link NullPointerException} is thrown when iterating. + * Answer the Iterator if it already implements of PrimitiveIterator.OfInt. + * + * @param iterator the {@link Iterator}<Integer> to extend + * @return a {@link PrimitiveIterator.OfInt} that is either the argument or an adaptor on the argument + */ + static PrimitiveIterator.OfInt unboxInt(Iterator iterator) + { + Objects.requireNonNull(iterator); + + if (iterator instanceof PrimitiveIterator.OfInt) { + return (PrimitiveIterator.OfInt) iterator; + } + + return new PrimitiveIterator.OfInt() + { + @Override + public boolean hasNext() + { + return iterator.hasNext(); + } + + @Override + public int nextInt() + { + return iterator.next(); + } + }; + } + + /** + * Convert an Iterable<Long> to a PrimitiveIterable.OfLong by unboxing each element. + * If the argument's Iterator yields {@code null}, a {@link NullPointerException} is thrown when iterating. + * Answer the Iterable if it already implements of PrimitiveIterable.OfLong. + * + * @param iterable the {@link Iterable}<Long> to extend + * @return a {@link PrimitiveIterable.OfLong} that is either the argument or an adaptor on the argument + */ + static PrimitiveIterable.OfLong unboxLong(Iterable iterable) + { + Objects.requireNonNull(iterable); + + return () -> unboxLong(iterable.iterator()); + } + + /** + * Convert an Iterator<Long> to a PrimitiveIterator.OfLong by unboxing each element. + * If the Iterator yields {@code null}, a {@link NullPointerException} is thrown when iterating. + * Answer the Iterator if it already implements of PrimitiveIterator.OfLong. + * + * @param iterator the {@link Iterator}<Long> to extend + * @return a {@link PrimitiveIterator.OfLong} that is either the argument or an adaptor on the argument + */ + static PrimitiveIterator.OfLong unboxLong(Iterator iterator) + { + Objects.requireNonNull(iterator); + + if (iterator instanceof PrimitiveIterator.OfLong) { + return (PrimitiveIterator.OfLong) iterator; + } + + return new PrimitiveIterator.OfLong() + { + @Override + public boolean hasNext() + { + return iterator.hasNext(); + } + + @Override + public long nextLong() + { + return iterator.next(); + } + }; + } + + @Override + PrimitiveIterator iterator(); + + /** + * Perform the given action for each element of the receiver. + * + * @see Iterable#forEach(java.util.function.Consumer) + */ + default void forEach(E_CONS action) + { + iterator().forEachRemaining(action); + } + + + + /** + * Specialisation for {@code double} of a PrimitiveIterable. + */ + interface OfDouble extends PrimitiveIterable + { + @Override + PrimitiveIterator.OfDouble iterator(); + } + + + + /** + * Specialisation for {@code int} of a PrimitiveIterable. + */ + interface OfInt extends PrimitiveIterable + { + @Override + PrimitiveIterator.OfInt iterator(); + } + + + + /** + * Specialisation for {@code long} of a PrimitiveIterable. + */ + interface OfLong extends PrimitiveIterable + { + @Override + PrimitiveIterator.OfLong iterator(); + } +} diff --git a/prism/src/common/iterable/PrimitiveReducible.java b/prism/src/common/iterable/PrimitiveReducible.java new file mode 100644 index 0000000000..824bd9d56e --- /dev/null +++ b/prism/src/common/iterable/PrimitiveReducible.java @@ -0,0 +1,922 @@ +package common.iterable; + +import common.functions.*; + +import java.util.*; +import java.util.function.*; + +/** + * A base type for primitive specializations of the methods provided by {@link Reducible}. + * Specialized sub interfaces are provided for {@code double}, {@code int} and {@code long}: + *

    + *
  • {@link PrimitiveReducible.OfDouble}
  • + *
  • {@link PrimitiveReducible.OfInt}
  • + *
  • {@link PrimitiveReducible.OfLong}
  • + *
+ * + * @param the type of elements returned by this Reducible + * @param the type of primitive consumers for the elements + * + * @see java.util.stream.DoubleStream DoubleStream + * @see java.util.stream.IntStream IntStream + * @see java.util.stream.LongStream LongStream + */ +public interface PrimitiveReducible extends Reducible +{ + /** + * Primitive specialisation of {@link Reducible#forEach}. + * + * @param action the action to be performed with each element + * @see PrimitiveIterator#forEachRemaining(Object); + */ + void forEach(E_CONS action); + + + + /** + * Specialisation for {@code double} of a {@link PrimitiveReducible}. + */ + interface OfDouble extends PrimitiveReducible + { + // Transforming Methods + + @Override + default OfDouble dedupe() + { + DoublePredicate isFirst = new DoublePredicate() + { + boolean start = true; + double previous = 0.0; + + @Override + public boolean test(double d) + { + if (start) { + start = false; + } else if (previous == d) { + return false; + } else if (Double.isNaN(previous) && Double.isNaN(d)) { + // Circumvent Double.NaN != Double.NaN + return false; + } + previous = d; + return true; + } + }; + return filter(isFirst); + } + + @Override + default OfDouble distinct() + { + return filter(new Distinct.OfDouble()); + } + + /** + * Primitive specialisation of {@code filter} for {@code double}. + * + * @see Reducible#filter(java.util.function.Predicate) + */ + OfDouble filter(DoublePredicate predicate); + + /** + * Primitive specialisation of {@code map} for {@code double}. + * + * @see Reducible#map(java.util.function.Function) + */ + Reducible map(DoubleFunction function); + + /** + * Primitive specialisation of {@code mapToDouble} for {@code double}. + * + * @see Reducible#mapToDouble(java.util.function.ToDoubleFunction) + */ + OfDouble mapToDouble(DoubleUnaryOperator function); + + /** + * Primitive specialisation of {@code mapToInt} for {@code double}. + * + * @see Reducible#mapToInt(java.util.function.ToIntFunction) + */ + OfInt mapToInt(DoubleToIntFunction function); + + /** + * Primitive specialisation of {@code mapToLong} for {@code double}. + * + * @see Reducible#mapToLong(java.util.function.ToLongFunction) + */ + OfLong mapToLong(DoubleToLongFunction function); + + + + + // Accumulations Methods (Consuming) + + @Override + default OfDouble consume() + { + forEach((double each) -> {}); + return this; + } + + /** + * Primitive specialisation of {@code allMatch} for {@code double}. + * + * @see Reducible#allMatch(java.util.function.Predicate) + */ + default boolean allMatch(DoublePredicate predicate) + { + return ! anyMatch(predicate.negate()); + } + + /** + * Primitive specialisation of {@code anyMatch} for {@code double}. + * + * @see Reducible#anyMatch(java.util.function.Predicate) + */ + default boolean anyMatch(DoublePredicate predicate) + { + return ! filter(predicate).isEmpty(); + } + + /** + * Primitive specialisation of {@code noneMatch} for {@code double}. + * + * @see Reducible#noneMatch(java.util.function.Predicate) + */ + default boolean noneMatch(DoublePredicate predicate) + { + return ! anyMatch(predicate); + } + + /** + * Primitive specialisation of {@code collect} for {@code double}. + * + * @see Reducible#collect(Object[]) + */ + default double[] collect(double[] array) + { + return collect(array, 0); + } + + /** + * Primitive specialisation of {@code collect} for {@code double}. + * + * @see Reducible#collect(Object[], int) + */ + default double[] collect(double[] array, int offset) + { + collectAndCount(array, offset); + return array; + } + + /** + * Primitive specialisation of {@code collectAndCount} for {@code double}. + * + * @see Reducible#collectAndCount(Object[]) + */ + default int collectAndCount(double[] array) + { + return collectAndCount(array, 0); + } + + /** + * Primitive specialisation of {@code collectAndCount} for {@code double}. + * + * @see Reducible#collectAndCount(Object[], int) + */ + default int collectAndCount(double[] array, int offset) + { + Objects.requireNonNull(array); + int index = reduce(offset, (int i, double e) -> { + array[i] = e; + return i + 1; + }); + return index - offset; + } + + @Override + default FunctionalPrimitiveIterable.OfDouble collectDistinct() + { + Distinct.OfDouble unseen = new Distinct.OfDouble(); + filter(unseen).consume(); + return unseen.getSeen(); + } + + @Override + default boolean contains(Object obj) + { + if (obj instanceof Double) { + return contains(((Double) obj).doubleValue()); + } + return false; + } + + /** + * Primitive specialisation of {@code contains} for {@code double}. + * Inclusion is defined in terms of {@link ==} except for {@code NaN} for which all instances are consider equal, although {@code Double.NaN != Double.NaN}. + * + * @see Reducible#contains(Object) + */ + default boolean contains(double d) + { + return anyMatch(Double.isNaN(d) ? (double e) -> Double.isNaN(e) : (double e) -> e == d); + } + + @Override + default long count() + { + // avoid auto-boxing + return reduce(0L, (long c, double d) -> c + 1); + } + + /** + * Primitive specialisation of {@code count} for {@code double}. + * + * @see Reducible#count(java.util.function.Predicate) + */ + default long count(DoublePredicate predicate) + { + return filter(predicate).count(); + } + + /** + * Primitive specialisation of {@code detect} for {@code double}. + * + * @see Reducible#detect(java.util.function.Predicate) + */ + double detect(DoublePredicate predicate); + + /** + * Find the maximum. + * + * @return an {@link OptionalDouble} either containing the maximum or being empty if the receiver is empty + * @see Math#max(double, double). + */ + default OptionalDouble max() + { + return reduce((DoubleBinaryOperator) Math::max); + } + + /** + * Find the minimum. + * + * @return an {@link OptionalDouble} either containing the minimum or being empty if the receiver is empty + * @see Math#min(double, double). + */ + default OptionalDouble min() + { + return reduce((DoubleBinaryOperator) Math::min); + } + + /** + * Primitive specialisation of {@code reduce} for {@code double}. + * + * @see Reducible#reduce(java.util.function.BinaryOperator) + */ + OptionalDouble reduce(DoubleBinaryOperator accumulator); + + /** + * Primitive specialisation of {@code reduce} for {@code double}. + * + * @see Reducible#reduce(Object, java.util.function.BiFunction) + */ + T reduce(T init, ObjDoubleFunction accumulator); + + /** + * Primitive specialisation of {@code reduce} for {@code double}. + * + * @see Reducible#reduce(double, common.functions.DoubleObjToDoubleFunction) + */ + double reduce(double init, DoubleBinaryOperator accumulator); + + /** + * Primitive specialisation of {@code reduce} for {@code double}. + * + * @see Reducible#reduce(int, common.functions.IntObjToIntFunction) + */ + int reduce(int init, IntDoubleToIntFunction accumulator); + + /** + * Primitive specialisation of {@code reduce} for {@code double}. + * + * @see Reducible#reduce(long, common.functions.LongObjToLongFunction) + */ + long reduce(long init, LongDoubleToLongFunction accumulator); + + /** + * Compute the sum over all elements of the receiver. + * + * @return the sum over all elements or 0 if the receiver is empty + */ + default double sum() + { + return reduce(0.0, (DoubleBinaryOperator) Double::sum); + } + } + + + + /** + * Specialisation for {@code int} of a PrimitiveReducible. + */ + interface OfInt extends PrimitiveReducible + { + // Transforming Methods + + @Override + default OfInt dedupe() + { + IntPredicate isFirst = new IntPredicate() + { + boolean start = true; + int previous = 0; + + @Override + public boolean test(int i) + { + if (start) { + start = false; + } else if (previous == i) { + return false; + } + previous = i; + return true; + } + }; + return filter(isFirst); + } + + @Override + default OfInt distinct() + { + return filter(new Distinct.OfInt()); + } + + /** + * Primitive specialisation of {@code filter} for {@code int}. + * + * @see Reducible#filter(java.util.function.Predicate) + */ + OfInt filter(IntPredicate predicate); + + /** + * Primitive specialisation of {@code map} for {@code int}. + * + * @see Reducible#map(java.util.function.Function) + */ + Reducible map(IntFunction function); + + /** + * Primitive specialisation of {@code mapToDouble} for {@code int}. + * + * @see Reducible#mapToDouble(java.util.function.ToDoubleFunction) + */ + OfDouble mapToDouble(IntToDoubleFunction function); + + /** + * Primitive specialisation of {@code mapToInt} for {@code int}. + * + * @see Reducible#mapToInt(java.util.function.ToIntFunction) + */ + OfInt mapToInt(IntUnaryOperator function); + + /** + * Primitive specialisation of {@code mapToLong} for {@code int}. + * + * @see Reducible#mapToLong(java.util.function.ToLongFunction) + */ + OfLong mapToLong(IntToLongFunction function); + + + // Accumulations Methods (Consuming) + + @Override + default OfInt consume() + { + forEach((int each) -> {}); + return this; + } + + /** + * Primitive specialisation of {@code allMatch} for {@code int}. + * + * @see Reducible#allMatch(java.util.function.Predicate) + */ + default boolean allMatch(IntPredicate predicate) + { + return ! anyMatch(predicate.negate()); + } + + /** + * Primitive specialisation of {@code anyMatch} for {@code int}. + * + * @see Reducible#anyMatch(java.util.function.Predicate) + */ + default boolean anyMatch(IntPredicate predicate) + { + return ! filter(predicate).isEmpty(); + } + + /** + * Primitive specialisation of {@code noneMatch} for {@code int}. + * + * @see Reducible#noneMatch(java.util.function.Predicate) + */ + default boolean noneMatch(IntPredicate predicate) + { + return ! anyMatch(predicate); + } + + /** + * Primitive specialisation of {@code collect} for {@code int}. + * + * @see Reducible#collect(Object[]) + */ + default int[] collect(int[] array) + { + return collect(array, 0); + } + + /** + * Primitive specialisation of {@code collect} for {@code int}. + * + * @see Reducible#collect(Object[], int) + */ + default int[] collect(int[] array, int offset) + { + collectAndCount(array, offset); + return array; + } + + /** + * Primitive specialisation of {@code collect} for {@code int} storing the elements in a {@link BitSet}. + * This method fails if the receiver yields a negative integer. + * + * @param indices a {@link BitSet} + * @return the BitSet with all elements added to it + * @throws IndexOutOfBoundsException if an integer is negative + * @see Reducible#collect(java.util.Collection) + */ + default BitSet collect(BitSet indices) + { + forEach((IntConsumer) indices::set); + return indices; + } + + /** + * Primitive specialisation of {@code collectAndCount} for {@code int}. + * + * @see Reducible#collectAndCount(Object[]) + */ + default int collectAndCount(int[] array) + { + return collectAndCount(array, 0); + } + + /** + * Primitive specialisation of {@code collectAndCount} for {@code int}. + * + * @see Reducible#collectAndCount(Object[]) + */ + default int collectAndCount(int[] array, int offset) + { + Objects.requireNonNull(array); + int index = reduce(offset, (int i, int e) -> { + array[i] = e; + return i + 1; + }); + return index - offset; + } + + /** + * Primitive specialisation of {@code collectAndCount} for {@code int} storing the elements in a {@link BitSet}. + * This method fails if the receiver yields a negative integer. + * + * @param indices a {@link BitSet} + * @return the number of elements added to the BitSet + * @throws IndexOutOfBoundsException if an integer is negative + * @see Reducible#collectAndCount(java.util.Collection) + */ + default int collectAndCount(BitSet indices) + { + Objects.requireNonNull(indices); + return reduce(0, (int c, int i) -> { + indices.set(i); + return c + 1; + }); + } + + @Override + default FunctionalPrimitiveIterable.OfInt collectDistinct() + { + Distinct.OfInt unseen = new Distinct.OfInt(); + filter(unseen).consume(); + return unseen.getSeen(); + } + + @Override + default boolean contains(Object obj) + { + if (obj instanceof Integer) { + return contains(((Integer) obj).intValue()); + } + return false; + } + + /** + * Primitive specialisation of {@code contains} for {@code int}. + * + * @see Reducible#contains(Object) + */ + default boolean contains(int i) + { + return anyMatch((int e) -> e == i); + } + + @Override + default long count() + { + // avoid auto-boxing + return reduce(0, (long c, long i) -> c + 1); + } + + /** + * Primitive specialisation of {@code count} for {@code int}. + * + * @see Reducible#count(java.util.function.Predicate) + */ + default long count(IntPredicate predicate) + { + return filter(predicate).count(); + } + + /** + * Primitive specialisation of {@code detect} for {@code int}. + * + * @see Reducible#detect(java.util.function.Predicate) + */ + int detect(IntPredicate predicate); + + /** + * Find the maximum. + * + * @return an {@link OptionalDouble} either containing the maximum or being empty if the receiver is empty + * @see Math#max(int, int). + */ + default OptionalInt max() + { + return reduce((IntBinaryOperator) Math::max); + } + + /** + * Find the minimum. + * + * @return an {@link OptionalDouble} either containing the minimum or being empty if the receiver is empty + * @see Math#min(int, int). + */ + default OptionalInt min() + { + return reduce((IntBinaryOperator) Math::min); + } + + /** + * Primitive specialisation of {@code reduce} for {@code double}. + * This methods exploits the widening primitive conversion from {@code int} to {@code double}. + * + * @see Reducible#reduce(java.util.function.BinaryOperator) + */ + OptionalDouble reduce(DoubleBinaryOperator accumulator); + + /** + * Primitive specialisation of {@code reduce} for {@code int}. + * + * @see Reducible#reduce(java.util.function.BinaryOperator) + */ + OptionalInt reduce(IntBinaryOperator accumulator); + + /** + * Primitive specialisation of {@code reduce} for {@code long}. + * This methods exploits the widening primitive conversion from {@code int} to {@code long}. + * + * @see Reducible#reduce(java.util.function.BinaryOperator) + */ + OptionalLong reduce(LongBinaryOperator accumulator); + + /** + * Primitive specialisation of {@code reduce} for {@code int}. + * + * @see Reducible#reduce(Object, java.util.function.BiFunction) + */ + T reduce(T init, ObjIntFunction accumulator); + + /** + * Primitive specialisation of {@code reduce} for {@code double}. + * This methods exploits the widening primitive conversion from {@code int} to {@code double}. + * + * @see Reducible#reduce(double, common.functions.DoubleObjToDoubleFunction) + */ + double reduce(double init, DoubleBinaryOperator accumulator); + + /** + * Primitive specialisation of {@code reduce} for {@code int}. + * + * @see Reducible#reduce(int, common.functions.IntObjToIntFunction) + */ + int reduce(int init, IntBinaryOperator accumulator); + + /** + * Primitive specialisation of {@code reduce} for {@code long}. + * This methods exploits the widening primitive conversion from {@code int} to {@code long}. + * + * @see Reducible#reduce(long, common.functions.LongObjToLongFunction) + */ + long reduce(long init, LongBinaryOperator accumulator); + + /** + * Compute the sum over all elements of the receiver. + * + * @return the sum over all elements or 0 if the receiver is empty + */ + default long sum() + { + return reduce(0L, (LongBinaryOperator) Long::sum); + } + } + + + + /** + * Specialisation for {@code long} of a PrimitiveReducible. + */ + interface OfLong extends PrimitiveReducible + { + // Transforming Methods + + @Override + default OfLong dedupe() + { + LongPredicate isFirst = new LongPredicate() + { + boolean start = true; + long previous = 0; + + @Override + public boolean test(long l) + { + if (start) { + start = false; + } else if (previous == l) { + return false; + } + previous = l; + return true; + } + }; + return filter(isFirst); + } + + @Override + default OfLong distinct() + { + return filter(new Distinct.OfLong()); + } + + /** + * Primitive specialisation of {@code filter} for {@code long}. + * + * @see Reducible#filter(java.util.function.Predicate) + */ + OfLong filter(LongPredicate predicate); + + /** + * Primitive specialisation of {@code map} for {@code long}. + * + * @see Reducible#map(java.util.function.Function) + */ + Reducible map(LongFunction function); + + /** + * Primitive specialisation of {@code map} for {@code long}. + * + * @see Reducible#mapToDouble(java.util.function.ToDoubleFunction) + */ + OfDouble mapToDouble(LongToDoubleFunction function); + + /** + * Primitive specialisation of {@code map} for {@code long}. + * + * @see Reducible#mapToInt(java.util.function.ToIntFunction) + */ + OfInt mapToInt(LongToIntFunction function); + + /** + * Primitive specialisation of {@code map} for {@code long}. + * + * @see Reducible#mapToLong(java.util.function.ToLongFunction) + */ + OfLong mapToLong(LongUnaryOperator function); + + + + // Accumulations Methods (Consuming) + + @Override + default OfLong consume() + { + forEach((long each) -> {}); + return this; + } + + /** + * Primitive specialisation of {@code allMatch} for {@code long}. + * + * @see Reducible#allMatch(java.util.function.Predicate) + */ + default boolean allMatch(LongPredicate predicate) + { + return ! anyMatch(predicate.negate()); + } + + /** + * Primitive specialisation of {@code anyMatch} for {@code long}. + * + * @see Reducible#anyMatch(java.util.function.Predicate) + */ + default boolean anyMatch(LongPredicate predicate) + { + return ! filter(predicate).isEmpty(); + } + + /** + * Primitive specialisation of {@code noneMatch} for {@code long}. + * + * @see Reducible#noneMatch(java.util.function.Predicate) + */ + default boolean noneMatch(LongPredicate predicate) + { + return ! anyMatch(predicate); + } + + /** + * Primitive specialisation of {@code collect} for {@code long}. + * + * @see Reducible#collect(Object[]) + */ + default long[] collect(long[] array) + { + return collect(array, 0); + } + + /** + * Primitive specialisation of {@code collect} for {@code long}. + * + * @see Reducible#collect(Object[], int) + */ + default long[] collect(long[] array, int offset) + { + collectAndCount(array, offset); + return array; + } + + /** + * Primitive specialisation of {@code collectAndCount} for {@code long}. + * + * @see Reducible#collectAndCount(Object[]) + */ + default int collectAndCount(long[] array) + { + return collectAndCount(array, 0); + } + + /** + * Primitive specialisation of {@code collectAndCount} for {@code long}. + * + * @see Reducible#collectAndCount(Object[], int) + */ + default int collectAndCount(long[] array, int offset) + { + Objects.requireNonNull(array); + int index = reduce(offset, (int i, long e) -> {array[i] = e; return i + 1;}); + return index - offset; + } + + @Override + default FunctionalPrimitiveIterable.OfLong collectDistinct() + { + Distinct.OfLong unseen = new Distinct.OfLong(); + filter(unseen).consume(); + return unseen.getSeen(); + } + + @Override + default boolean contains(Object obj) + { + if (obj instanceof Long) { + return contains(((Long) obj).longValue()); + } + return false; + } + + /** + * Primitive specialisation of {@code contains} for {@code long}. + * + * @see Reducible#contains(Object) + */ + default boolean contains(long l) + { + return anyMatch((long e) -> e == l); + } + + @Override + default long count() + { + // avoid auto-boxing + return reduce(0, (long c, long l) -> c + 1); + } + + /** + * Primitive specialisation of {@code count} for {@code long}. + * + * @see Reducible#count(java.util.function.Predicate) + */ + default long count(LongPredicate predicate) + { + return filter(predicate).count(); + } + + /** + * Primitive specialisation of {@code detect} for {@code long}. + * + * @see Reducible#detect(java.util.function.Predicate) + */ + long detect(LongPredicate predicate); + + /** + * Find the maximum. + * + * @return an {@link OptionalDouble} either containing the maximum or being empty if the receiver is empty + * @see Math#max(long, long). + */ + default OptionalLong max() + { + return reduce((LongBinaryOperator) Math::max); + } + + /** + * Find the minimum. + * + * @return an {@link OptionalDouble} either containing the minimum or being empty if the receiver is empty + * @see Math#min(long, long). + */ + default OptionalLong min() + { + return reduce((LongBinaryOperator) Math::min); + } + + /** + * Primitive specialisation of {@code reduce} for {@code long}. + * + * @see Reducible#reduce(java.util.function.BinaryOperator) + */ + OptionalLong reduce(LongBinaryOperator accumulator); + + /** + * Primitive specialisation of {@code reduce} for {@code long}. + * + * @see Reducible#reduce(Object, java.util.function.BiFunction) + */ + T reduce(T init, ObjLongFunction accumulator); + + /** + * Primitive specialisation of {@code reduce} for {@code double}. + * + * @see Reducible#reduce(double, common.functions.DoubleObjToDoubleFunction) + */ + double reduce(double init, DoubleLongToDoubleFunction accumulator); + + /** + * Primitive specialisation of {@code reduce} for {@code int}. + * + * @see Reducible#reduce(int, common.functions.IntObjToIntFunction) + */ + int reduce(int init, IntLongToIntFunction accumulator); + + /** + * Primitive specialisation of {@code reduce} for {@code long}. + * + * @see Reducible#reduce(long, common.functions.LongObjToLongFunction) + */ + long reduce(long init, LongBinaryOperator accumulator); + + /** + * Compute the sum over all elements of the receiver. + * + * @return the sum over all elements or 0 if the receiver is empty + */ + default long sum() + { + return reduce(0L, (LongBinaryOperator) Long::sum); + } + } +} diff --git a/prism/src/common/iterable/Range.java b/prism/src/common/iterable/Range.java new file mode 100644 index 0000000000..bfa1b1475d --- /dev/null +++ b/prism/src/common/iterable/Range.java @@ -0,0 +1,419 @@ +package common.iterable; + +import java.util.OptionalInt; + +/** + * An Iterable that yields all integers between two values, first and last (both inclusive). + * The step width can be customized and defaults to 1. + *

+ * If {@code step > 0} then the sequence is
+ * ascending (start, start+1, ... , stop).
+ * otherwise
+ * descending (start, start-1, ... , stop).
+ */ +public class Range implements FunctionalPrimitiveIterable.OfInt +{ + protected final int first; // inclusive + protected final int last; // inclusive + protected final int step; + + /** + * Factory method for a range from {@code 0} to {@code stop} (both inclusive) + * with step width {@code 1}. + * + * @param stop last {@code int}, inclusive + * @throws ArithmeticException if enumerating the Range would cause an integer over- or underflow + */ + public static Range closed(int stop) + { + return closed(0, stop, 1); + } + + /** + * Factory method for a range from {@code start} to {@code stop} (both inclusive) + * with step width {@code 1}. + * + * @param start first {@code int}, inclusive + * @param stop last {@code int}, inclusive + * @throws ArithmeticException if enumerating the Range would cause an integer over- or underflow + */ + public static Range closed(int start, int stop) + { + return closed(start, stop, 1); + } + + /** + * Factory method for a range from {@code start} (inclusive) to {@code stop} (inclusive it it is a step) + * with step width {@code step}. + * + * @param start first {@code int}, inclusive + * @param stop last {@code int}, inclusive if it is a step + * @param step an {@code int != 0} giving the step width + * @throws ArithmeticException if enumerating the Range would cause an integer over- or underflow + */ + public static Range closed(int start, int stop, int step) + { + return new Range(start, stop, step, true); + } + + + + /** + * Constructor for a range from {@code 0} (inclusive) to {@code stop} (exclusive) + * with step width 1. + * + * @param stop last {@code int}, exclusive + * @throws ArithmeticException if enumerating the Range would cause an integer over- or underflow + */ + public Range(int stop) + { + this(0, stop); + } + + /** + * Constructor for a range from {@code start} (inclusive) to {@code stop} (exclusive) + * with step width 1. + * + * @param start first {@code int}, inclusive + * @param stop last {@code int}, exclusive + * @throws ArithmeticException if enumerating the Range would cause an integer over- or underflow + */ + public Range(int start, int stop) + { + this(start, stop, 1); + } + + /** + * Constructor for a range from {@code start} (inclusive) to {@code stop} (exclusive) + * with step width {@code step}. + * + * @param start first {@code int}, inclusive + * @param stop last {@code int}, exclusive + * @param step an {@code int != 0} giving the step width + * @throws ArithmeticException if enumerating the Range would cause an integer over- or underflow + */ + public Range(int start, int stop, int step) + { + this(start, stop, step, false); + } + + /** + * Constructor for a range from {@code start} (inclusive) to {@code stop} (inclusive or exclusive) + * with step width {@code step}. + * If {@code step > 0} the range is ascending and otherwise descending. + * + * @param start first {@code int}, inclusive + * @param stop last {@code int}, inclusive if it is a step and {@code closed == true} + * @param step an {@code int != 0} + * @param closed flag whether {@code stop} is inclusive ({@code true}) or not ({@code false}) + * @throws ArithmeticException if enumerating the Range would cause an integer over- or underflow + */ + private Range(int start, int stop, int step, boolean closed) + { + if (step == 0) { + throw new IllegalArgumentException("Expected: step != 0"); + } + // convert to inclusive bound + if (!closed) { + stop = Math.addExact(stop, (step > 0) ? -1 : +1); + } + // normalize parameters + long distance = (long) stop - (long) start; + if ((step > 0 && distance < 0) || (step < 0 && distance > 0)) { + // empty range + this.first = 0; + this.last = -1; + this.step = 1; + } else { + // non-empty range + this.first = start; + // calculate last element + this.last = (int) (start + (distance / step) * step); + // set step = 1 for singleton ranges + this.step = (this.first == this.last) ? 1 : step; + } + // check for over- and underflows + checkForOverAndUnderflows(); + } + + /** + * Check that the iteration does not over- or underflow at Integer.MAX_VALUE or Integer.MIN_VALUE. + */ + private void checkForOverAndUnderflows() + { + if (isAscending()) { + if (last + step < last) { + throw new ArithmeticException("integer overflow"); + } + } else { + if (last + step > last) { + throw new ArithmeticException("integer underflow"); + } + } + } + + /** + * Answer whether the receiver is in ascending order. + * Empty and singleton ranges are ascending by default. + */ + public boolean isAscending() + { + return step > 0; + } + + /** + * Answer whether the receiver contains exactly one number. + */ + public boolean isSingleton() + { + return first == last; + } + + /** + * Return a new range with all elements in reverse order. + */ + public Range reversed() + { + return new Range(last, first, -step, true); + } + + @Override + public RangeIterator iterator() + { + if (isAscending()) { + return new AscendingRangeIterator(); + } else { + return new DescendingRangeIterator(); + } + } + + @Override + public boolean isEmpty() + { + // Empty ranges are ascending by default. + return isAscending() && first > last; + } + + @Override + public String toString() + { + return getClass().getSimpleName() + ".closed(" + first + ", " + last + ", " + step + ")"; + } + + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() + { + final int prime = 31; + int result = 1; + if (isEmpty()) { + return result; + } + result = prime * result + first; + result = prime * result + last; + result = prime * result + step; + return result; + } + + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) + { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof Range)) { + return false; + } + Range other = (Range) obj; + if (first != other.first) { + return false; + } + if (last != other.last) { + return false; + } + if (step != other.step) { + return false; + } + return true; + } + + + + /** + * A abstract base class for an Iterator from {@code first} (inclusive) and {@code last} (exclusive) with a custom step width. + */ + protected abstract class RangeIterator implements FunctionalPrimitiveIterator.OfInt + { + protected int next; + + /** + * Constructor for a range Iterator. + */ + public RangeIterator() + { + assert step != 0 : "Expected: step != 0"; + this.next = first; + } + + @Override + public int nextInt() + { + requireNext(); + int current = next; + next += step; + return current; + } + + @Override + public long count() + { + if (!hasNext()) { + return 0; + } + long count = ((long) last - (long) next) / step + 1; + release(); + return count; + } + + @Override + public long sum() + { + if (!hasNext()) { + return 0; + } + // S(1..n) = k + (k+s) + (k+2s) + ... + (k+(n-1)s) + // S(1..n) = n(2k + (n-1)s) / 2 + long k = next; // store next, since count() exhausts the iterator + long count = count(); + long sum = count * (2 * k + (count - 1) * step) / 2; + release(); + return sum; + } + + @Override + public void release() + { + next = last + step; + } + } + + + + /** + * Ascending Iterator from {@code first} (inclusive) and {@code last} (inclusive) with a custom step width. + */ + protected class AscendingRangeIterator extends RangeIterator + { + /** + * Constructor for an ascending Iterator. + */ + public AscendingRangeIterator() + { + super(); + assert step > 0 : "Expected: step > 0"; + } + + @Override + public boolean hasNext() + { + return next <= last; + } + + @Override + public boolean contains(int i) + { + // Is in interval? + boolean inInterval = (i >= next) && (i <= last); + // Is a step? Mind potential overflow! + boolean contains = inInterval && (((long) i - (long) next) % step) == 0; + release(); + return contains; + } + + @Override + public OptionalInt max() + { + if (!hasNext()) { + return OptionalInt.empty(); + } + OptionalInt max = OptionalInt.of(last); + release(); + return max; + } + + @Override + public OptionalInt min() + { + if (!hasNext()) { + return OptionalInt.empty(); + } + OptionalInt min = OptionalInt.of(next); + release(); + return min; + } + } + + + + /** + * Descending Iterator from {@code first} (inclusive) and {@code last} (inclusive) with a custom step width. + */ + protected class DescendingRangeIterator extends RangeIterator + { + /** + * Constructor for an descending Iterator. + */ + public DescendingRangeIterator() + { + super(); + assert step < 0 : "Expected: step < 0"; + } + + @Override + public boolean hasNext() + { + return next >= last; + } + + @Override + public boolean contains(int i) + { + // Is in interval? + boolean inInterval = (i <= next) && (i >= last); + // Is a step? Mind potential overflow! + boolean contains = inInterval && (((long) i - (long) next) % step) == 0; + release(); + return contains; + } + + @Override + public OptionalInt max() + { + if (!hasNext()) { + return OptionalInt.empty(); + } + OptionalInt max = OptionalInt.of(next); + release(); + return max; + } + + @Override + public OptionalInt min() + { + if (!hasNext()) { + return OptionalInt.empty(); + } + OptionalInt min = OptionalInt.of(last); + release(); + return min; + } + } +} diff --git a/prism/src/common/iterable/RangeIntIterable.java b/prism/src/common/iterable/RangeIntIterable.java deleted file mode 100644 index c8e220d8c2..0000000000 --- a/prism/src/common/iterable/RangeIntIterable.java +++ /dev/null @@ -1,87 +0,0 @@ -//============================================================================== -// -// Copyright (c) 2016- -// Authors: -// * Joachim Klein (TU Dresden) -// -//------------------------------------------------------------------------------ -// -// This file is part of PRISM. -// -// PRISM is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// PRISM 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 for more details. -// -// You should have received a copy of the GNU General Public License -// along with PRISM; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -//============================================================================== - - -package common.iterable; - -import java.util.PrimitiveIterator; - -/** - * An Iterable that returns a Primitive.OfInt iterator for all the integers - * between two values, first and last (inclusive). - * If first > last, then the sequence is descending (first, first-1, ..., last+1, last), - * otherwise it is ascending (first, first+1, ..., last-1, last). - */ -public class RangeIntIterable implements IterableInt -{ - /** The first integer of the sequence */ - final private int first; - /** The last integer of the sequence */ - final private int last; - /** Are we ascending? */ - final private boolean ascending; - - /** - * Constructor - * @param first the first integer in the sequence - * @param last the last integer in the sequence - */ - public RangeIntIterable(int first, int last) - { - this.first = first; - this.last = last; - ascending = (first <= last); - } - - @Override - public PrimitiveIterator.OfInt iterator() - { - return new PrimitiveIterator.OfInt() - { - int current = first; - - @Override - public boolean hasNext() - { - if (ascending) { - return current <= last; - } else { - return current >= last; - } - } - - @Override - public int nextInt() - { - if (ascending) { - return current++; - } else { - return current--; - } - } - }; - } -} diff --git a/prism/src/common/iterable/Reducible.java b/prism/src/common/iterable/Reducible.java new file mode 100644 index 0000000000..2002c010a3 --- /dev/null +++ b/prism/src/common/iterable/Reducible.java @@ -0,0 +1,651 @@ +package common.iterable; + +import common.functions.DoubleObjToDoubleFunction; +import common.functions.IntObjToIntFunction; +import common.functions.LongObjToLongFunction; + +import java.util.*; +import java.util.function.*; + +/** + * A {@link Reducible} provides transformation and accumulation operations similar to {@link java.util.stream.Stream Stream}. + * It servers as a bridge between Iterator-based code and the functional API provided by Java streams. + * The operations are implemented and specialized in {@link FunctionalIterator} and {@link FunctionalIterable}. + * The following example illustrates is usage. + * + *

+ * List<String>  allFibonacci = List.of("0", "1", "1", "2", "3", "5", "8", "13");
+ * List<Integer> oddFibonacci = Reducible.extend(allFibonacci)
+ *                                   .mapToInt(Integer::parseInt)
+ *                                   .filter((int i) -> i % 2 != 0)
+ *                                   .collect(ArrayList::new);
+ * 
+ * The code computes the odd Fibonacci numbers from a {@code List} of {@code String} representations: + *
    + *
  1. Extend an ordinary Iterable (the {@code List}) with the methods of this interface + *
  2. Map the String representation of each number to its respective {@code int} value + *
  3. Filter all odd numbers + *
  4. Collect the filtered numbers in a new {@code ArrayList} + *
+ * Please note that {@link Reducible#mapToInt} and {@link Reducible#filter} only wrap the underlying reducible. + * The actual computation happens on-the-fly when {@code collect} is called. + * + *

Transformation operations (known as intermediate operations on streams) + * transform the sequence of elements, e.g., by filtering with a predicate or by mapping elements using a function. + * All transformation operations are defined in this interface with one exception: + * {@code flatMap} and its primitive specializations {@code flatMapToDouble}, {@code flatMapToInt} and {@code flatMapToLong} + * have to be defined in the implementors of this interface, as Java's generic type system is not flexible enough to define it here. + * + *

Accumulation operations (known as terminal operations on streams) + * consume the elements and compute a result, e.g., by testing whether all elements match a predicate or by collecting all elements in an array. + * The most general accumulation operation is {@link Reducible#reduce(Object, BiFunction) reduce}. + * To enable an efficient treatment of the primitive types {@code double}, {@code int} and {@code long}, reduce is overloaded. + * Please note that implementors of the interface may consume no elements if the result of an accumulation can be computed directly. + * + * @param the type of elements returned by this Reducible + * @param the type of reducibles accepted by {@link Reducible#concat concat} + *ø + * @see java.util.stream.Stream Stream + */ +public interface Reducible +{ + // Bridging methods to Iterator-based code + + /** + * Extend an Iterable with the methods provided by FunctionalIterable. + * Answer the argument if it already implements {@code FunctionalIterable}. + * + * @param iterable the {@link Iterable} to extend + * @return a {@link FunctionalIterable} that is either the argument or an adaptor on the argument + */ + @SuppressWarnings("unchecked") + static FunctionalIterable extend(Iterable iterable) + { + if (iterable instanceof FunctionalIterable) { + return (FunctionalIterable) iterable; + } + if (iterable instanceof PrimitiveIterable.OfDouble) { + return (FunctionalIterable) extend((PrimitiveIterable.OfDouble) iterable); + } + if (iterable instanceof PrimitiveIterable.OfInt) { + return (FunctionalIterable) extend((PrimitiveIterable.OfInt) iterable); + } + if (iterable instanceof PrimitiveIterable.OfLong) { + return (FunctionalIterable) extend((PrimitiveIterable.OfLong) iterable); + } + return new IterableAdaptor.Of<>(iterable); + + } + + /** + * Extend an Iterator with the methods provided by FunctionalIterator. + * If the Iterator is a PrimitiveIterator, the extension is a {@code FunctionalPrimitiveIterator}. + * Answer the argument if it already implements {@code FunctionalIterator}. + * + * @param iterator the {@link Iterator} to extend + * @return a {@link FunctionalIterator} that is either the argument or an adaptor on the argument + */ + @SuppressWarnings("unchecked") + static FunctionalIterator extend(Iterator iterator) + { + if (iterator instanceof FunctionalIterator) { + return (FunctionalIterator) iterator; + } + if (iterator instanceof PrimitiveIterator.OfDouble) { + return (FunctionalIterator) extend((PrimitiveIterator.OfDouble) iterator); + } + if (iterator instanceof PrimitiveIterator.OfInt) { + return (FunctionalIterator) extend((PrimitiveIterator.OfInt) iterator); + } + if (iterator instanceof PrimitiveIterator.OfLong) { + return (FunctionalIterator) extend((PrimitiveIterator.OfLong) iterator); + } + return new IteratorAdaptor.Of<>(iterator); + } + + /** + * Extend a PrimitiveIterable.OfDouble with the methods provided by FunctionalPrimitiveIterable. + * Answer the argument if it already implements {@code FunctionalIterable}. + * + * @param iterable the {@link PrimitiveIterable.OfDouble} to extend + * @return a {@link FunctionalPrimitiveIterable.OfDouble} that is either the argument or an adaptor on the argument + */ + static FunctionalPrimitiveIterable.OfDouble extend(PrimitiveIterable.OfDouble iterable) + { + if (iterable instanceof FunctionalPrimitiveIterable.OfDouble) { + return (FunctionalPrimitiveIterable.OfDouble) iterable; + } + return new IterableAdaptor.OfDouble(iterable); + } + + /** + * Extend a PrimitiveIterator.OfDouble with the methods provided by FunctionalPrimitiveIterator. + * Answer the argument if it already implements {@code FunctionalPrimitiveIterator.OfDouble}. + * + * @param iterator the {@link PrimitiveIterator.OfDouble} to extend + * @return a {@link FunctionalPrimitiveIterator.OfDouble} that is either the argument or an adaptor on the argument + */ + static FunctionalPrimitiveIterator.OfDouble extend(PrimitiveIterator.OfDouble iterator) + { + if (iterator instanceof FunctionalPrimitiveIterator.OfDouble) { + return (FunctionalPrimitiveIterator.OfDouble) iterator; + } + return new IteratorAdaptor.OfDouble(iterator); + } + + /** + * Extend a PrimitiveIterable.OfInt with the methods provided by FunctionalPrimitiveIterable. + * Answer the argument if it already implements {@code FunctionalPrimitiveIterable}. + * + * @param iterable the {@link PrimitiveIterable.OfInt} to extend + * @return a {@link FunctionalPrimitiveIterable.OfDouble} that is either the argument or an adaptor on the argument + */ + static FunctionalPrimitiveIterable.OfInt extend(PrimitiveIterable.OfInt iterable) + { + if (iterable instanceof FunctionalPrimitiveIterable.OfInt) { + return (FunctionalPrimitiveIterable.OfInt) iterable; + } + return new IterableAdaptor.OfInt(iterable); + } + + /** + * Extend a PrimitiveIterator.OfInt with the methods provided by FunctionalPrimitiveIterator. + * Answer the argument if it already implements {@code FunctionalPrimitiveIterator.OfInt}. + * + * @param iterator the {@link PrimitiveIterator.OfInt} to extend + * @return a {@link FunctionalPrimitiveIterator.OfInt} that is either the argument or an adaptor on the argument + */ + static FunctionalPrimitiveIterator.OfInt extend(PrimitiveIterator.OfInt iterator) + { + if (iterator instanceof FunctionalPrimitiveIterator.OfInt) { + return (FunctionalPrimitiveIterator.OfInt) iterator; + } + return new IteratorAdaptor.OfInt(iterator); + } + + /** + * Extend a PrimitiveIterable.OfLong with the methods provided by FunctionalPrimitiveIterable. + * Answer the argument if it already implements {@code FunctionalPrimitiveIterable}. + * + * @param iterable the {@link PrimitiveIterable.OfLong} to extend + * @return a {@link FunctionalPrimitiveIterable.OfLong} that is either the argument or an adaptor on the argument + */ + static FunctionalPrimitiveIterable.OfLong extend(PrimitiveIterable.OfLong iterable) + { + if (iterable instanceof FunctionalPrimitiveIterable.OfLong) { + return (FunctionalPrimitiveIterable.OfLong) iterable; + } + return new IterableAdaptor.OfLong(iterable); + } + + /** + * Extend a PrimitiveIterator.OfLong with the methods provided by FunctionalPrimitiveIterator. + * Answer the argument if it already implements {@code FunctionalPrimitiveIterator.OfLong}. + * + * @param iterator the {@link PrimitiveIterator.OfLong} to extend + * @return a {@link FunctionalPrimitiveIterator.OfLong} that is either the argument or an adaptor on the argument + */ + static FunctionalPrimitiveIterator.OfLong extend(PrimitiveIterator.OfLong iterator) + { + if (iterator instanceof FunctionalPrimitiveIterator.OfLong) { + return (FunctionalPrimitiveIterator.OfLong) iterator; + } + return new IteratorAdaptor.OfLong(iterator); + } + + /** + * Convert an Iterable<Double> to a FunctionalPrimitiveIterable.OfDouble by unboxing each element. + * If the argument's Iterator yields {@code null}, a {@link NullPointerException} is thrown when iterating. + * Answer the Iterable if it already implements of FunctionalPrimitiveIterable.OfDouble. + * + * @param iterable the {@link Iterable}<Double> to extend + * @return a {@link FunctionalPrimitiveIterable.OfDouble} that is either the argument or an adaptor on the argument + */ + static FunctionalPrimitiveIterable.OfDouble unboxDouble(Iterable iterable) + { + if (iterable instanceof FunctionalPrimitiveIterable.OfDouble) { + return (FunctionalPrimitiveIterable.OfDouble) iterable; + } + return extend(PrimitiveIterable.unboxDouble(iterable)); + } + + /** + * Convert an Iterator<Double> to a FunctionalPrimitiveIterator.OfDouble by unboxing each element. + * If the Iterator yields {@code null}, a {@link NullPointerException} is thrown when iterating. + * Answer the Iterator if it already implements of FunctionalPrimitiveIterator.OfDouble. + * + * @param iterator the {@link Iterator}<Double> to unbox + * @return a {@link FunctionalPrimitiveIterator.OfDouble} that is either the argument or an unboxing iterator + */ + static FunctionalPrimitiveIterator.OfDouble unboxDouble(Iterator iterator) + { + if (iterator instanceof PrimitiveIterator.OfDouble) { + return extend((PrimitiveIterator.OfDouble) iterator); + } + return extend(PrimitiveIterable.unboxDouble(iterator)); + } + + /** + * Convert an Iterable<Integer> to a FunctionalPrimitiveIterable.OfInt by unboxing each element. + * If the argument's Iterator yields {@code null}, a {@link NullPointerException} is thrown when iterating. + * Answer the Iterable if it already implements of FunctionalPrimitiveIterable.OfInt. + * + * @param iterable the {@link Iterable}<Integer> to extend + * @return a {@link FunctionalPrimitiveIterable.OfInt} that is either the argument or an adaptor on the argument + */ + static FunctionalPrimitiveIterable.OfInt unboxInt(Iterable iterable) + { + if (iterable instanceof FunctionalPrimitiveIterable.OfInt) { + return (FunctionalPrimitiveIterable.OfInt) iterable; + } + return extend(PrimitiveIterable.unboxInt(iterable)); + } + + /** + * Convert an Iterator<Integer> to a FunctionalPrimitiveIterator.OfInt by unboxing each element. + * If the Iterator yields {@code null}, a {@link NullPointerException} is thrown when iterating. + * Answer the Iterator if it already implements of FunctionalPrimitiveIterator.OfInt. + * + * @param iterator the {@link Iterator}<Integer> to unbox + * @return a {@link FunctionalPrimitiveIterator.OfInt} that is either the argument or an unboxing iterator + */ + static FunctionalPrimitiveIterator.OfInt unboxInt(Iterator iterator) + { + if (iterator instanceof PrimitiveIterator.OfInt) { + return extend((PrimitiveIterator.OfInt) iterator); + } + return extend(PrimitiveIterable.unboxInt(iterator)); + } + + /** + * Convert an Iterable<Long> to a FunctionalPrimitiveIterable.OfLong by unboxing each element. + * If the argument's Iterator yields {@code null}, a {@link NullPointerException} is thrown when iterating. + * Answer the Iterable if it already implements of FunctionalPrimitiveIterable.OfLong. + * + * @param iterable the {@link Iterable}<Long> to extend + * @return a {@link FunctionalPrimitiveIterable.OfLong} that is either the argument or an adaptor on the argument + */ + static FunctionalPrimitiveIterable.OfLong unboxLong(Iterable iterable) + { + if (iterable instanceof FunctionalPrimitiveIterable.OfLong) { + return (FunctionalPrimitiveIterable.OfLong) iterable; + } + return extend(PrimitiveIterable.unboxLong(iterable)); + } + + /** + * Convert an Iterator<Long> to a FunctionalPrimitiveIterator.OfLong by unboxing each element. + * If the Iterator yields {@code null}, a {@link NullPointerException} is thrown when iterating. + * Answer the Iterator if it already implements of FunctionalPrimitiveIterator.OfLong. + * + * @param iterator the {@link Iterator}<Long> to unbox + * @return a {@link FunctionalPrimitiveIterator.OfLong} that is either the argument or an unboxing iterator + */ + static FunctionalPrimitiveIterator.OfLong unboxLong(Iterator iterator) + { + if (iterator instanceof PrimitiveIterator.OfLong) { + return extend((PrimitiveIterator.OfLong) iterator); + } + return extend(PrimitiveIterable.unboxLong(iterator)); + } + + + + // Fundamental methods + + /** + * Perform an action with each of the receivers elements. + * + * @param action the action to be performed with each element + * @see Iterable#forEach(Consumer) + */ + void forEach(Consumer action); + + /** + * Test whether the receiver is empty. + * + * @return {@code true} iff the receiver is empty + */ + boolean isEmpty(); + + + + // Transforming Methods + + /** + * Concatenate the receiver and the argument. + * The returned reducible first iterates over the elements of the receiver and then over the elements the argument. + * + * @param reducible the {@link Reducible} to append + * @return a {@link Reducible} that iterates over the elements of the receiver and the argument + */ + Reducible concat(E_CAT reducible); + + /** + * Remove consecutive duplicate elements such that only the first occurrence in a sequence is retained. + * Duplicates are identified in terms of {@link Object#equals}. + */ + default Reducible dedupe() + { + Predicate isFirst = new Predicate<>() + { + Object previous = new Object(); + + @Override + public boolean test(E obj) + { + if (Objects.equals(previous, obj)) { + return false; + } + previous = obj; + return true; + } + }; + return filter(isFirst); + } + + /** + * Remove duplicate elements from the receiver such that only one occurrence is retained. + * Duplicates are identified in terms of {@link Object#equals} which requires a proper implementation of {@link Object#hashCode}. + */ + default Reducible distinct() + { + return filter(new Distinct.Of<>()); + } + + /** + * Filter the receiver by a predicate, i.e., only elements that match the predicate are kept. + * + * @param predicate a predicate evaluating to {@code true} for the elements to keep + */ + Reducible filter(Predicate predicate); + + /** + * Map each element. + * + * @param function a mapping function that is applied to each element + */ + Reducible map(Function function); + + /** + * Map each element to a {@code double}. + * + * @param function a mapping function that is applied to each element + */ + PrimitiveReducible.OfDouble mapToDouble(ToDoubleFunction function); + + /** + * Map each element to an {@code int}. + * + * @param function a mapping function that is applied to each element + */ + PrimitiveReducible.OfInt mapToInt(ToIntFunction function); + + /** + * Map each element to a {@code long}. + * + * @param function a mapping function that is applied to each element + */ + PrimitiveReducible.OfLong mapToLong(ToLongFunction function); + + /** + * Remove all {@code null} elements. + */ + default Reducible nonNull() + { + return filter(Objects::nonNull); + } + + + + // Accumulations Methods (Consuming) + + /** + * Consume this reducible, i.e., iterate over all its elements. + */ + default Reducible consume() + { + forEach((E each) -> {}); + return this; + } + + /** + * Test whether each element matches a predicate. + * + * @param predicate a {@link Predicate} to test the element against + * @return {@code true} iff the predicate evaluates to {@code true} for each element + */ + default boolean allMatch(Predicate predicate) + { + return !anyMatch(predicate.negate()); + } + + /** + * Test whether any element matches a predicate. + * Return {@code true} after the first match without testing the remaining elements. + * + * @param predicate a {@link Predicate} to test the elements against + * @return {@code true} iff the predicate evaluates to {@code true} for any element + */ + default boolean anyMatch(Predicate predicate) + { + return ! filter(predicate).isEmpty(); + } + + /** + * Test whether no element matches a predicate. + * Return {@code false} after the first match without testing the remaining elements. + * + * @param predicate a {@link Predicate} to test the elements against + * @return {@code false} iff the predicate evaluates to {@code true} for any element + */ + default boolean noneMatch(Predicate predicate) + { + return !anyMatch(predicate); + } + + /** + * Build an array-like string that lists the string representation {@link Object#toString} of each element. + * + * @return a String of the form "[e_1, e_2, ... , e_n]" + */ + default String asString() + { + StringBuilder builder = new StringBuilder("["); + forEach(each -> { + if (builder.length() > 1) { + builder.append(", "); + } + builder.append(each); + }); + return builder.append("]").toString(); + } + + /** + * Add each element to a newly instantiated {@code Collection} supplied by the argument using {@link Collection#add(Object)}. + * + * @param constructor a function yielding a new Collection + * @return the new Collection with all elements added to it + * @see java.util.stream.Stream#collect(Supplier, java.util.function.BiConsumer, java.util.function.BiConsumer) + */ + default > C collect(Supplier constructor) + { + Objects.requireNonNull(constructor); + C collection = constructor.get(); + collect(collection); + return collection; + } + + /** + * Add each element to the argument {@code Collection} using {@link Collection#add(Object)}. + * + * @param collection a {@link Collection} + * @return the Collection with all elements added to it + */ + default > C collect(C collection) + { + Objects.requireNonNull(collection); + forEach(collection::add); + return collection; + } + + /** + * Store each element in an array starting at index 0. + * + * @param array an Array of the receiver's element type + * @return the array with all elements stored in it + */ + default E[] collect(E[] array) + { + return collect(array, 0); + } + + /** + * Store each element in an array starting at index {@code offset}. + * + * @param array an Array of the receiver's element type + * @param offset an index (inclusive) from which on the elements are stored + * @return the array with all elements stored in it + */ + default E[] collect(E[] array, int offset) + { + collectAndCount(array, offset); + return array; + } + + /** + * Add each element to the argument {@code Collection} using {@link Collection#add(Object)} and count the number of elements added. + * + * @param collection a {@link Collection} + * @return the number of elements added to the Collection + */ + default long collectAndCount(Collection collection) + { + Objects.requireNonNull(collection); + return reduce(0L, (long c, E e) -> {collection.add(e); return c + 1;}); + } + + /** + * Store each element in an array starting at index 0 and count the number of elements stored. + * + * @param array an Array of the receiver's element type + * @return the number of elements stored in the array + */ + default int collectAndCount(E[] array) + { + return collectAndCount(array, 0); + } + + /** + * Store each element in an array starting at index {@code offset} and count the number of elements stored. + * + * @param array an Array of the receiver's element type + * @param offset an index (inclusive) from which on the elements are stored + * @return the number of elements stored in the array + */ + default int collectAndCount(E[] array, int offset) + { + Objects.requireNonNull(array); + int index = reduce(offset, (int i, E e) -> {array[i] = e; return i + 1;}); + return index - offset; + } + + /** + * Collect distinct elements from the receiver such that only one occurrence of each element is retained. + * Duplicates are identified in terms of {@link Object#equals} which requires a proper implementation of {@link Object#hashCode}. + * The order of elements in the result may differ from the order in the receiver. + * + * @return a {@link FunctionalIterable} that contains each distinct of the receiver exactly once + * @see FunctionalIterator#distinct() + */ + default FunctionalIterable collectDistinct() + { + Distinct.Of unseen = new Distinct.Of<>(); + filter(unseen).consume(); + return unseen.getSeen(); + } + + /** + * Test in terms of {@link Object#equals} whether an object (or {@code null}) is one of the receiver's elements. + * + * @param obj an object to be found in the receiver + * @return {@code true} if the argument is contained in the receiver + */ + default boolean contains(Object obj) + { + return anyMatch((obj == null) ? Objects::isNull : obj::equals); + } + + /** + * Count the number of elements in the receiver. + * + * @return the number of elements + */ + default long count() + { + return reduce(0L, (long c, E e) -> c + 1); + } + + /** + * Count the number of elements that match a predicate. + * + * @param predicate a {@link Predicate} evaluating to {@code true} for the elements to count + * @return the number of elements matching the predicate + */ + default long count(Predicate predicate) + { + return filter(predicate).count(); + } + + /** + * Find the first element that matches a predicate. + * + * @param predicate a {@link Predicate} evaluating to {@code true} for the element to return + * @return the first a matching element + * @throws NoSuchElementException if no matching element was found + */ + E detect(Predicate predicate); + + /** + * Reduce the receiver with an accumulator similar to {@code fold}. + * The first element serves as initial value for the reduction of the remaining elements. + * + * @param accumulator a {@link BinaryOperator} taking an intermediate result as first argument and an element as second argument + * @return an {@link Optional} either containing the result of the evaluation of the accumulator with the last element or being empty if the receiver is empty. + * @throws NullPointerException if the result of the reduction is {@code null} + * @see FunctionalIterator#reduce(Object, BiFunction) + */ + Optional reduce(BinaryOperator accumulator); + + /** + * Reduce the receiver with an accumulator and an initial value. + * First, the accumulator is evaluated with the initial value and the first element. + * Then it is evaluated with each subsequent element and the result of the previous evaluation. + * + * @param init an initial value for the reduction + * @param accumulator a {@link BiFunction} taking an intermediate result as first argument and an element as second argument + * @return the result of the evaluation of the accumulator with the last element + */ + T reduce(T init, BiFunction accumulator); + + /** + * Primitive specialisation of {@code reduce} for values of type {@code double}. + * + * @see FunctionalIterator#reduce(Object, BiFunction) + */ + double reduce(double init, DoubleObjToDoubleFunction accumulator); + + /** + * Primitive specialisation of {@code reduce} for values of type {@code int}. + * + * @see FunctionalIterator#reduce(Object, BiFunction) + */ + int reduce(int init, IntObjToIntFunction accumulator); + + /** + * Primitive specialisation of {@code reduce} for values of type {@code long}. + * + * @see FunctionalIterator#reduce(Object, BiFunction) + */ + long reduce(long init, LongObjToLongFunction accumulator); +} diff --git a/prism/src/common/iterable/SingletonIterable.java b/prism/src/common/iterable/SingletonIterable.java index ae56821322..94a0e3d97c 100644 --- a/prism/src/common/iterable/SingletonIterable.java +++ b/prism/src/common/iterable/SingletonIterable.java @@ -1,29 +1,157 @@ -package common.iterable; +//============================================================================== +// +// Copyright (c) 2016- +// Authors: +// * Steffen Maercker (TU Dresden) +// +//------------------------------------------------------------------------------ +// +// This file is part of PRISM. +// +// PRISM is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// PRISM 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 for more details. +// +// You should have received a copy of the GNU General Public License +// along with PRISM; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//============================================================================== -import java.util.Iterator; +package common.iterable; -public abstract class SingletonIterable implements Iterable +/** + * Abstract base class for Iterables ranging over a single element. + * + * @param type of the Iterable's elements + */ +public abstract class SingletonIterable implements FunctionalIterable { - public static class Of extends SingletonIterable + @Override + public long count() + { + return 1; + } + + @Override + public boolean isEmpty() { - final T element; + return false; + } - public Of(T theElement) + @Override + public SingletonIterable dedupe() + { + return this; + } + + @Override + public SingletonIterable distinct() + { + return this; + } + + + + /** + * Generic implementation of an singleton Iterable. + * + * @param type of the Iterables's elements + */ + public static class Of extends SingletonIterable + { + /** The single element */ + protected final E element; + + /** + * Constructor for an Iterable ranging over a single element. + * + * @param element the single element of the Iterable + */ + public Of(E theElement) { element = theElement; } @Override - public Iterator iterator() + public FunctionalIterator iterator() { return new SingletonIterator.Of<>(element); } + + @Override + public boolean contains(Object o) + { + return element == null ? o == null : element.equals(o); + } + } + + + + /** + * Primitive specialisation for {@code double} of an singleoton Iterable. + */ + public static class OfDouble extends SingletonIterable implements FunctionalPrimitiveIterable.OfDouble + { + /** The single element */ + protected final double element; + + /** + * Constructor for an Iterable ranging over a single element. + * + * @param element the single element of the Iterable + */ + public OfDouble(double theElement) + { + element = theElement; + } + + @Override + public SingletonIterator.OfDouble iterator() + { + return new SingletonIterator.OfDouble(element); + } + + @Override + public SingletonIterable.OfDouble dedupe() + { + return this; + } + + @Override + public SingletonIterable.OfDouble distinct() + { + return this; + } + + @Override + public boolean contains(double d) + { + return element == d; + } } - public static class OfInt extends SingletonIterable implements IterableInt + + + /** + * Primitive specialisation for {@code int} of an singleoton Iterable. + */ + public static class OfInt extends SingletonIterable implements FunctionalPrimitiveIterable.OfInt { - final int element; + /** The single element */ + protected final int element; + /** + * Constructor for an Iterable ranging over a single element. + * + * @param element the single element of the Iterable + */ public OfInt(int theElement) { element = theElement; @@ -34,12 +162,41 @@ public SingletonIterator.OfInt iterator() { return new SingletonIterator.OfInt(element); } + + @Override + public SingletonIterable.OfInt dedupe() + { + return this; + } + + @Override + public SingletonIterable.OfInt distinct() + { + return this; + } + + @Override + public boolean contains(int i) + { + return element == i; + } } - public static class OfLong extends SingletonIterable implements IterableLong + + + /** + * Primitive specialisation for {@code long} of an singleoton Iterable. + */ + public static class OfLong extends SingletonIterable implements FunctionalPrimitiveIterable.OfLong { - final long element; + /** The single element */ + protected final long element; + /** + * Constructor for an Iterable ranging over a single element. + * + * @param element the single element of the Iterable + */ public OfLong(long theElement) { element = theElement; @@ -50,21 +207,23 @@ public SingletonIterator.OfLong iterator() { return new SingletonIterator.OfLong(element); } - } - public static class OfDouble extends SingletonIterable implements IterableDouble - { - final double element; + @Override + public SingletonIterable.OfLong dedupe() + { + return this; + } - public OfDouble(double theElement) + @Override + public SingletonIterable.OfLong distinct() { - element = theElement; + return this; } @Override - public SingletonIterator.OfDouble iterator() + public boolean contains(long l) { - return new SingletonIterator.OfDouble(element); + return element == l; } } } diff --git a/prism/src/common/iterable/SingletonIterator.java b/prism/src/common/iterable/SingletonIterator.java index 62a5e365f7..1a9fe16626 100644 --- a/prism/src/common/iterable/SingletonIterator.java +++ b/prism/src/common/iterable/SingletonIterator.java @@ -2,7 +2,7 @@ // // Copyright (c) 2016- // Authors: -// * Steffen Maercker (TU Dresden) +// * Steffen Maercker (TU Dresden) // //------------------------------------------------------------------------------ // @@ -26,112 +26,267 @@ package common.iterable; -import java.util.Iterator; -import java.util.Optional; import java.util.OptionalDouble; import java.util.OptionalInt; import java.util.OptionalLong; -import java.util.PrimitiveIterator; /** - * Base class for an iterator that ranges over a single element, - * static helpers for common primitive iterators. + * Abstract base class for Iterators ranging over a single element. + * + * @param type of the Iterator's elements */ -public abstract class SingletonIterator implements Iterator +public abstract class SingletonIterator implements FunctionalIterator { - public static class Of extends SingletonIterator + protected boolean hasNext = true; + + @Override + public SingletonIterator dedupe() + { + return this; + } + + @Override + public SingletonIterator distinct() + { + return this; + } + + @Override + public boolean hasNext() + { + return hasNext; + } + + @Override + public void release() { - private Optional element; + hasNext = false; + } + - public Of(T element) + /** + * Generic implementation of an singleton Iterator. + * + * @param type of the Iterator's elements + */ + public static class Of extends SingletonIterator + { + /** The single element */ + protected E element; + + /** + * Constructor for an Iterator ranging over a single element. + * + * @param element the single element of the Iterator + */ + public Of(E element) { - this.element = Optional.of(element); + this.element = element; } @Override - public boolean hasNext() + public E next() { - return element.isPresent(); + requireNext(); + E next = element; + release(); + return next; } @Override - public T next() + public void release() { - Optional result = element; - element = Optional.empty(); - return result.get(); + super.release(); + element = null; } } - public static class OfInt extends SingletonIterator implements PrimitiveIterator.OfInt + + + /** + * Primitive specialisation for {@code double} of an singleoton Iterator. + */ + public static class OfDouble extends SingletonIterator implements FunctionalPrimitiveIterator.OfDouble { - private OptionalInt element; + /** The single element */ + protected final double element; - public OfInt(int element) + /** + * Constructor for an Iterator ranging over a single element. + * + * @param element the single element of the Iterator + */ + public OfDouble(double element) { - this.element = OptionalInt.of(element); + this.element = element; } @Override - public boolean hasNext() + public double nextDouble() { - return element.isPresent(); + requireNext(); + release(); + return element; } @Override - public int nextInt() + public SingletonIterator.OfDouble dedupe() { - OptionalInt result = element; - element = OptionalInt.empty(); - return result.getAsInt(); + return this; + } + + @Override + public SingletonIterator.OfDouble distinct() + { + return this; + } + + @Override + public OptionalDouble max() + { + if (hasNext) { + release(); + return OptionalDouble.of(element); + } + return OptionalDouble.empty(); + } + + @Override + public OptionalDouble min() + { + return max(); + } + + @Override + public double sum() + { + return hasNext ? element : 0.0; } } - public static class OfLong extends SingletonIterator implements PrimitiveIterator.OfLong + + + /** + * Primitive specialisation for {@code int} of an singleoton Iterator. + */ + public static class OfInt extends SingletonIterator implements FunctionalPrimitiveIterator.OfInt { - private OptionalLong element; + /** The single element */ + protected final int element; + + /** + * Constructor for an Iterator ranging over a single element. + * + * @param element the single element of the Iterator + */ + public OfInt(int element) + { + this.element = element; + } + + @Override + public int nextInt() + { + requireNext(); + release(); + return element; + } - public OfLong(Long element) + @Override + public SingletonIterator.OfInt dedupe() { - this.element = OptionalLong.of(element); + return this; } @Override - public boolean hasNext() + public SingletonIterator.OfInt distinct() { - return element.isPresent(); + return this; } @Override - public long nextLong() + public OptionalInt max() { - OptionalLong result = element; - element = OptionalLong.empty(); - return result.getAsLong(); + if (hasNext) { + release(); + return OptionalInt.of(element); + } + return OptionalInt.empty(); + } + + @Override + public OptionalInt min() + { + return max(); + } + + @Override + public long sum() + { + return hasNext ? element : 0L; } } - public static class OfDouble extends SingletonIterator implements PrimitiveIterator.OfDouble + + + /** + * Primitive specialisation for {@code long} of an singleoton Iterator. + */ + public static class OfLong extends SingletonIterator implements FunctionalPrimitiveIterator.OfLong { - private OptionalDouble element; + /** The single element */ + protected final long element; - public OfDouble(double element) + /** + * Constructor for an Iterator ranging over a single element. + * + * @param element the single element of the Iterator + */ + public OfLong(long element) { - this.element = OptionalDouble.of(element); + this.element = element; } @Override - public boolean hasNext() + public long nextLong() { - return element.isPresent(); + requireNext(); + release(); + return element; } @Override - public double nextDouble() + public SingletonIterator.OfLong dedupe() + { + return this; + } + + @Override + public SingletonIterator.OfLong distinct() + { + return this; + } + + @Override + public OptionalLong max() + { + if (hasNext) { + release(); + return OptionalLong.of(element); + } + return OptionalLong.empty(); + } + + @Override + public OptionalLong min() + { + return max(); + } + + @Override + public long sum() { - OptionalDouble result = element; - element = OptionalDouble.empty(); - return result.getAsDouble(); + return hasNext ? element : 0L; } } -} +} \ No newline at end of file diff --git a/prism/src/explicit/DTMC.java b/prism/src/explicit/DTMC.java index 822ad4738f..75d0bf2dc8 100644 --- a/prism/src/explicit/DTMC.java +++ b/prism/src/explicit/DTMC.java @@ -33,13 +33,9 @@ import java.util.PrimitiveIterator.OfInt; import common.IterableStateSet; -import common.iterable.IterableInt; import common.iterable.MappingIterator; -import prism.ModelType; -import prism.Pair; -import prism.PrismException; -import prism.PrismLog; -import prism.PrismUtils; +import common.iterable.PrimitiveIterable; +import prism.*; import explicit.graphviz.Decorator; import explicit.rewards.MCRewards; @@ -170,9 +166,9 @@ default String infoStringTable() */ public default Iterator>> getTransitionsAndActionsIterator(int s) { - // Default implementation just adds null actions + // Default implementation just adds null actions final Iterator> transitions = getTransitionsIterator(s); - return new MappingIterator.From<>(transitions, transition -> attachAction(transition, null)); + return new MappingIterator.ObjToObj<>(transitions, transition -> attachAction(transition, null)); } /** @@ -239,7 +235,7 @@ public interface TransitionToDoubleFunction { * Return sum_t f(s, t, P(s,t)), where t ranges over the successors of s. * * @param s the state s - * @param c the consumer + * @param f the consumer */ public default double sumOverTransitions(final int s, final TransitionToDoubleFunction f) { @@ -740,7 +736,7 @@ public default void vmMult(double vect[], double result[]) * @param deltaT deltaT conditioning factor * @param states subset of states to consider */ - public default void vmMultPowerSteadyState(double vect[], double[] result, double[] diagsQ, double deltaT, IterableInt states) + public default void vmMultPowerSteadyState(double vect[], double[] result, double[] diagsQ, double deltaT, PrimitiveIterable.OfInt states) { // Recall that the generator matrix Q has entries // Q(s,s) = -sum_{t!=s} prob(s,t) diff --git a/prism/src/explicit/DTMCFromMDPMemorylessAdversary.java b/prism/src/explicit/DTMCFromMDPMemorylessAdversary.java index 5b8057055e..7260e0c41c 100644 --- a/prism/src/explicit/DTMCFromMDPMemorylessAdversary.java +++ b/prism/src/explicit/DTMCFromMDPMemorylessAdversary.java @@ -163,7 +163,7 @@ public Iterator>> getTransitionsAndActionsIt { if (adv[s] >= 0) { final Iterator> transitions = mdp.getTransitionsIterator(s, adv[s]); - return new MappingIterator.From<>(transitions, transition -> DTMC.attachAction(transition, mdp.getAction(s, adv[s]))); + return new MappingIterator.ObjToObj<>(transitions, transition -> DTMC.attachAction(transition, mdp.getAction(s, adv[s]))); } else { // Empty iterator return Collections.>>emptyIterator(); diff --git a/prism/src/explicit/DTMCModelChecker.java b/prism/src/explicit/DTMCModelChecker.java index 69498eb08c..1a36bb2f0e 100644 --- a/prism/src/explicit/DTMCModelChecker.java +++ b/prism/src/explicit/DTMCModelChecker.java @@ -1393,7 +1393,7 @@ public boolean hasTransitionRewards() for (int scc = 0, numSCCs = sccs.getNumSCCs(); scc < numSCCs; scc++) { IntSet statesForSCC = sccs.getStatesForSCC(scc); - int cardinality = statesForSCC.cardinality(); + int cardinality = Math.toIntExact(statesForSCC.cardinality()); PrimitiveIterator.OfInt itSCC = statesForSCC.iterator(); while (itSCC.hasNext()) { @@ -1500,7 +1500,7 @@ public boolean hasTransitionRewards() double q = 0; double p = 1; - int cardinality = statesForSCC.cardinality(); + int cardinality = Math.toIntExact(statesForSCC.cardinality()); PrimitiveIterator.OfInt itSCC = statesForSCC.iterator(); while (itSCC.hasNext()) { diff --git a/prism/src/explicit/DTMCSparse.java b/prism/src/explicit/DTMCSparse.java index c337d969b2..19a46370f0 100644 --- a/prism/src/explicit/DTMCSparse.java +++ b/prism/src/explicit/DTMCSparse.java @@ -4,7 +4,7 @@ // Authors: // * Dave Parker (University of Oxford) // * Christian von Essen (Verimag, Grenoble) -// * Steffen Maercker (TU Dresden) +// * Steffen Maercker (TU Dresden) // * Joachim Klein (TU Dresden) // //------------------------------------------------------------------------------ @@ -38,8 +38,7 @@ import java.util.function.Function; import common.IterableStateSet; -import common.iterable.IterableInt; -import common.iterable.MappingIterator; +import common.iterable.PrimitiveIterable; import explicit.rewards.MCRewards; import prism.PrismException; import prism.PrismNotSupportedException; @@ -358,7 +357,7 @@ public void vmMult(final double[] vect, final double[] result) } @Override - public void vmMultPowerSteadyState(double vect[], double result[], double[] diagsQ, double deltaT, IterableInt states) + public void vmMultPowerSteadyState(double vect[], double result[], double[] diagsQ, double deltaT, PrimitiveIterable.OfInt states) { // Recall that the generator matrix Q has entries // Q(s,s) = -sum_{t!=s} prob(s,t) @@ -407,8 +406,8 @@ public final Entry apply(final Integer state) } }; String s = "trans: [ "; - final IterableStateSet states = new IterableStateSet(numStates); - final Iterator> distributions = new MappingIterator.From<>(states, getDistribution); + IterableStateSet states = new IterableStateSet(numStates); + Iterator> distributions = states.iterator().map(getDistribution); while (distributions.hasNext()) { final Entry dist = distributions.next(); s += dist.getKey() + ": " + dist.getValue(); diff --git a/prism/src/explicit/MDP.java b/prism/src/explicit/MDP.java index 8c6e69a3ef..facc73a58f 100644 --- a/prism/src/explicit/MDP.java +++ b/prism/src/explicit/MDP.java @@ -206,7 +206,7 @@ default String infoStringTable() @Override default int getNumTransitions(final int s, final int i) { - return IteratorTools.count(getTransitionsIterator(s, i)); + return Math.toIntExact(IteratorTools.count(getTransitionsIterator(s, i))); } @Override diff --git a/prism/src/explicit/MDPModelChecker.java b/prism/src/explicit/MDPModelChecker.java index 3c3e2ca697..7d7d148e1a 100644 --- a/prism/src/explicit/MDPModelChecker.java +++ b/prism/src/explicit/MDPModelChecker.java @@ -1493,7 +1493,7 @@ private boolean isContracting(MDP mdp, BitSet unknown, BitSet target) for (int scc = 0, numSCCs = sccs.getNumSCCs(); scc < numSCCs; scc++) { IntSet statesForSCC = sccs.getStatesForSCC(scc); - int cardinality = statesForSCC.cardinality(); + int cardinality = Math.toIntExact(statesForSCC.cardinality()); PrimitiveIterator.OfInt itSCC = statesForSCC.iterator(); while (itSCC.hasNext()) { @@ -1605,7 +1605,7 @@ private boolean isContracting(MDP mdp, BitSet unknown, BitSet target) double q = 0; double p = 1; - int cardinality = statesForSCC.cardinality(); + int cardinality = Math.toIntExact(statesForSCC.cardinality()); PrimitiveIterator.OfInt itSCC = statesForSCC.iterator(); while (itSCC.hasNext()) { diff --git a/prism/src/explicit/Model.java b/prism/src/explicit/Model.java index e80a1a7f9f..c60b0cd3db 100644 --- a/prism/src/explicit/Model.java +++ b/prism/src/explicit/Model.java @@ -181,7 +181,7 @@ public default int getNumTransitions() */ public default int getNumTransitions(int s) { - return IteratorTools.count(getSuccessorsIterator(s)); + return Math.toIntExact(IteratorTools.count(getSuccessorsIterator(s))); } /** diff --git a/prism/src/explicit/SCCInfo.java b/prism/src/explicit/SCCInfo.java index 254c77feab..148a259ccc 100644 --- a/prism/src/explicit/SCCInfo.java +++ b/prism/src/explicit/SCCInfo.java @@ -27,9 +27,10 @@ package explicit; import java.util.Arrays; -import java.util.PrimitiveIterator.OfInt; +import java.util.PrimitiveIterator; import common.IntSet; +import common.iterable.FunctionalPrimitiveIterator; import prism.PrismLog; /** @@ -144,9 +145,9 @@ public IntSet getStatesForSCC(final int sccIndex) return new IntSet() { @Override - public OfInt iterator() + public FunctionalPrimitiveIterator.OfInt iterator() { - return new OfInt() { + return new FunctionalPrimitiveIterator.OfInt() { int cur = start; @Override @@ -164,9 +165,9 @@ public int nextInt() } @Override - public OfInt reversedIterator() + public FunctionalPrimitiveIterator.OfInt reversedIterator() { - return new OfInt() { + return new FunctionalPrimitiveIterator.OfInt() { int cur = end; @Override @@ -184,7 +185,7 @@ public int nextInt() } @Override - public int cardinality() + public long count() { return getNumStatesInSCC(sccIndex); } @@ -209,7 +210,7 @@ public void print(PrismLog log) { for (int scc = 0; scc < getNumSCCs(); scc++) { log.println("SCC " + scc + " (" + getNumStatesInSCC(scc) + "):"); - for (OfInt states = getStatesForSCC(scc).iterator(); states.hasNext();) { + for (PrimitiveIterator.OfInt states = getStatesForSCC(scc).iterator(); states.hasNext();) { int state = states.nextInt(); log.print(" "); log.print(state); diff --git a/prism/src/explicit/SuccessorsIterator.java b/prism/src/explicit/SuccessorsIterator.java index 1751e98169..60e49988ab 100644 --- a/prism/src/explicit/SuccessorsIterator.java +++ b/prism/src/explicit/SuccessorsIterator.java @@ -24,7 +24,6 @@ // //============================================================================== - package explicit; import java.util.Iterator; @@ -35,7 +34,8 @@ import java.util.stream.IntStream; import java.util.stream.StreamSupport; -import common.iterable.FilteringIterator; +import common.iterable.FunctionalIterator; +import common.iterable.Reducible; import common.iterable.SingletonIterator; /** @@ -70,7 +70,7 @@ public SuccessorsIterator distinct() if (successorsAreDistinct()) { return this; } else { - return new SuccessorsIteratorFromOfInt(FilteringIterator.dedupe(this), true); + return new SuccessorsIteratorFromOfInt(Reducible.extend(this).distinct(), true); } } diff --git a/prism/src/explicit/ZeroRewardECQuotient.java b/prism/src/explicit/ZeroRewardECQuotient.java index 80a3234a48..dd837e885a 100644 --- a/prism/src/explicit/ZeroRewardECQuotient.java +++ b/prism/src/explicit/ZeroRewardECQuotient.java @@ -30,7 +30,7 @@ import java.util.BitSet; import java.util.List; -import common.functions.primitive.PairPredicateInt; +import common.functions.PairPredicateInt; import common.IterableBitSet; import explicit.graphviz.Decorator; import explicit.graphviz.ShowRewardDecorator; diff --git a/prism/src/explicit/modelviews/DTMCView.java b/prism/src/explicit/modelviews/DTMCView.java index 1f9dbefb20..a942532c00 100644 --- a/prism/src/explicit/modelviews/DTMCView.java +++ b/prism/src/explicit/modelviews/DTMCView.java @@ -2,7 +2,7 @@ // // Copyright (c) 2016- // Authors: -// * Steffen Maercker (TU Dresden) +// * Steffen Maercker (TU Dresden) // * Joachim Klein (TU Dresden) // //------------------------------------------------------------------------------ @@ -34,7 +34,6 @@ import java.util.function.IntFunction; import common.IterableStateSet; -import common.iterable.MappingIterator; import explicit.DTMC; import explicit.Distribution; import explicit.SuccessorsIterator; @@ -77,8 +76,8 @@ public final Entry apply(final int state) } }; String s = "trans: [ "; - final IterableStateSet states = new IterableStateSet(getNumStates()); - final Iterator> distributions = new MappingIterator.FromInt<>(states, getDistribution); + IterableStateSet states = new IterableStateSet(getNumStates()); + Iterator> distributions = states.iterator().map(getDistribution); while (distributions.hasNext()) { final Entry dist = distributions.next(); s += dist.getKey() + ": " + dist.getValue(); diff --git a/prism/src/explicit/modelviews/EquivalenceRelationInteger.java b/prism/src/explicit/modelviews/EquivalenceRelationInteger.java index e4af3c6615..89dff4a60e 100644 --- a/prism/src/explicit/modelviews/EquivalenceRelationInteger.java +++ b/prism/src/explicit/modelviews/EquivalenceRelationInteger.java @@ -31,7 +31,7 @@ import java.util.HashMap; import java.util.Map; -import common.functions.primitive.PairPredicateInt; +import common.functions.PairPredicateInt; import common.IterableBitSet; /** diff --git a/prism/src/explicit/modelviews/MDPDroppedAllChoices.java b/prism/src/explicit/modelviews/MDPDroppedAllChoices.java index f71f75c91c..96cf587876 100644 --- a/prism/src/explicit/modelviews/MDPDroppedAllChoices.java +++ b/prism/src/explicit/modelviews/MDPDroppedAllChoices.java @@ -147,7 +147,7 @@ public boolean hasLabel(String name) @Override public Iterator getSuccessorsIterator(final int state) { - return states.get(state) ? EmptyIterator.Of() : model.getSuccessorsIterator(state); + return states.get(state) ? EmptyIterator.of() : model.getSuccessorsIterator(state); } diff --git a/prism/src/explicit/modelviews/MDPDroppedChoicesCached.java b/prism/src/explicit/modelviews/MDPDroppedChoicesCached.java index 7ebc5dbb13..8d8f752bb8 100644 --- a/prism/src/explicit/modelviews/MDPDroppedChoicesCached.java +++ b/prism/src/explicit/modelviews/MDPDroppedChoicesCached.java @@ -34,7 +34,7 @@ import java.util.Map.Entry; import java.util.Set; -import common.functions.primitive.PairPredicateInt; +import common.functions.PairPredicateInt; import explicit.Distribution; import explicit.MDP; import parser.State; diff --git a/prism/src/explicit/modelviews/MDPEquiv.java b/prism/src/explicit/modelviews/MDPEquiv.java index b3e339604e..7b9fcb69e2 100644 --- a/prism/src/explicit/modelviews/MDPEquiv.java +++ b/prism/src/explicit/modelviews/MDPEquiv.java @@ -2,7 +2,7 @@ // // Copyright (c) 2016- // Authors: -// * Steffen Maercker (TU Dresden) +// * Steffen Maercker (TU Dresden) // * Joachim Klein (TU Dresden) // //------------------------------------------------------------------------------ @@ -34,12 +34,12 @@ import java.util.Map.Entry; import java.util.PrimitiveIterator.OfInt; import java.util.Set; +import java.util.function.IntUnaryOperator; -import common.functions.primitive.PairPredicateInt; +import common.functions.PairPredicateInt; import common.iterable.FilteringIterator; import common.IterableBitSet; import common.IterableStateSet; -import common.IteratorTools; import common.iterable.MappingIterator; import explicit.BasicModelTransformation; import explicit.MDP; @@ -80,8 +80,8 @@ public MDPEquiv(final MDP model, final EquivalenceRelationInteger identify) // => leave it as it is numChoices[representative] = model.getNumChoices(representative); } else { - final IterableBitSet eqStates = new IterableBitSet(equivalenceClass); - numChoices[representative] = IteratorTools.sum(new MappingIterator.FromIntToInt(eqStates, model::getNumChoices)); + IterableBitSet eqStates = new IterableBitSet(equivalenceClass); + numChoices[representative] = Math.toIntExact(eqStates.mapToInt((IntUnaryOperator) model::getNumChoices).sum()); StateChoicePair[] choices = originalChoices[representative] = new StateChoicePair[numChoices[representative]]; assert representative == equivalenceClass.nextSetBit(0); int choice = model.getNumChoices(representative); @@ -232,7 +232,7 @@ public Iterator getSuccessorsIterator(final int state, final int choice } Iterator successors = model.getSuccessorsIterator(originalState, originalChoice); if (hasTransitionToNonRepresentative.get(originalState)) { - return FilteringIterator.dedupe(new MappingIterator.From<>(successors, this::mapStateToRestrictedModel)); + return (new MappingIterator.ObjToObj<>(successors, this::mapStateToRestrictedModel)).distinct(); } return successors; } @@ -255,7 +255,7 @@ public Iterator> getTransitionsIterator(final int state, } Iterator> transitions = model.getTransitionsIterator(originalState, originalChoice); if (hasTransitionToNonRepresentative.get(originalState)) { - return new MappingIterator.From<>(transitions, this::mapTransitionToRestrictedModel); + return new MappingIterator.ObjToObj<>(transitions, this::mapTransitionToRestrictedModel); } return transitions; } diff --git a/prism/src/explicit/modelviews/ModelView.java b/prism/src/explicit/modelviews/ModelView.java index 39809ee045..73c90e3cfe 100644 --- a/prism/src/explicit/modelviews/ModelView.java +++ b/prism/src/explicit/modelviews/ModelView.java @@ -2,7 +2,7 @@ // // Copyright (c) 2016- // Authors: -// * Steffen Maercker (TU Dresden) +// * Steffen Maercker (TU Dresden) // * Joachim Klein (TU Dresden) // //------------------------------------------------------------------------------ @@ -31,10 +31,10 @@ import java.util.List; import java.util.PrimitiveIterator.OfInt; +import common.iterable.FilteringIterable; +import common.iterable.FunctionalPrimitiveIterable; import common.IterableBitSet; import common.IterableStateSet; -import common.iterable.FilteringIterable; -import common.iterable.IterableInt; import explicit.Model; import explicit.PredecessorRelation; import explicit.StateValues; @@ -78,7 +78,7 @@ public int getNumDeadlockStates() } @Override - public IterableInt getDeadlockStates() + public FunctionalPrimitiveIterable.OfInt getDeadlockStates() { return new IterableBitSet(deadlockStates); } @@ -115,9 +115,9 @@ public void findDeadlocks(final boolean fix) throws PrismException } } - public IterableInt findDeadlocks(final BitSet except) + public FunctionalPrimitiveIterable.OfInt findDeadlocks(final BitSet except) { - IterableInt states = new IterableStateSet(except, getNumStates(), true); + IterableStateSet states = new IterableStateSet(except, getNumStates(), true); return new FilteringIterable.OfInt(states, state -> !getSuccessorsIterator(state).hasNext()); } diff --git a/prism/src/parser/EvaluateContextMutableState.java b/prism/src/parser/EvaluateContextMutableState.java new file mode 100644 index 0000000000..6c51289d57 --- /dev/null +++ b/prism/src/parser/EvaluateContextMutableState.java @@ -0,0 +1,46 @@ +//============================================================================== +// +// Copyright (c) 2018- +// Authors: +// * Steffen Maercker (TU Dresden) +// +//------------------------------------------------------------------------------ +// +// This file is part of PRISM. +// +// PRISM is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// PRISM 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 for more details. +// +// You should have received a copy of the GNU General Public License +// along with PRISM; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//============================================================================== + +package parser; + +public class EvaluateContextMutableState extends EvaluateContextState +{ + public EvaluateContextMutableState(State state) + { + super(state); + } + + public EvaluateContextMutableState(Values constantValues, State state) + { + super(constantValues, state); + } + + public EvaluateContextMutableState setVariables(Object[] assignment) + { + varValues = assignment; + return this; + } +} diff --git a/prism/src/parser/EvaluateContextState.java b/prism/src/parser/EvaluateContextState.java index 9f25e7c053..cb6c3885cc 100644 --- a/prism/src/parser/EvaluateContextState.java +++ b/prism/src/parser/EvaluateContextState.java @@ -33,8 +33,8 @@ */ public class EvaluateContextState implements EvaluateContext { - private Values constantValues; - private Object[] varValues; + protected Values constantValues; + protected Object[] varValues; public EvaluateContextState(State state) { diff --git a/prism/src/parser/State.java b/prism/src/parser/State.java index 944d1dfba8..b2c04afffa 100644 --- a/prism/src/parser/State.java +++ b/prism/src/parser/State.java @@ -28,6 +28,7 @@ import java.util.Arrays; import java.util.List; +import java.util.Objects; import prism.ModelInfo; import prism.PrismLangException; @@ -46,7 +47,17 @@ public class State implements Comparable */ public State(int n) { - varValues = new Object[n]; + this(new Object[n]); + } + + /** + * Construct state from value array. + * @param n Number of variables. + */ + public State(Object[] varValues) + { + Objects.requireNonNull(varValues); + this.varValues = varValues; } /** diff --git a/prism/src/parser/VarList.java b/prism/src/parser/VarList.java index 5a9cdb57c6..5d97f119fa 100644 --- a/prism/src/parser/VarList.java +++ b/prism/src/parser/VarList.java @@ -27,7 +27,12 @@ package parser; import java.util.*; +import java.util.function.Function; +import common.iterable.CartesianProduct; +import common.iterable.FunctionalIterable; +import common.iterable.Range; +import common.iterable.Reducible; import prism.*; import parser.VarList.Var; import parser.ast.*; @@ -406,45 +411,30 @@ public List getAllValues(List vars) throws PrismLangException } /** - * Get a list of all possible states over the variables in this list. Use with care! + * Get an iterable of all possible states over the variables in this list. + * States will be generated on the fly during iteration. + * Use with care! */ - public List getAllStates() throws PrismLangException + public FunctionalIterable getAllAssignments() throws PrismLangException { - List allStates; - State state, stateNew; - - int numVars = getNumVars(); - allStates = new ArrayList(); - allStates.add(new State(numVars)); - for (int i = 0; i < numVars; i++) { - if (getType(i) instanceof TypeBool) { - int n = allStates.size(); - for (int j = 0; j < n; j++) { - state = allStates.get(j); - stateNew = new State(state); - stateNew.setValue(i, true); - state.setValue(i, false); - allStates.add(stateNew); - } - } else if (getType(i) instanceof TypeInt) { - int lo = getLow(i); - int hi = getHigh(i); - int n = allStates.size(); - for (int j = 0; j < n; j++) { - state = allStates.get(j); - for (int k = lo + 1; k < hi + 1; k++) { - stateNew = new State(state); - stateNew.setValue(i, k); - allStates.add(stateNew); - } - state.setValue(i, lo); - } - } else { - throw new PrismLangException("Cannot determine all values for a variable of type " + getType(i)); + for (Var var : vars) { + Type type = var.type; + if ((type instanceof TypeBool) || (type instanceof TypeInt)) { + continue; } + throw new PrismLangException("Cannot determine all values for a variable of type " + var.type); } - return allStates; + // convert variable list to list of domains + List booleans = Arrays.asList(false, true); + Function> toDomain = var -> (var.type instanceof TypeBool) + ? booleans + : Range.closed(var.low, var.high); + FunctionalIterable variables = Reducible.extend(vars); + Iterable> domains = variables.map(toDomain); + + // iterate states from Cartesian product + return CartesianProduct.mutableOf(domains); } /** diff --git a/prism/src/prism/PrismUtils.java b/prism/src/prism/PrismUtils.java index 054f2261fe..1a4ef3b0b6 100644 --- a/prism/src/prism/PrismUtils.java +++ b/prism/src/prism/PrismUtils.java @@ -39,7 +39,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import common.iterable.IterableInt; +import common.iterable.PrimitiveIterable; import param.BigRational; /** @@ -144,7 +144,7 @@ public static boolean doublesAreClose(double d1[], double d2[], double epsilon, *
* Considers Inf == Inf and -Inf == -Inf. */ - public static boolean doublesAreClose(double d1[], double d2[], IterableInt indizes, double epsilon, boolean abs) + public static boolean doublesAreClose(double d1[], double d2[], PrimitiveIterable.OfInt indizes, double epsilon, boolean abs) { return doublesAreClose(d1, d2, indizes.iterator(), epsilon, abs); } @@ -480,7 +480,7 @@ public static double[] normalise(double[] vector) * @param entries Iterable over the entries (must not contain duplicates) * @return the altered vector (returned for convenience; it's the same one) */ - public static double[] normalise(double[] vector, IterableInt entries) + public static double[] normalise(double[] vector, PrimitiveIterable.OfInt entries) { double sum = 0.0; for (PrimitiveIterator.OfInt iter = entries.iterator(); iter.hasNext();) { diff --git a/prism/src/simulator/ModulesFileModelGenerator.java b/prism/src/simulator/ModulesFileModelGenerator.java index ff5dc88bb9..31e023d7b2 100644 --- a/prism/src/simulator/ModulesFileModelGenerator.java +++ b/prism/src/simulator/ModulesFileModelGenerator.java @@ -1,8 +1,11 @@ package simulator; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; +import parser.EvaluateContextMutableState; import parser.State; import parser.Values; import parser.VarList; @@ -250,27 +253,31 @@ public State getInitialState() throws PrismException return getInitialStates().get(0); } } - + @Override public List getInitialStates() throws PrismException { - List initStates = new ArrayList(); - // Easy (normal) case: just one initial state if (modulesFile.getInitialStates() == null) { + // Easy (normal) case: just one initial state State state = modulesFile.getDefaultInitialState(); - initStates.add(state); + return Collections.singletonList(state); } // Otherwise, there may be multiple initial states - // For now, we handle this is in a very inefficient way - else { - Expression init = modulesFile.getInitialStates(); - List allPossStates = varList.getAllStates(); - for (State possState : allPossStates) { - if (init.evaluateBoolean(modulesFile.getConstantValues(), possState)) { - initStates.add(possState); - } + // For now, we handle this in a very inefficient way + Expression init = modulesFile.getInitialStates(); + Values constants = modulesFile.getConstantValues(); + ArrayList initStates = new ArrayList(); + // We reuse the evaluation context to avoid thrashing the gc + EvaluateContextMutableState context = new EvaluateContextMutableState(constants, new State(0)); + for (Object[] assignment : varList.getAllAssignments()) { + // loop instead of filter function to handle PrismException + context.setVariables(assignment); + if (init.evaluateBoolean(context)) { + // create new state only for init states + initStates.add(new State(Arrays.copyOf(assignment, assignment.length))); } } + initStates.trimToSize(); return initStates; } diff --git a/prism/src/simulator/ModulesFileModelGeneratorSymbolic.java b/prism/src/simulator/ModulesFileModelGeneratorSymbolic.java index 9f0efb8fc5..50806bb135 100644 --- a/prism/src/simulator/ModulesFileModelGeneratorSymbolic.java +++ b/prism/src/simulator/ModulesFileModelGeneratorSymbolic.java @@ -1,12 +1,15 @@ package simulator; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; import param.Function; import param.FunctionFactory; import param.ModelBuilder; import param.SymbolicEngine; +import parser.EvaluateContextMutableState; import parser.State; import parser.Values; import parser.VarList; @@ -276,24 +279,27 @@ public State getInitialState() throws PrismException @Override public List getInitialStates() throws PrismException { - List initStates = new ArrayList(); - // Easy (normal) case: just one initial state if (modulesFile.getInitialStates() == null) { - // get initial state, using exact evaluation - State state = modulesFile.getDefaultInitialState(true); - initStates.add(state); + // Easy (normal) case: just one initial state + State state = modulesFile.getDefaultInitialState(); + return Collections.singletonList(state); } // Otherwise, there may be multiple initial states - // For now, we handle this is in a very inefficient way - else { - Expression init = modulesFile.getInitialStates(); - List allPossStates = varList.getAllStates(); - for (State possState : allPossStates) { - if (init.evaluateExact(modulesFile.getConstantValues(), possState).toBoolean()) { - initStates.add(possState); - } + // For now, we handle this in a very inefficient way + Expression init = modulesFile.getInitialStates(); + Values constants = modulesFile.getConstantValues(); + ArrayList initStates = new ArrayList(); + // We reuse the evaluation context to avoid thrashing the gc + EvaluateContextMutableState context = new EvaluateContextMutableState(constants, new State(0)); + for (Object[] assignment : varList.getAllAssignments()) { + // loop instead of filter function to handle PrismException + context.setVariables(assignment); + if (init.evaluateBoolean(context)) { + // create new state only for init states + initStates.add(new State(Arrays.copyOf(assignment, assignment.length))); } } + initStates.trimToSize(); return initStates; } diff --git a/prism/unit-tests/common/Makefile b/prism/unit-tests/common/Makefile new file mode 100644 index 0000000000..70eda419c9 --- /dev/null +++ b/prism/unit-tests/common/Makefile @@ -0,0 +1,44 @@ +################################################ +# NB: This Makefile is designed to be called # +# from the main PRISM Makefile. It won't # +# work on its own because it needs # +# various options to be passed in # +################################################ + +.SUFFIXES: .o .c .cc + +# Reminder: $@ = target, $* = target without extension, $< = dependency + +THIS_DIR = common +PRISM_DIR_REL = ../.. + +JNI_GEN_HEADER_DIR=$(THIS_DIR)/$(PRISM_DIR_REL)/$(PRISM_INCLUDE_DIR)/jni + +JAVA_FILES_ALL = $(wildcard *.java iterable/*.java) +JAVA_FILES = $(subst package-info.java,,$(JAVA_FILES_ALL)) +CLASS_FILES = $(JAVA_FILES:%.java=$(PRISM_DIR_REL)/$(PRISM_CLASSES_DIR)/$(THIS_DIR)/%.class) + +PRISM_CLASSPATH = "$(THIS_DIR)/$(PRISM_DIR_REL)/$(PRISM_CLASSES_DIR)$(CLASSPATHSEP)$(THIS_DIR)/$(PRISM_DIR_REL)/$(PRISM_LIB_DIR)/*" + +default: all + +all: checks $(CLASS_FILES) + +# inhibit building in parallel (-j option) +.NOTPARALLEL: + +# Try and prevent accidental makes (i.e. called manually, not from top-level Makefile) +checks: + @if [ "$(PRISM_SRC_DIR)" = "" ]; then \ + (echo "Error: This Makefile is designed to be called from the main PRISM Makefile"; exit 1) \ + fi; + +$(PRISM_DIR_REL)/$(PRISM_CLASSES_DIR)/$(THIS_DIR)/%.class: %.java + (cd ..; $(JAVAC) $(JFLAGS) -sourcepath $(THIS_DIR)/$(PRISM_DIR_REL)/$(PRISM_SRC_DIR)$(CLASSPATHSEP)$(THIS_DIR)/$(PRISM_DIR_REL)/unit-tests -classpath $(PRISM_CLASSPATH) -h $(JNI_GEN_HEADER_DIR) -d $(THIS_DIR)/$(PRISM_DIR_REL)/$(PRISM_CLASSES_DIR) $(THIS_DIR)/$<) + +clean: checks + @rm -f $(CLASS_FILES) + +celan: clean + +################################################# diff --git a/prism/unit-tests/common/iterable/ArrayIteratorTest.java b/prism/unit-tests/common/iterable/ArrayIteratorTest.java new file mode 100644 index 0000000000..958f49b1b3 --- /dev/null +++ b/prism/unit-tests/common/iterable/ArrayIteratorTest.java @@ -0,0 +1,253 @@ +package common.iterable; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.NoSuchElementException; +import java.util.Optional; +import java.util.function.Supplier; + +import static common.iterable.Assertions.assertIteratorEquals; +import static org.junit.jupiter.api.Assertions.*; + +interface ArrayIteratorTest +{ + @ParameterizedTest + @MethodSource("getReducibles") + default void testNextIndex(Supplier> supplier) + { + ArrayIterator iterator = supplier.get(); + for (int i=0; iterator.hasNext(); i++) { + assertEquals(i, iterator.nextIndex()); + iterator.next(); + } + assertThrows(NoSuchElementException.class, iterator::nextIndex); + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class Of implements ArrayIteratorTest, FunctionalIteratorTest.Of> + { + @Override + public ArrayIterator.Of getReducible(Object[] objects) + { + return new ArrayIterator.Of<>(objects); + } + + @ParameterizedTest + @MethodSource("getArraysAsArguments") + public void testOfArray(Object[] array) + { + ArrayIterator.Of iterator = new ArrayIterator.Of<>(array); + Object[] actual = iterator.collect(new Object[array.length]); + assertArrayEquals(array, actual); + } + + @ParameterizedTest + @MethodSource("getArraysAsArguments") + public void testOfArrayIntInt_All(Object[] array) + { + ArrayIterator.Of expected = new ArrayIterator.Of<>(array); + ArrayIterator.Of actual = new ArrayIterator.Of<>(array, 0, array.length); + assertIteratorEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource({"getMultitonArraysAsArguments"}) + public void testOfArrayIntInt_Range(Object[] array) + { + FunctionalIterable expected = new Range(1, array.length - 1).map((int i) -> array[i]); + ArrayIterator.Of actual = new ArrayIterator.Of<>(array, 1, array.length - 1); + assertIteratorEquals(expected.iterator(), actual); + } + + @Test + public void testOf_Errors() + { + Optional any = getMultitonArraysOfObject().findAny(); + assert any.isPresent(); + Object[] array = any.get(); + int length = array.length; + assertThrows(NullPointerException.class, () -> new ArrayIterator.Of<>((Object[]) null)); + assertThrows(NullPointerException.class, () -> new ArrayIterator.Of<>(null, 0, 0)); + assertThrows(IndexOutOfBoundsException.class, () -> new ArrayIterator.Of<>(array, -1, -1)); + assertThrows(IndexOutOfBoundsException.class, () -> new ArrayIterator.Of<>(array, -1, length)); + assertThrows(IndexOutOfBoundsException.class, () -> new ArrayIterator.Of<>(array, 1, 0)); + assertThrows(IndexOutOfBoundsException.class, () -> new ArrayIterator.Of<>(array, 0, length+1)); + assertThrows(IndexOutOfBoundsException.class, () -> new ArrayIterator.Of<>(array, length+1, length+1)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfDouble implements ArrayIteratorTest, FunctionalPrimitiveIteratorTest.OfDouble + { + @Override + public ArrayIterator.OfDouble getReducible(double[] numbers) + { + return new ArrayIterator.OfDouble(numbers); + } + + @ParameterizedTest + @MethodSource({"getEmptyArraysOfDouble", "getSingletonArraysOfDouble", "getMultitonArraysOfDouble"}) + public void testOfDouble(double[] array) + { + ArrayIterator.OfDouble iterator = new ArrayIterator.OfDouble(array); + double[] actual = iterator.collect(new double[array.length]); + assertArrayEquals(array, actual); + } + + @ParameterizedTest + @MethodSource({"getEmptyArraysOfDouble", "getSingletonArraysOfDouble", "getMultitonArraysOfDouble"}) + public void testOfDoubleArrayIntInt_All(double[] array) + { + ArrayIterator.OfDouble expected = new ArrayIterator.OfDouble(array); + ArrayIterator.OfDouble actual = new ArrayIterator.OfDouble(array, 0, array.length); + assertIteratorEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource({"getMultitonArraysOfDouble"}) + public void testOfDoubleArrayIntInt_Range(double[] array) + { + FunctionalPrimitiveIterable.OfDouble expected = new Range(1, array.length - 1).mapToDouble((int i) -> array[i]); + ArrayIterator.OfDouble actual = new ArrayIterator.OfDouble(array, 1, array.length - 1); + assertIteratorEquals(expected.iterator(), actual); + } + + @Test + public void testOfDouble_Errors() + { + Optional any = getMultitonArraysOfDouble().findAny(); + assert any.isPresent(); + double[] array = any.get(); + int length = array.length; + assertThrows(NullPointerException.class, () -> new ArrayIterator.OfDouble((double[]) null)); + assertThrows(NullPointerException.class, () -> new ArrayIterator.OfDouble(null, 0, 0)); + assertThrows(IndexOutOfBoundsException.class, () -> new ArrayIterator.OfDouble(array, -1, -1)); + assertThrows(IndexOutOfBoundsException.class, () -> new ArrayIterator.OfDouble(array, -1, length)); + assertThrows(IndexOutOfBoundsException.class, () -> new ArrayIterator.OfDouble(array, 1, 0)); + assertThrows(IndexOutOfBoundsException.class, () -> new ArrayIterator.OfDouble(array, 0, length+1)); + assertThrows(IndexOutOfBoundsException.class, () -> new ArrayIterator.OfDouble(array, length+1, length+1)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfInt implements ArrayIteratorTest, FunctionalPrimitiveIteratorTest.OfInt + { + @Override + public ArrayIterator.OfInt getReducible(int[] numbers) + { + return new ArrayIterator.OfInt(numbers); + } + + @ParameterizedTest + @MethodSource({"getEmptyArraysOfInt", "getSingletonArraysOfInt", "getMultitonArraysOfInt"}) + public void testOfInt(int[] array) + { + ArrayIterator.OfInt iterator = new ArrayIterator.OfInt(array); + int[] actual = iterator.collect(new int[array.length]); + assertArrayEquals(array, actual); + } + + @ParameterizedTest + @MethodSource({"getEmptyArraysOfInt", "getSingletonArraysOfInt", "getMultitonArraysOfInt"}) + public void testOfIntArrayIntInt_All(int[] array) + { + ArrayIterator.OfInt expected = new ArrayIterator.OfInt(array); + ArrayIterator.OfInt actual = new ArrayIterator.OfInt(array, 0, array.length); + assertIteratorEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource({"getMultitonArraysOfInt"}) + public void testOfIntArrayIntInt_Range(int[] array) + { + FunctionalPrimitiveIterable.OfInt expected = new Range(1, array.length - 1).mapToInt((int i) -> array[i]); + ArrayIterator.OfInt actual = new ArrayIterator.OfInt(array, 1, array.length - 1); + assertIteratorEquals(expected.iterator(), actual); + } + + @Test + public void testOfInt_Errors() + { + Optional any = getMultitonArraysOfInt().findAny(); + assert any.isPresent(); + int[] array = any.get(); + int length = array.length; + assertThrows(NullPointerException.class, () -> new ArrayIterator.OfInt((int[]) null)); + assertThrows(NullPointerException.class, () -> new ArrayIterator.OfInt(null, 0, 0)); + assertThrows(IndexOutOfBoundsException.class, () -> new ArrayIterator.OfInt(array, -1, -1)); + assertThrows(IndexOutOfBoundsException.class, () -> new ArrayIterator.OfInt(array, -1, length)); + assertThrows(IndexOutOfBoundsException.class, () -> new ArrayIterator.OfInt(array, 1, 0)); + assertThrows(IndexOutOfBoundsException.class, () -> new ArrayIterator.OfInt(array, 0, length+1)); + assertThrows(IndexOutOfBoundsException.class, () -> new ArrayIterator.OfInt(array, length+1, length+1)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfLong implements ArrayIteratorTest, FunctionalPrimitiveIteratorTest.OfLong + { + @Override + public ArrayIterator.OfLong getReducible(long[] numbers) + { + return new ArrayIterator.OfLong(numbers); + } + + @ParameterizedTest + @MethodSource({"getEmptyArraysOfLong", "getSingletonArraysOfLong", "getMultitonArraysOfLong"}) + public void testOfLong(long[] array) + { + ArrayIterator.OfLong iterator = new ArrayIterator.OfLong(array); + long[] actual = iterator.collect(new long[array.length]); + assertArrayEquals(array, actual); + } + + @ParameterizedTest + @MethodSource({"getEmptyArraysOfLong", "getSingletonArraysOfLong", "getMultitonArraysOfLong"}) + public void testOfLongArrayIntInt_All(long[] array) + { + ArrayIterator.OfLong expected = new ArrayIterator.OfLong(array); + ArrayIterator.OfLong actual = new ArrayIterator.OfLong(array, 0, array.length); + assertIteratorEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource({"getMultitonArraysOfLong"}) + public void testOfLongArrayIntInt_Range(long[] array) + { + FunctionalPrimitiveIterable.OfLong expected = new Range(1, array.length - 1).mapToLong((int i) -> array[i]); + ArrayIterator.OfLong actual = new ArrayIterator.OfLong(array, 1, array.length - 1); + assertIteratorEquals(expected.iterator(), actual); + } + + @Test + public void testOfLong_Errors() + { + Optional any = getMultitonArraysOfLong().findAny(); + assert any.isPresent(); + long[] array = any.get(); + int length = array.length; + assertThrows(NullPointerException.class, () -> new ArrayIterator.OfLong((long[]) null)); + assertThrows(NullPointerException.class, () -> new ArrayIterator.OfLong(null, 0, 0)); + assertThrows(IndexOutOfBoundsException.class, () -> new ArrayIterator.OfLong(array, -1, -1)); + assertThrows(IndexOutOfBoundsException.class, () -> new ArrayIterator.OfLong(array, -1, length)); + assertThrows(IndexOutOfBoundsException.class, () -> new ArrayIterator.OfLong(array, 1, 0)); + assertThrows(IndexOutOfBoundsException.class, () -> new ArrayIterator.OfLong(array, 0, length+1)); + assertThrows(IndexOutOfBoundsException.class, () -> new ArrayIterator.OfLong(array, length+1, length+1)); + } + } +} \ No newline at end of file diff --git a/prism/unit-tests/common/iterable/Assertions.java b/prism/unit-tests/common/iterable/Assertions.java new file mode 100644 index 0000000000..113676bf6a --- /dev/null +++ b/prism/unit-tests/common/iterable/Assertions.java @@ -0,0 +1,80 @@ +package common.iterable; + +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.PrimitiveIterator; + +import static org.junit.jupiter.api.Assertions.*; + +public class Assertions +{ + /** + * Assert two double values are equals while assuming -0.0 == +0.0 and NaN == NaN. + */ + protected static void assertDoubleEquals(double expected, double actual) + { + assertTrue(expected == actual || Double.isNaN(expected) && Double.isNaN(actual)); + } + + public static void assertIterableEquals(PrimitiveIterable.OfDouble expected, PrimitiveIterable.OfDouble actual) + { + assertIteratorEquals(expected.iterator(), actual.iterator()); + } + + public static void assertIterableEquals(PrimitiveIterable.OfInt expected, PrimitiveIterable.OfInt actual) + { + assertIteratorEquals(expected.iterator(), actual.iterator()); + } + + public static void assertIterableEquals(PrimitiveIterable.OfLong expected, PrimitiveIterable.OfLong actual) + { + assertIteratorEquals(expected.iterator(), actual.iterator()); + } + + public static void assertIteratorEquals(Iterator expected, Iterator actual) + { + while(expected.hasNext() && actual.hasNext()) { + assertEquals(expected.next(), actual.next()); + } + assertFalse(expected.hasNext()); + assertFalse(actual.hasNext()); + assertThrows(NoSuchElementException.class, expected::next); + assertThrows(NoSuchElementException.class, actual::next); + } + + public static void assertIteratorEquals(PrimitiveIterator.OfDouble expected, PrimitiveIterator.OfDouble actual) + { + while(expected.hasNext() && actual.hasNext()) { + double exp = expected.nextDouble(); + double act = actual.nextDouble(); + assertDoubleEquals(exp, act); + } + assertFalse(expected.hasNext()); + assertFalse(actual.hasNext()); + assertThrows(NoSuchElementException.class, expected::next); + assertThrows(NoSuchElementException.class, actual::next); + } + + public static void assertIteratorEquals(PrimitiveIterator.OfInt expected, PrimitiveIterator.OfInt actual) + { + while(expected.hasNext() && actual.hasNext()) { + assertEquals(expected.nextInt(), actual.nextInt()); + } + assertFalse(expected.hasNext()); + assertFalse(actual.hasNext()); + assertThrows(NoSuchElementException.class, expected::next); + assertThrows(NoSuchElementException.class, actual::next); + } + + public static void assertIteratorEquals(PrimitiveIterator.OfLong expected, PrimitiveIterator.OfLong actual) + { + while(expected.hasNext() && actual.hasNext()) { + assertEquals(expected.nextLong(), actual.nextLong()); + } + assertFalse(expected.hasNext()); + assertFalse(actual.hasNext()); + assertThrows(NoSuchElementException.class, expected::next); + assertThrows(NoSuchElementException.class, actual::next); + } + +} diff --git a/prism/unit-tests/common/iterable/ChainedIterableTest.java b/prism/unit-tests/common/iterable/ChainedIterableTest.java new file mode 100644 index 0000000000..f0952b9558 --- /dev/null +++ b/prism/unit-tests/common/iterable/ChainedIterableTest.java @@ -0,0 +1,345 @@ +package common.iterable; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.*; +import java.util.function.Supplier; +import java.util.stream.Stream; + +import static common.iterable.Assertions.assertIterableEquals; +import static common.iterable.Reducible.*; +import static org.junit.jupiter.api.Assertions.assertIterableEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +interface ChainedIterableTest +{ + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class Of implements ChainedIterableTest, FunctionalIterableTest.Of> + { + @Override + public ChainedIterable.Of getReducible(Object[] objects) + { + throw new RuntimeException("Should not be called"); + } + + protected Stream>> split(Object[] objects) + { + // 1. whole sequence + FunctionalIterable> complete = FunctionalIterable.of(Arrays.asList(objects)); + // 2. split & pad with empty + List empty = Collections.emptyList(); + int l1 = objects.length / 2; + Object[] first = new Object[l1]; + System.arraycopy(objects, 0, first, 0, l1); + int l2 = objects.length - l1; + Object[] second = new Object[l2]; + System.arraycopy(objects, l1, second, 0, l2); + FunctionalIterable> chunks = FunctionalIterable.of(empty, Arrays.asList(first), empty, Arrays.asList(second), empty); + return Stream.of(complete, chunks); + } + + public Stream>> getChains() + { + return getArraysOfObject().flatMap(this::split); + } + + @Override + public Stream>> getDuplicatesReducibles() + { + Stream>> splits = getDuplicatesArraysOfObject().flatMap(this::split); + return splits.map(args -> () -> new ChainedIterable.Of<>(args)); + } + + @Override + public Stream>> getEmptyReducibles() + { + Stream>> splits = getEmptyArraysOfObject().flatMap(this::split); + return splits.map(args -> () -> new ChainedIterable.Of<>(args)); + } + + @Override + public Stream>> getSingletonReducibles() + { + Stream>> splits = getSingletonArraysOfObject().flatMap(this::split); + return splits.map(args -> () -> new ChainedIterable.Of<>(args)); + } + + @Override + public Stream>> getMultitonReducibles() + { + Stream>> splits = getMultitonArraysOfObject().flatMap(this::split); + return splits.map(args -> () -> new ChainedIterable.Of<>(args)); + } + + @ParameterizedTest + @MethodSource("getChains") + public void testOf(Iterable> chain) + { + List expected = new ArrayList<>(); + for (Iterable iterable : chain) { + for (Object each : iterable) { + expected.add(each); + } + } + ChainedIterable.Of actual = new ChainedIterable.Of<>(chain); + assertIterableEquals(expected, actual); + } + + @Test + public void testOf_Null() + { + assertThrows(NullPointerException.class, () -> new ChainedIterable.Of<>(null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfDouble implements ChainedIterableTest, FunctionalPrimitiveIterableTest.OfDouble + { + @Override + public ChainedIterable.OfDouble getReducible(double[] numbers) + { + throw new RuntimeException("Should not be called"); + } + + protected Stream> split(double[] numbers) + { + // 1. whole sequence + FunctionalIterable complete = FunctionalIterable.of(new IterableArray.OfDouble(numbers)); + // 2. split & pad with empty + EmptyIterable.OfDouble empty = EmptyIterable.ofDouble(); + int l1 = numbers.length / 2; + double[] first = new double[l1]; + System.arraycopy(numbers, 0, first, 0, l1); + int l2 = numbers.length - l1; + double[] second = new double[l2]; + System.arraycopy(numbers, l1, second, 0, l2); + FunctionalIterable chunks = FunctionalIterable.of(empty, new IterableArray.OfDouble(first), empty, new IterableArray.OfDouble(second), empty); + return Stream.of(complete, chunks); + } + + public Stream> getChains() + { + return getArraysOfDouble().flatMap(this::split); + } + + @Override + public Stream> getDuplicatesReducibles() + { + Stream> splits = getDuplicatesArraysOfDouble().flatMap(this::split); + return splits.map(args -> () -> new ChainedIterable.OfDouble(args)); + } + + @Override + public Stream> getEmptyReducibles() + { + Stream> splits = getEmptyArraysOfDouble().flatMap(this::split); + return splits.map(args -> () -> new ChainedIterable.OfDouble(args)); + } + + @Override + public Stream> getSingletonReducibles() + { + Stream> splits = getSingletonArraysOfDouble().flatMap(this::split); + return splits.map(args -> () -> new ChainedIterable.OfDouble(args)); + } + + @Override + public Stream> getMultitonReducibles() + { + Stream> splits = getMultitonArraysOfDouble().flatMap(this::split); + return splits.map(args -> () -> new ChainedIterable.OfDouble(args)); + } + + @ParameterizedTest + @MethodSource("getChains") + public void testOf(FunctionalIterable chain) + { + List expected = new ArrayList<>(); + for (Iterable iterable : chain) { + for (Double each : iterable) { + expected.add(each); + } + } + ChainedIterable.OfDouble actual = new ChainedIterable.OfDouble(chain); + assertIterableEquals(unboxDouble(expected), actual); + } + + @Test + public void testOfDouble_Null() + { + assertThrows(NullPointerException.class, () -> new ChainedIterable.OfDouble(null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfInt implements ChainedIterableTest, FunctionalPrimitiveIterableTest.OfInt + { + @Override + public ChainedIterable.OfInt getReducible(int[] numbers) + { + throw new RuntimeException("Should not be called"); + } + + protected Stream> split(int[] numbers) + { + // 1. whole sequence + FunctionalIterable complete = FunctionalIterable.of(new IterableArray.OfInt(numbers)); + // 2. split & pad with empty + EmptyIterable.OfInt empty = EmptyIterable.ofInt(); + int l1 = numbers.length / 2; + int[] first = new int[l1]; + System.arraycopy(numbers, 0, first, 0, l1); + int l2 = numbers.length - l1; + int[] second = new int[l2]; + System.arraycopy(numbers, l1, second, 0, l2); + FunctionalIterable chunks = FunctionalIterable.of(empty, new IterableArray.OfInt(first), empty, new IterableArray.OfInt(second), empty); + return Stream.of(complete, chunks); + } + + public Stream> getChains() + { + return getArraysOfInt().flatMap(this::split); + } + + @Override + public Stream> getDuplicatesReducibles() + { + Stream> splits = getDuplicatesArraysOfInt().flatMap(this::split); + return splits.map(args -> () -> new ChainedIterable.OfInt(args)); + } + + @Override + public Stream> getEmptyReducibles() + { + Stream> splits = getEmptyArraysOfInt().flatMap(this::split); + return splits.map(args -> () -> new ChainedIterable.OfInt(args)); + } + + @Override + public Stream> getSingletonReducibles() + { + Stream> splits = getSingletonArraysOfInt().flatMap(this::split); + return splits.map(args -> () -> new ChainedIterable.OfInt(args)); + } + + @Override + public Stream> getMultitonReducibles() + { + Stream> splits = getMultitonArraysOfInt().flatMap(this::split); + return splits.map(args -> () -> new ChainedIterable.OfInt(args)); + } + + @ParameterizedTest + @MethodSource("getChains") + public void testOf(FunctionalIterable chain) + { + List expected = new ArrayList<>(); + for (Iterable iterable : chain) { + for (Integer each : iterable) { + expected.add(each); + } + } + ChainedIterable.OfInt actual = new ChainedIterable.OfInt(chain); + assertIterableEquals(unboxInt(expected), actual); + } + + @Test + public void testOfDouble_Null() + { + assertThrows(NullPointerException.class, () -> new ChainedIterable.OfInt(null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfLong implements ChainedIterableTest, FunctionalPrimitiveIterableTest.OfLong + { + @Override + public ChainedIterable.OfLong getReducible(long[] numbers) + { + throw new RuntimeException("Should not be called"); + } + + protected Stream> split(long[] numbers) + { + // 1. whole sequence + FunctionalIterable complete = FunctionalIterable.of(new IterableArray.OfLong(numbers)); + // 2. split & pad with empty + EmptyIterable.OfLong empty = EmptyIterable.ofLong(); + int l1 = numbers.length / 2; + long[] first = new long[l1]; + System.arraycopy(numbers, 0, first, 0, l1); + int l2 = numbers.length - l1; + long[] second = new long[l2]; + System.arraycopy(numbers, l1, second, 0, l2); + FunctionalIterable chunks = FunctionalIterable.of(empty, new IterableArray.OfLong(first), empty, new IterableArray.OfLong(second), empty); + return Stream.of(complete, chunks); + } + + public Stream> getChains() + { + return getArraysOfLong().flatMap(this::split); + } + + @Override + public Stream> getDuplicatesReducibles() + { + Stream> splits = getDuplicatesArraysOfLong().flatMap(this::split); + return splits.map(args -> () -> new ChainedIterable.OfLong(args)); + } + + @Override + public Stream> getEmptyReducibles() + { + Stream> splits = getEmptyArraysOfLong().flatMap(this::split); + return splits.map(args -> () -> new ChainedIterable.OfLong(args)); + } + + @Override + public Stream> getSingletonReducibles() + { + Stream> splits = getSingletonArraysOfLong().flatMap(this::split); + return splits.map(args -> () -> new ChainedIterable.OfLong(args)); + } + + @Override + public Stream> getMultitonReducibles() + { + Stream> splits = getMultitonArraysOfLong().flatMap(this::split); + return splits.map(args -> () -> new ChainedIterable.OfLong(args)); + } + + @ParameterizedTest + @MethodSource("getChains") + public void testOf(FunctionalIterable chain) + { + List expected = new ArrayList<>(); + for (Iterable iterable : chain) { + for (Long each : iterable) { + expected.add(each); + } + } + ChainedIterable.OfLong actual = new ChainedIterable.OfLong(chain); + assertIterableEquals(unboxLong(expected), actual); + } + + @Test + public void testOfDouble_Null() + { + assertThrows(NullPointerException.class, () -> new ChainedIterable.OfLong(null)); + } + } +} diff --git a/prism/unit-tests/common/iterable/ChainedIteratorTest.java b/prism/unit-tests/common/iterable/ChainedIteratorTest.java new file mode 100644 index 0000000000..e1e05c7614 --- /dev/null +++ b/prism/unit-tests/common/iterable/ChainedIteratorTest.java @@ -0,0 +1,347 @@ +package common.iterable; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.*; +import java.util.function.Supplier; +import java.util.stream.Stream; + +import static common.iterable.Assertions.assertIteratorEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +interface ChainedIteratorTest +{ + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class Of implements ChainedIteratorTest, FunctionalIteratorTest.Of> + { + @Override + public ChainedIterator.Of getReducible(Object[] objects) + { + throw new RuntimeException("Should not be called"); + } + + protected Stream>> split(Object[] objects) + { + // 1. whole sequence + FunctionalIterable> complete = FunctionalIterable.of(Arrays.asList(objects)); + // 2. split & pad with empty + List empty = Collections.emptyList(); + int l1 = objects.length / 2; + Object[] first = new Object[l1]; + System.arraycopy(objects, 0, first, 0, l1); + int l2 = objects.length - l1; + Object[] second = new Object[l2]; + System.arraycopy(objects, l1, second, 0, l2); + FunctionalIterable> chunks = FunctionalIterable.of(empty, Arrays.asList(first), empty, Arrays.asList(second), empty); + return Stream.of(complete, chunks); + } + + public Stream>> getChains() + { + return getArraysOfObject().flatMap(this::split); + } + + @Override + public Stream>> getDuplicatesReducibles() + { + Stream>> splits = getDuplicatesArraysOfObject().flatMap(this::split); + return splits.map(args -> () -> new ChainedIterator.Of<>(args.map(Iterable::iterator).iterator())); + } + + @Override + public Stream>> getEmptyReducibles() + { + Stream>> splits = getEmptyArraysOfObject().flatMap(this::split); + return splits.map(args -> () -> new ChainedIterator.Of<>(args.map(Iterable::iterator).iterator())); + } + + @Override + public Stream>> getSingletonReducibles() + { + Stream>> splits = getSingletonArraysOfObject().flatMap(this::split); + return splits.map(args -> () -> new ChainedIterator.Of<>(args.map(Iterable::iterator).iterator())); + } + + @Override + public Stream>> getMultitonReducibles() + { + Stream>> splits = getMultitonArraysOfObject().flatMap(this::split); + return splits.map(args -> () -> new ChainedIterator.Of<>(args.map(Iterable::iterator).iterator())); + } + + @ParameterizedTest + @MethodSource("getChains") + public void testOf(FunctionalIterable> chain) + { + List expected = new ArrayList<>(); + for (Iterable iterable : chain) { + for (Object each : iterable) { + expected.add(each); + } + } + FunctionalIterator> iterators = Reducible.extend(chain.iterator()).map(Iterable::iterator); + ChainedIterator.Of actual = new ChainedIterator.Of<>(iterators); + assertIteratorEquals(expected.iterator(), actual); + } + + @Test + public void testOf_Null() + { + assertThrows(NullPointerException.class, () -> new ChainedIterator.Of<>(null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfDouble implements ChainedIteratorTest, FunctionalPrimitiveIteratorTest.OfDouble + { + @Override + public ChainedIterator.OfDouble getReducible(double[] numbers) + { + throw new RuntimeException("Should not be called"); + } + + protected Stream> split(double[] numbers) + { + // 1. whole sequence + FunctionalIterable complete = FunctionalIterable.of(new IterableArray.OfDouble(numbers)); + // 2. split & pad with empty + EmptyIterable.OfDouble empty = EmptyIterable.ofDouble(); + int l1 = numbers.length / 2; + double[] first = new double[l1]; + System.arraycopy(numbers, 0, first, 0, l1); + int l2 = numbers.length - l1; + double[] second = new double[l2]; + System.arraycopy(numbers, l1, second, 0, l2); + FunctionalIterable chunks = FunctionalIterable.of(empty, new IterableArray.OfDouble(first), empty, new IterableArray.OfDouble(second), empty); + return Stream.of(complete, chunks); + } + + public Stream> getChains() + { + return getArraysOfDouble().flatMap(this::split); + } + + @Override + public Stream> getDuplicatesReducibles() + { + Stream> splits = getDuplicatesArraysOfDouble().flatMap(this::split); + return splits.map(args -> () -> new ChainedIterator.OfDouble(args.map(PrimitiveIterable.OfDouble::iterator).iterator())); + } + + @Override + public Stream> getEmptyReducibles() + { + Stream> splits = getEmptyArraysOfDouble().flatMap(this::split); + return splits.map(args -> () -> new ChainedIterator.OfDouble(args.map(PrimitiveIterable.OfDouble::iterator).iterator())); + } + + @Override + public Stream> getSingletonReducibles() + { + Stream> splits = getSingletonArraysOfDouble().flatMap(this::split); + return splits.map(args -> () -> new ChainedIterator.OfDouble(args.map(PrimitiveIterable.OfDouble::iterator).iterator())); + } + + @Override + public Stream> getMultitonReducibles() + { + Stream> splits = getMultitonArraysOfDouble().flatMap(this::split); + return splits.map(args -> () -> new ChainedIterator.OfDouble(args.map(PrimitiveIterable.OfDouble::iterator).iterator())); + } + + @ParameterizedTest + @MethodSource("getChains") + public void testOf(FunctionalIterable chain) + { + List expected = new ArrayList<>(); + for (Iterable iterable : chain) { + for (Double each : iterable) { + expected.add(each); + } + } + FunctionalIterator iterators = Reducible.extend(chain.iterator()).map(PrimitiveIterable.OfDouble::iterator); + ChainedIterator.OfDouble actual = new ChainedIterator.OfDouble(iterators); + assertIteratorEquals(expected.iterator(), actual); + } + + @Test + public void testOfDouble_Null() + { + assertThrows(NullPointerException.class, () -> new ChainedIterator.OfDouble(null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfInt implements ChainedIteratorTest, FunctionalPrimitiveIteratorTest.OfInt + { + @Override + public ChainedIterator.OfInt getReducible(int[] numbers) + { + throw new RuntimeException("Should not be called"); + } + + protected Stream> split(int[] numbers) + { + // 1. whole sequence + FunctionalIterable complete = FunctionalIterable.of(new IterableArray.OfInt(numbers)); + // 2. split & pad with empty + EmptyIterable.OfInt empty = EmptyIterable.ofInt(); + int l1 = numbers.length / 2; + int[] first = new int[l1]; + System.arraycopy(numbers, 0, first, 0, l1); + int l2 = numbers.length - l1; + int[] second = new int[l2]; + System.arraycopy(numbers, l1, second, 0, l2); + FunctionalIterable chunks = FunctionalIterable.of(empty, new IterableArray.OfInt(first), empty, new IterableArray.OfInt(second), empty); + return Stream.of(complete, chunks); + } + + public Stream> getChains() + { + return getArraysOfInt().flatMap(this::split); + } + + @Override + public Stream> getDuplicatesReducibles() + { + Stream> splits = getDuplicatesArraysOfInt().flatMap(this::split); + return splits.map(args -> () -> new ChainedIterator.OfInt(args.map(PrimitiveIterable.OfInt::iterator).iterator())); + } + + @Override + public Stream> getEmptyReducibles() + { + Stream> splits = getEmptyArraysOfInt().flatMap(this::split); + return splits.map(args -> () -> new ChainedIterator.OfInt(args.map(PrimitiveIterable.OfInt::iterator).iterator())); + } + + @Override + public Stream> getSingletonReducibles() + { + Stream> splits = getSingletonArraysOfInt().flatMap(this::split); + return splits.map(args -> () -> new ChainedIterator.OfInt(args.map(PrimitiveIterable.OfInt::iterator).iterator())); + } + + @Override + public Stream> getMultitonReducibles() + { + Stream> splits = getMultitonArraysOfInt().flatMap(this::split); + return splits.map(args -> () -> new ChainedIterator.OfInt(args.map(PrimitiveIterable.OfInt::iterator).iterator())); + } + + @ParameterizedTest + @MethodSource("getChains") + public void testOf(FunctionalIterable chain) + { + List expected = new ArrayList<>(); + for (Iterable iterable : chain) { + for (Integer each : iterable) { + expected.add(each); + } + } + FunctionalIterator iterators = Reducible.extend(chain.iterator()).map(PrimitiveIterable.OfInt::iterator); + ChainedIterator.OfInt actual = new ChainedIterator.OfInt(iterators); + assertIteratorEquals(expected.iterator(), actual); + } + + @Test + public void testOfDouble_Null() + { + assertThrows(NullPointerException.class, () -> new ChainedIterator.OfInt(null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfLong implements ChainedIteratorTest, FunctionalPrimitiveIteratorTest.OfLong + { + @Override + public ChainedIterator.OfLong getReducible(long[] numbers) + { + throw new RuntimeException("Should not be called"); + } + + protected Stream> split(long[] numbers) + { + // 1. whole sequence + FunctionalIterable complete = FunctionalIterable.of(new IterableArray.OfLong(numbers)); + // 2. split & pad with empty + EmptyIterable.OfLong empty = EmptyIterable.ofLong(); + int l1 = numbers.length / 2; + long[] first = new long[l1]; + System.arraycopy(numbers, 0, first, 0, l1); + int l2 = numbers.length - l1; + long[] second = new long[l2]; + System.arraycopy(numbers, l1, second, 0, l2); + FunctionalIterable chunks = FunctionalIterable.of(empty, new IterableArray.OfLong(first), empty, new IterableArray.OfLong(second), empty); + return Stream.of(complete, chunks); + } + + public Stream> getChains() + { + return getArraysOfLong().flatMap(this::split); + } + + @Override + public Stream> getDuplicatesReducibles() + { + Stream> splits = getDuplicatesArraysOfLong().flatMap(this::split); + return splits.map(args -> () -> new ChainedIterator.OfLong(args.map(PrimitiveIterable.OfLong::iterator).iterator())); + } + + @Override + public Stream> getEmptyReducibles() + { + Stream> splits = getEmptyArraysOfLong().flatMap(this::split); + return splits.map(args -> () -> new ChainedIterator.OfLong(args.map(PrimitiveIterable.OfLong::iterator).iterator())); + } + + @Override + public Stream> getSingletonReducibles() + { + Stream> splits = getSingletonArraysOfLong().flatMap(this::split); + return splits.map(args -> () -> new ChainedIterator.OfLong(args.map(PrimitiveIterable.OfLong::iterator).iterator())); + } + + @Override + public Stream> getMultitonReducibles() + { + Stream> splits = getMultitonArraysOfLong().flatMap(this::split); + return splits.map(args -> () -> new ChainedIterator.OfLong(args.map(PrimitiveIterable.OfLong::iterator).iterator())); + } + + @ParameterizedTest + @MethodSource("getChains") + public void testOf(FunctionalIterable chain) + { + List expected = new ArrayList<>(); + for (Iterable iterable : chain) { + for (Long each : iterable) { + expected.add(each); + } + } + FunctionalIterator iterators = Reducible.extend(chain.iterator()).map(PrimitiveIterable.OfLong::iterator); + ChainedIterator.OfLong actual = new ChainedIterator.OfLong(iterators); + assertIteratorEquals(expected.iterator(), actual); + } + + @Test + public void testOfDouble_Null() + { + assertThrows(NullPointerException.class, () -> new ChainedIterator.OfLong(null)); + } + } +} diff --git a/prism/unit-tests/common/iterable/DistinctTest.java b/prism/unit-tests/common/iterable/DistinctTest.java new file mode 100644 index 0000000000..b11636438a --- /dev/null +++ b/prism/unit-tests/common/iterable/DistinctTest.java @@ -0,0 +1,160 @@ +package common.iterable; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.*; + +public interface DistinctTest> +{ + T getDistinct(); + + boolean test(T distinct, E element); + + Stream> getElements(); + + @ParameterizedTest + @MethodSource("getElements") + default void testGetSeen(FunctionalIterable elements) + { + T distinct = getDistinct(); + assertTrue(distinct.getSeen().isEmpty()); + for (E e : elements) { + test(distinct, e); + test(distinct, e); + } + FunctionalIterable seen = distinct.getSeen(); + for (E e : elements) { + assertTrue(seen.contains(e)); + } + for (E e : seen) { + assertTrue(elements.contains(e)); + } + } + + @ParameterizedTest + @MethodSource("getElements") + default void testTest(FunctionalIterable elements) + { + T distinct = getDistinct(); + for (E e : elements) { + assertTrue(test(distinct, e)); + assertFalse(test(distinct, e)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class Of implements DistinctTest> + { + @Override + public Distinct.Of getDistinct() + { + return new Distinct.Of<>(); + } + + @Override + public boolean test(Distinct.Of distinct, String element) + { + return distinct.test(element); + } + + @Override + public Stream> getElements() + { + return Stream.of(new IterableArray.Of<>("first", "second", "third")); + } + } + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfDouble implements DistinctTest + { + @Override + public Distinct.OfDouble getDistinct() + { + return new Distinct.OfDouble(); + } + + @Override + public boolean test(Distinct.OfDouble distinct, Double element) + { + return distinct.test(element); + } + + @Override + public Stream> getElements() + { + return Stream.of(new IterableArray.Of<>(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, Double.NaN, 0.0, 1.0, 2.0, 3.0)); + } + + @Test + public void testTest_PositiveZero() + { + Distinct.OfDouble distinct = getDistinct(); + assertTrue(distinct.test(+0.0)); + assertFalse(distinct.test(+0.0)); + assertFalse(distinct.test(-0.0)); + } + + @Test + public void testTest_NegativeZero() + { + Distinct.OfDouble distinct = getDistinct(); + assertTrue(distinct.test(+0.0)); + assertFalse(distinct.test(-0.0)); + assertFalse(distinct.test(+0.0)); + } + } + + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfInt implements DistinctTest + { + @Override + public Distinct.OfInt getDistinct() + { + return new Distinct.OfInt(); + } + + @Override + public boolean test(Distinct.OfInt distinct, Integer element) + { + return distinct.test(element); + } + + @Override + public Stream> getElements() + { + return Stream.of(new IterableArray.Of<>(1, 2, 3)); + } + } + + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfLong implements DistinctTest + { + @Override + public Distinct.OfLong getDistinct() + { + return new Distinct.OfLong(); + } + + @Override + public boolean test(Distinct.OfLong distinct, Long element) + { + return distinct.test(element); + } + + @Override + public Stream> getElements() + { + return Stream.of(new IterableArray.Of<>(1L, 2L, 3L)); + } + } +} diff --git a/prism/unit-tests/common/iterable/EmptyIterableTest.java b/prism/unit-tests/common/iterable/EmptyIterableTest.java new file mode 100644 index 0000000000..af3489556d --- /dev/null +++ b/prism/unit-tests/common/iterable/EmptyIterableTest.java @@ -0,0 +1,342 @@ +package common.iterable; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.TestInstance; + +import java.util.function.Supplier; +import java.util.stream.Stream; + +interface EmptyIterableTest> extends FunctionalIterableTest +{ + @Override + default void testAllMatch(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + default void testAnyMatch(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + default void testDetect_Multiton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + default void testDetect_Singleton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + default void testFlatMapToNull(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + default void testNoneMatch(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + default void testIsEmpty_NonEmpty(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + default void testReduceBinaryOperatorOfE_Singleton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + default void testReduceBinaryOperatorOfE_Multiton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + default void testReduceBinary_ResultNull(Supplier supplier) + { /* empty reducibles hold no value */ } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class Of implements EmptyIterableTest>, FunctionalIterableTest.Of> + { + @Override + public EmptyIterable.Of getReducible(Object[] objects) + { + assert objects.length == 0 : "empty array expected"; + return EmptyIterable.of(); + } + + @Override + public Stream>> getDuplicatesReducibles() + { + return Stream.empty(); + } + + @Override + public Stream>> getSingletonReducibles() + { + return Stream.empty(); + } + + @Override + public Stream>> getMultitonReducibles() + { + return Stream.empty(); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfDouble implements EmptyIterableTest, FunctionalPrimitiveIterableTest.OfDouble + { + @Override + public EmptyIterable.OfDouble getReducible(double[] numbers) + { + assert numbers.length == 0 : "empty array expected"; + return EmptyIterable.ofDouble(); + } + + @Override + public Stream> getDuplicatesReducibles() + { + return Stream.empty(); + } + + @Override + public Stream> getSingletonReducibles() + { + return Stream.empty(); + } + + @Override + public Stream> getMultitonReducibles() + { + return Stream.empty(); + } + + @Override + public void testAllMatchDoublePredicate(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testAnyMatchDoublePredicate(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testDetectDoublePredicate_Multiton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testDetectDoublePredicate_Singleton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testFlatMapDoubleToNull(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testMax_Singleton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testMax_Multiton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testMin_Singleton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testMin_Multiton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testNoneMatchDoublePredicate(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testReduceDoubleBinaryOperator_Singleton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testReduceDoubleBinaryOperator_Multiton(Supplier supplier) + { /* empty reducibles hold no value */ } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfInt implements EmptyIterableTest, FunctionalPrimitiveIterableTest.OfInt + { + @Override + public EmptyIterable.OfInt getReducible(int[] numbers) + { + assert numbers.length == 0 : "empty array expected"; + return EmptyIterable.ofInt(); + } + + @Override + public Stream> getDuplicatesReducibles() + { + return Stream.empty(); + } + + @Override + public Stream> getSingletonReducibles() + { + return Stream.empty(); + } + + @Override + public Stream> getMultitonReducibles() + { + return Stream.empty(); + } + + @Override + public void testAllMatchIntPredicate(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testAnyMatchIntPredicate(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testDetectIntPredicate_Multiton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testDetectIntPredicate_Singleton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testFlatMapIntToNull(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testMax_Singleton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testMax_Multiton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testMin_Singleton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testMin_Multiton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testNoneMatchIntPredicate(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testReduceDoubleBinaryOperator_Singleton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testReduceDoubleBinaryOperator_Multiton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testReduceIntBinaryOperator_Singleton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testReduceIntBinaryOperator_Multiton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testReduceLongBinaryOperator_Singleton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testReduceLongBinaryOperator_Multiton(Supplier supplier) + { /* empty reducibles hold no value */ } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfLong implements EmptyIterableTest, FunctionalPrimitiveIterableTest.OfLong + { + @Override + public EmptyIterable.OfLong getReducible(long[] numbers) + { + assert numbers.length == 0 : "empty array expected"; + return EmptyIterable.ofLong(); + } + + @Override + public Stream> getDuplicatesReducibles() + { + return Stream.empty(); + } + + @Override + public Stream> getSingletonReducibles() + { + return Stream.empty(); + } + + @Override + public Stream> getMultitonReducibles() + { + return Stream.empty(); + } + + @Override + public void testAllMatchLongPredicate(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testAnyMatch(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testAnyMatchLongPredicate(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testDetectLongPredicate_Multiton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testDetectLongPredicate_Singleton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testFlatMapLongToNull(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testMax_Singleton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testMax_Multiton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testMin_Singleton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testMin_Multiton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testNoneMatchLongPredicate(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testReduceLongBinaryOperator_Singleton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testReduceLongBinaryOperator_Multiton(Supplier supplier) + { /* empty reducibles hold no value */ } + } +} \ No newline at end of file diff --git a/prism/unit-tests/common/iterable/EmptyIteratorTest.java b/prism/unit-tests/common/iterable/EmptyIteratorTest.java new file mode 100644 index 0000000000..0816bdfe1d --- /dev/null +++ b/prism/unit-tests/common/iterable/EmptyIteratorTest.java @@ -0,0 +1,342 @@ +package common.iterable; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.TestInstance; + +import java.util.function.Supplier; +import java.util.stream.Stream; + +interface EmptyIteratorTest> extends FunctionalIteratorTest +{ + @Override + default void testAllMatch(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + default void testAnyMatch(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + default void testDetect_Multiton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + default void testDetect_Singleton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + default void testFlatMapToNull(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + default void testNoneMatch(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + default void testIsEmpty_NonEmpty(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + default void testReduceBinaryOperatorOfE_Singleton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + default void testReduceBinaryOperatorOfE_Multiton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + default void testReduceBinary_ResultNull(Supplier supplier) + { /* empty reducibles hold no value */ } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class Of implements EmptyIteratorTest>, FunctionalIteratorTest.Of> + { + @Override + public EmptyIterator.Of getReducible(Object[] objects) + { + assert objects.length == 0 : "empty array expected"; + return EmptyIterator.of(); + } + + @Override + public Stream>> getDuplicatesReducibles() + { + return Stream.empty(); + } + + @Override + public Stream>> getSingletonReducibles() + { + return Stream.empty(); + } + + @Override + public Stream>> getMultitonReducibles() + { + return Stream.empty(); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfDouble implements EmptyIteratorTest, FunctionalPrimitiveIteratorTest.OfDouble + { + @Override + public EmptyIterator.OfDouble getReducible(double[] numbers) + { + assert numbers.length == 0 : "empty array expected"; + return EmptyIterator.ofDouble(); + } + + @Override + public Stream> getDuplicatesReducibles() + { + return Stream.empty(); + } + + @Override + public Stream> getSingletonReducibles() + { + return Stream.empty(); + } + + @Override + public Stream> getMultitonReducibles() + { + return Stream.empty(); + } + + @Override + public void testAllMatchDoublePredicate(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testAnyMatchDoublePredicate(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testDetectDoublePredicate_Multiton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testDetectDoublePredicate_Singleton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testFlatMapDoubleToNull(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testMax_Singleton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testMax_Multiton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testMin_Singleton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testMin_Multiton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testNoneMatchDoublePredicate(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testReduceDoubleBinaryOperator_Singleton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testReduceDoubleBinaryOperator_Multiton(Supplier supplier) + { /* empty reducibles hold no value */ } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfInt implements EmptyIteratorTest, FunctionalPrimitiveIteratorTest.OfInt + { + @Override + public EmptyIterator.OfInt getReducible(int[] numbers) + { + assert numbers.length == 0 : "empty array expected"; + return EmptyIterator.ofInt(); + } + + @Override + public Stream> getDuplicatesReducibles() + { + return Stream.empty(); + } + + @Override + public Stream> getSingletonReducibles() + { + return Stream.empty(); + } + + @Override + public Stream> getMultitonReducibles() + { + return Stream.empty(); + } + + @Override + public void testAllMatchIntPredicate(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testAnyMatchIntPredicate(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testDetectIntPredicate_Multiton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testDetectIntPredicate_Singleton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testFlatMapIntToNull(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testMax_Singleton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testMax_Multiton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testMin_Singleton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testMin_Multiton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testNoneMatchIntPredicate(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testReduceDoubleBinaryOperator_Singleton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testReduceDoubleBinaryOperator_Multiton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testReduceIntBinaryOperator_Singleton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testReduceIntBinaryOperator_Multiton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testReduceLongBinaryOperator_Singleton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testReduceLongBinaryOperator_Multiton(Supplier supplier) + { /* empty reducibles hold no value */ } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfLong implements EmptyIteratorTest, FunctionalPrimitiveIteratorTest.OfLong + { + @Override + public EmptyIterator.OfLong getReducible(long[] numbers) + { + assert numbers.length == 0 : "empty array expected"; + return EmptyIterator.ofLong(); + } + + @Override + public Stream> getDuplicatesReducibles() + { + return Stream.empty(); + } + + @Override + public Stream> getSingletonReducibles() + { + return Stream.empty(); + } + + @Override + public Stream> getMultitonReducibles() + { + return Stream.empty(); + } + + @Override + public void testAllMatchLongPredicate(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testAnyMatch(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testAnyMatchLongPredicate(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testDetectLongPredicate_Multiton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testDetectLongPredicate_Singleton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testFlatMapLongToNull(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testMax_Singleton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testMax_Multiton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testMin_Singleton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testMin_Multiton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testNoneMatchLongPredicate(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testReduceLongBinaryOperator_Singleton(Supplier supplier) + { /* empty reducibles hold no value */ } + + @Override + public void testReduceLongBinaryOperator_Multiton(Supplier supplier) + { /* empty reducibles hold no value */ } + } +} \ No newline at end of file diff --git a/prism/unit-tests/common/iterable/FilteringIterableTest.java b/prism/unit-tests/common/iterable/FilteringIterableTest.java new file mode 100644 index 0000000000..ca3711c58f --- /dev/null +++ b/prism/unit-tests/common/iterable/FilteringIterableTest.java @@ -0,0 +1,165 @@ +package common.iterable; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.ArrayList; +import java.util.Arrays; + +import static common.iterable.Assertions.assertIterableEquals; +import static common.iterable.PrimitiveIterable.*; +import static org.junit.jupiter.api.Assertions.assertIterableEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +interface FilteringIterableTest +{ + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class Of implements FilteringIterableTest, FunctionalIterableTest.Of> + { + @Override + public FilteringIterable.Of getReducible(Object[] objects) + { + return new FilteringIterable.Of<>(FunctionalIterable.of(objects), e -> true); + } + + @ParameterizedTest + @MethodSource("getArraysAsArguments") + void testOf(Object[] objects) + { + ArrayList expected = new ArrayList<>(); + int c = 0; + for (Object each : objects) { + if (c++ % 2 == 0) { + expected.add(each); + } + } + Iterable iterable = Arrays.asList(objects); + FunctionalIterable actual = new FilteringIterable.Of<>(iterable, expected::contains); + assertIterableEquals(expected, actual); + } + + @Test + public void testOf_Null() + { + EmptyIterable.Of iterable = EmptyIterable.of(); + assertThrows(NullPointerException.class, () -> new FilteringIterable.Of<>(null, e -> true)); + assertThrows(NullPointerException.class, () -> new FilteringIterable.Of<>(iterable, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfDouble implements FilteringIterableTest, FunctionalPrimitiveIterableTest.OfDouble + { + @Override + public FilteringIterable.OfDouble getReducible(double[] numbers) + { + return new FilteringIterable.OfDouble(FunctionalIterable.ofDouble(numbers), e -> true); + } + + @ParameterizedTest + @MethodSource("getArraysOfDouble") + public void testOfDouble(double[] numbers) + { + ArrayList expected = new ArrayList<>(); + int c = 0; + for (double d : numbers) { + if (c++ % 2 == 0) { + expected.add(d); + } + } + IterableArray.OfDouble iterable = new IterableArray.OfDouble(numbers); + FunctionalPrimitiveIterable.OfDouble actual = new FilteringIterable.OfDouble(iterable, expected::contains); + assertIterableEquals(unboxDouble(expected), actual); + } + + @Test + public void testOfDouble_Null() + { + EmptyIterable.OfDouble iterable = EmptyIterable.ofDouble(); + assertThrows(NullPointerException.class, () -> new FilteringIterable.OfDouble(null, e -> true)); + assertThrows(NullPointerException.class, () -> new FilteringIterable.OfDouble(iterable, null)); + } + } + + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfInt implements FilteringIterableTest, FunctionalPrimitiveIterableTest.OfInt + { + @Override + public FilteringIterable.OfInt getReducible(int[] numbers) + { + return new FilteringIterable.OfInt(FunctionalIterable.ofInt(numbers), e -> true); + } + + @ParameterizedTest + @MethodSource("getArraysOfInt") + public void testOfInt(int[] numbers) + { + ArrayList expected = new ArrayList<>(); + int c = 0; + for (int i : numbers) { + if (c++ % 2 == 0) { + expected.add(i); + } + } + IterableArray.OfInt iterable = new IterableArray.OfInt(numbers); + FunctionalPrimitiveIterable.OfInt actual = new FilteringIterable.OfInt(iterable, expected::contains); + assertIterableEquals(unboxInt(expected), actual); + } + + @Test + public void testOfInt_Null() + { + EmptyIterable.OfInt iterable = EmptyIterable.ofInt(); + assertThrows(NullPointerException.class, () -> new FilteringIterable.OfInt(null, e -> true)); + assertThrows(NullPointerException.class, () -> new FilteringIterable.OfInt(iterable, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfLong implements FilteringIterableTest, FunctionalPrimitiveIterableTest.OfLong + { + @Override + public FilteringIterable.OfLong getReducible(long[] numbers) + { + return new FilteringIterable.OfLong(FunctionalIterable.ofLong(numbers), e -> true); + } + + @ParameterizedTest + @MethodSource("getArraysOfLong") + public void testOfLong(long[] numbers) + { + ArrayList expected = new ArrayList<>(); + int c = 0; + for (Long i : numbers) { + if (c++ % 2 == 0) { + expected.add(i); + } + } + IterableArray.OfLong iterable = new IterableArray.OfLong(numbers); + FunctionalPrimitiveIterable.OfLong actual = new FilteringIterable.OfLong(iterable, expected::contains); + assertIterableEquals(unboxLong(expected), actual); + } + + @Test + public void testOfLong_Null() + { + EmptyIterable.OfLong iterable = EmptyIterable.ofLong(); + assertThrows(NullPointerException.class, () -> new FilteringIterable.OfLong(null, e -> true)); + assertThrows(NullPointerException.class, () -> new FilteringIterable.OfLong(iterable, null)); + } + } +} diff --git a/prism/unit-tests/common/iterable/FilteringIteratorTest.java b/prism/unit-tests/common/iterable/FilteringIteratorTest.java new file mode 100644 index 0000000000..004e9e32d0 --- /dev/null +++ b/prism/unit-tests/common/iterable/FilteringIteratorTest.java @@ -0,0 +1,165 @@ +package common.iterable; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; + +import static common.iterable.Assertions.assertIteratorEquals; +import static common.iterable.PrimitiveIterable.*; +import static org.junit.jupiter.api.Assertions.assertThrows; + +interface FilteringIteratorTest +{ + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class Of implements FilteringIteratorTest, FunctionalIteratorTest.Of> + { + @Override + public FilteringIterator.Of getReducible(Object[] objects) + { + return new FilteringIterator.Of<>(FunctionalIterator.of(objects), e -> true); + } + + @ParameterizedTest + @MethodSource("getArraysAsArguments") + void testOf(Object[] objects) + { + ArrayList expected = new ArrayList<>(); + int c = 0; + for (Object each : objects) { + if (c++ % 2 == 0) { + expected.add(each); + } + } + Iterator iterator = Arrays.asList(objects).iterator(); + FunctionalIterator actual = new FilteringIterator.Of<>(iterator, expected::contains); + assertIteratorEquals(expected.iterator(), actual); + } + + @Test + public void testOf_Null() + { + EmptyIterator.Of iterator = EmptyIterator.of(); + assertThrows(NullPointerException.class, () -> new FilteringIterator.Of<>(null, e -> true)); + assertThrows(NullPointerException.class, () -> new FilteringIterator.Of<>(iterator, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfDouble implements FilteringIteratorTest, FunctionalPrimitiveIteratorTest.OfDouble + { + @Override + public FilteringIterator.OfDouble getReducible(double[] numbers) + { + return new FilteringIterator.OfDouble(FunctionalIterator.ofDouble(numbers), e -> true); + } + + @ParameterizedTest + @MethodSource("getArraysOfDouble") + public void testOfDouble(double[] numbers) + { + ArrayList expected = new ArrayList<>(); + int c = 0; + for (double d : numbers) { + if (c++ % 2 == 0) { + expected.add(d); + } + } + ArrayIterator.OfDouble iterator = new ArrayIterator.OfDouble(numbers); + FunctionalPrimitiveIterator.OfDouble actual = new FilteringIterator.OfDouble(iterator, expected::contains); + assertIteratorEquals(unboxDouble(expected.iterator()), actual); + } + + @Test + public void testOfDouble_Null() + { + EmptyIterator.OfDouble iterator = EmptyIterator.ofDouble(); + assertThrows(NullPointerException.class, () -> new FilteringIterator.OfDouble(null, e -> true)); + assertThrows(NullPointerException.class, () -> new FilteringIterator.OfDouble(iterator, null)); + } + } + + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfInt implements FilteringIteratorTest, FunctionalPrimitiveIteratorTest.OfInt + { + @Override + public FilteringIterator.OfInt getReducible(int[] numbers) + { + return new FilteringIterator.OfInt(FunctionalIterator.ofInt(numbers), e -> true); + } + + @ParameterizedTest + @MethodSource("getArraysOfInt") + public void testOfInt(int[] numbers) + { + ArrayList expected = new ArrayList<>(); + int c = 0; + for (int i : numbers) { + if (c++ % 2 == 0) { + expected.add(i); + } + } + ArrayIterator.OfInt iterator = new ArrayIterator.OfInt(numbers); + FunctionalPrimitiveIterator.OfInt actual = new FilteringIterator.OfInt(iterator, expected::contains); + assertIteratorEquals(unboxInt(expected.iterator()), actual); + } + + @Test + public void testOfInt_Null() + { + EmptyIterator.OfInt iterator = EmptyIterator.ofInt(); + assertThrows(NullPointerException.class, () -> new FilteringIterator.OfInt(null, e -> true)); + assertThrows(NullPointerException.class, () -> new FilteringIterator.OfInt(iterator, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfLong implements FilteringIteratorTest, FunctionalPrimitiveIteratorTest.OfLong + { + @Override + public FilteringIterator.OfLong getReducible(long[] numbers) + { + return new FilteringIterator.OfLong(FunctionalIterator.ofLong(numbers), e -> true); + } + + @ParameterizedTest + @MethodSource("getArraysOfLong") + public void testOfLong(long[] numbers) + { + ArrayList expected = new ArrayList<>(); + int c = 0; + for (Long i : numbers) { + if (c++ % 2 == 0) { + expected.add(i); + } + } + ArrayIterator.OfLong iterator = new ArrayIterator.OfLong(numbers); + FunctionalPrimitiveIterator.OfLong actual = new FilteringIterator.OfLong(iterator, expected::contains); + assertIteratorEquals(unboxLong(expected.iterator()), actual); + } + + @Test + public void testOfLong_Null() + { + EmptyIterator.OfLong iterator = EmptyIterator.ofLong(); + assertThrows(NullPointerException.class, () -> new FilteringIterator.OfLong(null, e -> true)); + assertThrows(NullPointerException.class, () -> new FilteringIterator.OfLong(iterator, null)); + } + } +} diff --git a/prism/unit-tests/common/iterable/FunctionalIterableStaticTest.java b/prism/unit-tests/common/iterable/FunctionalIterableStaticTest.java new file mode 100644 index 0000000000..7bbe8fb2b2 --- /dev/null +++ b/prism/unit-tests/common/iterable/FunctionalIterableStaticTest.java @@ -0,0 +1,140 @@ +package common.iterable; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.*; +import java.util.stream.Stream; + +import static common.iterable.Assertions.assertIterableEquals; +import static org.junit.jupiter.api.Assertions.assertIterableEquals; +import static org.junit.jupiter.api.Assertions.*; + +class FunctionalIterableStaticTest +{ + static Stream> getIterables() + { + return Stream.of(Collections.singleton(null), + Collections.emptyList(), + Collections.singleton("one"), + Arrays.asList("one", "two", "three")); + } + + static Stream> getIterablesDouble() + { + return Stream.of(Collections.emptyList(), + Collections.singleton(1.0), + Arrays.asList(1.0, 2.0, 3.0)); + } + + static Stream> getIterablesInt() + { + return Stream.of(Collections.emptyList(), + Collections.singleton(1), + Arrays.asList(1, 2, 3)); + } + + static Stream> getIterablesLong() + { + return Stream.of(Collections.emptyList(), + Collections.singleton(1L), + Arrays.asList(1L, 2L, 3L)); + } + + @ParameterizedTest + @MethodSource("getIterables") + void testOf(Iterable iterable) + { + FunctionalIterable expected = Reducible.extend(iterable); + Object[] arguments = new Object[Math.toIntExact(expected.count())]; + expected.collect(arguments); + FunctionalIterable actual = FunctionalIterable.of(arguments); + assertIterableEquals(expected, actual); + } + + @Test + void testOfTypes() + { + assertTrue(FunctionalIterable.of() instanceof EmptyIterable.Of); + assertTrue(FunctionalIterable.of("first") instanceof SingletonIterable.Of); + } + + @Test + void testOf_Null() + { + assertThrows(NullPointerException.class, () -> FunctionalIterable.of((Object[]) null)); + } + + @ParameterizedTest + @MethodSource("getIterablesDouble") + void testOfDouble(Iterable iterable) + { + FunctionalPrimitiveIterable.OfDouble expected = Reducible.unboxDouble(iterable); + double[] arguments = new double[Math.toIntExact(expected.count())]; + expected.collect(arguments); + FunctionalPrimitiveIterable.OfDouble actual = FunctionalIterable.ofDouble(arguments); + assertIterableEquals(expected, actual); + } + + @Test + static void testOfDoubleTypes() + { + assertTrue(FunctionalIterable.ofDouble() instanceof EmptyIterable.OfDouble); + assertTrue(FunctionalIterable.ofDouble(1.0) instanceof SingletonIterable.Of); + } + + @Test + void testOfDouble_Null() + { + assertThrows(NullPointerException.class, () -> FunctionalIterable.ofDouble((double[]) null)); + } + + @ParameterizedTest + @MethodSource("getIterablesInt") + void testOfInt(Iterable iterable) + { + FunctionalPrimitiveIterable.OfInt expected = Reducible.unboxInt(iterable); + int[] arguments = new int[Math.toIntExact(expected.count())]; + expected.collect(arguments); + FunctionalPrimitiveIterable.OfInt actual = FunctionalIterable.ofInt(arguments); + assertIterableEquals(expected, actual); + } + + @Test + void testOfIntTypes() + { + assertTrue(FunctionalIterable.ofInt() instanceof EmptyIterable.OfInt); + assertTrue(FunctionalIterable.ofInt(1) instanceof SingletonIterable.OfInt); + } + + @Test + void testOfInt_Null() + { + assertThrows(NullPointerException.class, () -> FunctionalIterable.ofInt((int[])null)); + } + + @ParameterizedTest + @MethodSource("getIterablesLong") + void testOfLong(Iterable iterable) + { + FunctionalPrimitiveIterable.OfLong expected = Reducible.unboxLong(iterable); + long[] arguments = new long[Math.toIntExact(expected.count())]; + expected.collect(arguments); + FunctionalPrimitiveIterable.OfLong actual = FunctionalIterable.ofLong(arguments); + assertIterableEquals(expected, actual); + } + + @Test + void testOfLongTypes() + { + assertTrue(FunctionalIterable.ofLong() instanceof EmptyIterable.OfLong); + assertTrue(FunctionalIterable.ofLong(1L) instanceof SingletonIterable.OfLong); + } + + @Test + void testOfLong_Null() + { + assertThrows(NullPointerException.class, () -> FunctionalIterable.ofLong((long[]) null)); + } +} diff --git a/prism/unit-tests/common/iterable/FunctionalIterableTest.java b/prism/unit-tests/common/iterable/FunctionalIterableTest.java new file mode 100644 index 0000000000..6d6caeb775 --- /dev/null +++ b/prism/unit-tests/common/iterable/FunctionalIterableTest.java @@ -0,0 +1,112 @@ +package common.iterable; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.*; +import java.util.function.Supplier; + +import static common.iterable.PrimitiveIterable.*; +import static org.junit.jupiter.api.Assertions.assertIterableEquals; +import static org.junit.jupiter.api.Assertions.*; + +public interface FunctionalIterableTest> extends ReducibleTest +{ + @ParameterizedTest + @MethodSource({"getReducibles"}) + @Override + default void testConcat(Supplier supplier) + { + ArrayList expected = supplier.get().collect(new ArrayList<>()); + supplier.get().collect(expected); + FunctionalIterable actual = supplier.get().concat(supplier.get()); + assertIterableEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + @Override + default void testFlatMap(Supplier supplier) + { + FunctionalIterable expected = supplier.get().map(String::valueOf); + FunctionalIterable actual = supplier.get().flatMap(e -> new SingletonIterable.Of<>(String.valueOf(e))); + assertIterableEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + @Override + default void testFlatMapToDouble(Supplier supplier) + { + Range range = new Range((int) supplier.get().count()); + PrimitiveIterable.OfDouble expected = unboxDouble(range.map((int i) -> (double) i)); + Range.RangeIterator index = range.iterator(); + PrimitiveIterable.OfDouble actual = supplier.get().flatMapToDouble(e -> new SingletonIterable.OfDouble(index.next())); + assertIterableEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + @Override + default void testFlatMapToInt(Supplier supplier) + { + Range expected = new Range((int) supplier.get().count()); + Range.RangeIterator index = expected.iterator(); + PrimitiveIterable.OfInt actual = supplier.get().flatMapToInt(e -> new SingletonIterable.OfInt(index.next())); + assertIterableEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + @Override + default void testFlatMapToLong(Supplier supplier) + { + Range range = new Range((int) supplier.get().count()); + PrimitiveIterable.OfLong expected = unboxLong(range.map((int i) -> (long) i)); + Range.RangeIterator index = range.iterator(); + PrimitiveIterable.OfLong actual = supplier.get().flatMapToLong(e -> new SingletonIterable.OfLong(index.next())); + assertIterableEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getSingletonReducibles") + @Override + default void testFlatMapToNull(Supplier supplier) + { + assertThrows(NullPointerException.class, () -> supplier.get().flatMap(e -> null).consume()); + assertThrows(NullPointerException.class, () -> supplier.get().flatMapToDouble(e -> null).consume()); + assertThrows(NullPointerException.class, () -> supplier.get().flatMapToInt(e -> null).consume()); + assertThrows(NullPointerException.class, () -> supplier.get().flatMapToLong(e -> null).consume()); + } + + @Test + @Override + default void testFlatMap_Null() + { + FunctionalIterable iterator = getAnyReducible(); + assertThrows(NullPointerException.class, () -> iterator.flatMap(null)); + assertThrows(NullPointerException.class, () -> iterator.flatMapToDouble(null)); + assertThrows(NullPointerException.class, () -> iterator.flatMapToInt(null)); + assertThrows(NullPointerException.class, () -> iterator.flatMapToLong(null)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + @DisplayName("forEach yields same sequence as the underlying iterator.") + @Override + default void testForEach(Supplier supplier) + { + T expected = supplier.get(); + List actual = new ArrayList<>(); + supplier.get().forEach(actual::add); + assertIterableEquals(expected, actual); + } + + + + interface Of> extends FunctionalIterableTest, ReducibleTest.Of + { + } +} diff --git a/prism/unit-tests/common/iterable/FunctionalIteratorStaticTest.java b/prism/unit-tests/common/iterable/FunctionalIteratorStaticTest.java new file mode 100644 index 0000000000..78f9a33da8 --- /dev/null +++ b/prism/unit-tests/common/iterable/FunctionalIteratorStaticTest.java @@ -0,0 +1,139 @@ +package common.iterable; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.*; +import java.util.stream.Stream; + +import static common.iterable.Assertions.assertIteratorEquals; +import static org.junit.jupiter.api.Assertions.*; + +class FunctionalIteratorStaticTest +{ + static Stream> getIterables() + { + return Stream.of(Collections.singleton(null), + Collections.emptyList(), + Collections.singleton("one"), + Arrays.asList("one", "two", "three")); + } + + static Stream> getIterablesDouble() + { + return Stream.of(Collections.emptyList(), + Collections.singleton(1.0), + Arrays.asList(1.0, 2.0, 3.0)); + } + + static Stream> getIterablesInt() + { + return Stream.of(Collections.emptyList(), + Collections.singleton(1), + Arrays.asList(1, 2, 3)); + } + + static Stream> getIterablesLong() + { + return Stream.of(Collections.emptyList(), + Collections.singleton(1L), + Arrays.asList(1L, 2L, 3L)); + } + + @ParameterizedTest + @MethodSource("getIterables") + void testOf(Iterable iterable) + { + FunctionalIterable expected = Reducible.extend(iterable); + Object[] arguments = new Object[Math.toIntExact(expected.count())]; + expected.collect(arguments); + FunctionalIterator actual = FunctionalIterator.of(arguments); + assertIteratorEquals(expected.iterator(), actual); + } + + @Test + void testOfTypes() + { + assertTrue(FunctionalIterator.of() instanceof EmptyIterator.Of); + assertTrue(FunctionalIterator.of("first") instanceof SingletonIterator.Of); + } + + @Test + void testOf_Null() + { + assertThrows(NullPointerException.class, () -> FunctionalIterator.of((Object[]) null)); + } + + @ParameterizedTest + @MethodSource("getIterablesDouble") + void testOfDouble(Iterable iterable) + { + FunctionalPrimitiveIterable.OfDouble expected = Reducible.unboxDouble(iterable); + double[] arguments = new double[Math.toIntExact(expected.count())]; + expected.collect(arguments); + FunctionalPrimitiveIterator.OfDouble actual = FunctionalIterator.ofDouble(arguments); + assertIteratorEquals(expected.iterator(), actual); + } + + @Test + static void testOfDoubleTypes() + { + assertTrue(FunctionalIterator.ofDouble() instanceof EmptyIterator.OfDouble); + assertTrue(FunctionalIterator.ofDouble(1.0) instanceof SingletonIterator.Of); + } + + @Test + void testOfDouble_Null() + { + assertThrows(NullPointerException.class, () -> FunctionalIterator.ofDouble((double[]) null)); + } + + @ParameterizedTest + @MethodSource("getIterablesInt") + void testOfInt(Iterable iterable) + { + FunctionalPrimitiveIterable.OfInt expected = Reducible.unboxInt(iterable); + int[] arguments = new int[Math.toIntExact(expected.count())]; + expected.collect(arguments); + FunctionalPrimitiveIterator.OfInt actual = FunctionalIterator.ofInt(arguments); + assertIteratorEquals(expected.iterator(), actual); + } + + @Test + void testOfIntTypes() + { + assertTrue(FunctionalIterator.ofInt() instanceof EmptyIterator.OfInt); + assertTrue(FunctionalIterator.ofInt(1) instanceof SingletonIterator.OfInt); + } + + @Test + void testOfInt_Null() + { + assertThrows(NullPointerException.class, () -> FunctionalIterator.ofInt((int[]) null)); + } + + @ParameterizedTest + @MethodSource("getIterablesLong") + void testOfLong(Iterable iterable) + { + FunctionalPrimitiveIterable.OfLong expected = Reducible.unboxLong(iterable); + long[] arguments = new long[Math.toIntExact(expected.count())]; + expected.collect(arguments); + FunctionalPrimitiveIterator.OfLong actual = FunctionalIterator.ofLong(arguments); + assertIteratorEquals(expected.iterator(), actual); + } + + @Test + void testOfLongTypes() + { + assertTrue(FunctionalIterator.ofLong() instanceof EmptyIterator.OfLong); + assertTrue(FunctionalIterator.ofLong(1L) instanceof SingletonIterator.OfLong); + } + + @Test + void testOfLong_Null() + { + assertThrows(NullPointerException.class, () -> FunctionalIterator.ofLong((long[]) null)); + } +} diff --git a/prism/unit-tests/common/iterable/FunctionalIteratorTest.java b/prism/unit-tests/common/iterable/FunctionalIteratorTest.java new file mode 100644 index 0000000000..f1b2e47666 --- /dev/null +++ b/prism/unit-tests/common/iterable/FunctionalIteratorTest.java @@ -0,0 +1,193 @@ +package common.iterable; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.*; +import java.util.function.Supplier; + +import static common.iterable.Assertions.assertIteratorEquals; +import static common.iterable.PrimitiveIterable.*; +import static org.junit.jupiter.api.Assertions.*; + +public interface FunctionalIteratorTest> extends ReducibleTest +{ + /** + * Collect elements from an iterator without using method from Reducible. + * + * @param supplier the supplier yielding the iterator + * @return a {@link List} of the iterator elements + */ + default List collectElements(Supplier supplier) + { + ArrayList elements = new ArrayList<>(); + for (Iterator iterator = supplier.get(); iterator.hasNext();) { + elements.add(iterator.next()); + } + return elements; + } + + @ParameterizedTest + @MethodSource("getReducibles") + @DisplayName("release() empties the iterator.") + default void testRelease(Supplier supplier) + { + FunctionalIterator iterator = supplier.get(); + iterator.release(); + assertFalse(iterator.hasNext(), "Expected no next element after release()"); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testUnwrap(Supplier supplier) + { + FunctionalIterator iterator = supplier.get(); + assertIteratorEquals(supplier.get(), iterator.unwrap()); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testRequireNext(Supplier supplier) + { + FunctionalIterator iterator = supplier.get().consume(); + assertThrows(NoSuchElementException.class, iterator::requireNext); + } + + @ParameterizedTest + @MethodSource("getReducibles") + @Override + default void testConsume(Supplier supplier) + { + ReducibleTest.super.testConsume(supplier); + // Just test that the iterator is empty after calling #consume. + // There is no way to test whether consume does anything beyond this. + FunctionalIterator iterator = supplier.get().consume(); + assertTrue(iterator.isEmpty(), "Expected empty iterator after consume()"); + assertFalse(iterator.hasNext(), "Expected no next element after consume()"); + } + + @ParameterizedTest + @MethodSource({"getReducibles"}) + @Override + default void testConcat(Supplier supplier) + { + ArrayList expected = supplier.get().collect(new ArrayList<>()); + supplier.get().collect(expected); + FunctionalIterator actual = supplier.get().concat(supplier.get()); + assertIteratorEquals(expected.iterator(), actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + @Override + default void testFlatMap(Supplier supplier) + { + FunctionalIterator expected = supplier.get().map(String::valueOf); + FunctionalIterator actual = supplier.get().flatMap(e -> new SingletonIterator.Of<>(String.valueOf(e))); + assertIteratorEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + @Override + default void testFlatMapToDouble(Supplier supplier) + { + Range range = new Range((int) supplier.get().count()); + PrimitiveIterator.OfDouble expected = unboxDouble(range.iterator().map((int i) -> (double) i)); + Range.RangeIterator index = range.iterator(); + PrimitiveIterator.OfDouble actual = supplier.get().flatMapToDouble(e -> new SingletonIterator.OfDouble(index.next())); + assertIteratorEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + @Override + default void testFlatMapToInt(Supplier supplier) + { + Range range = new Range((int) supplier.get().count()); + PrimitiveIterator.OfInt expected = range.iterator(); + Range.RangeIterator index = range.iterator(); + PrimitiveIterator.OfInt actual = supplier.get().flatMapToInt(e -> new SingletonIterator.OfInt(index.next())); + assertIteratorEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + @Override + default void testFlatMapToLong(Supplier supplier) + { + Range range = new Range((int) supplier.get().count()); + PrimitiveIterator.OfLong expected = unboxLong(range.iterator().map((int i) -> (long) i)); + Range.RangeIterator index = range.iterator(); + PrimitiveIterator.OfLong actual = supplier.get().flatMapToLong(e -> new SingletonIterator.OfLong(index.next())); + assertIteratorEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getSingletonReducibles") + @Override + default void testFlatMapToNull(Supplier supplier) + { + assertThrows(NullPointerException.class, () -> supplier.get().flatMap(e -> null).consume()); + assertThrows(NullPointerException.class, () -> supplier.get().flatMapToDouble(e -> null).consume()); + assertThrows(NullPointerException.class, () -> supplier.get().flatMapToInt(e -> null).consume()); + assertThrows(NullPointerException.class, () -> supplier.get().flatMapToLong(e -> null).consume()); + } + + @Test + @Override + default void testFlatMap_Null() + { + FunctionalIterator iterator = getAnyReducible(); + assertThrows(NullPointerException.class, () -> iterator.flatMap(null)); + assertThrows(NullPointerException.class, () -> iterator.flatMapToDouble(null)); + assertThrows(NullPointerException.class, () -> iterator.flatMapToInt(null)); + assertThrows(NullPointerException.class, () -> iterator.flatMapToLong(null)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + @DisplayName("forEach yields same sequence as the underlying iterator.") + @Override + default void testForEach(Supplier supplier) + { + List expected = collectElements(supplier); + List actual = new ArrayList<>(); + supplier.get().forEach(actual::add); + assertIterableEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + @DisplayName("forEachRemaining() yields same sequence as the underlying iterator.") + default void testForEachRemaining(Supplier supplier) + { + List expected = collectElements(supplier); + List actual = new ArrayList<>(); + supplier.get().forEachRemaining(actual::add); + assertIterableEquals(expected, actual); + } + + @Test + default void testForEachRemaining_Null() + { + FunctionalIterator iterator = getAnyReducible(); + assertThrows(NullPointerException.class, () -> iterator.forEachRemaining(null)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testIsEmpty(Supplier supplier) + { + T iterator = supplier.get(); + assertTrue(iterator.isEmpty() ^ iterator.hasNext()); + } + + + + interface Of> extends FunctionalIteratorTest, ReducibleTest.Of + { + } +} diff --git a/prism/unit-tests/common/iterable/FunctionalPrimitiveIterableTest.java b/prism/unit-tests/common/iterable/FunctionalPrimitiveIterableTest.java new file mode 100644 index 0000000000..a95d63b3aa --- /dev/null +++ b/prism/unit-tests/common/iterable/FunctionalPrimitiveIterableTest.java @@ -0,0 +1,282 @@ +package common.iterable; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.*; +import java.util.function.*; + +import static common.iterable.Assertions.assertIterableEquals; +import static common.iterable.PrimitiveIterable.*; +import static org.junit.jupiter.api.Assertions.assertIterableEquals; +import static org.junit.jupiter.api.Assertions.*; + +public interface FunctionalPrimitiveIterableTest +{ + interface OfDouble extends FunctionalIterableTest, PrimitiveReducibleTest.OfDouble + { + @ParameterizedTest + @MethodSource("getReducibles") + default void testFlatMapDoubleToObj(Supplier supplier) + { + FunctionalIterable expected = supplier.get().map((DoubleFunction) String::valueOf); + Iterable actual = supplier.get().flatMap((double d) -> List.of(String.valueOf(d))); + assertIterableEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testFlatMapDoubleToDouble(Supplier supplier) + { + Range range = new Range((int) supplier.get().count()); + PrimitiveIterable.OfDouble expected = range.mapToDouble((int i) -> (double) i); + Range.RangeIterator index = range.iterator(); + PrimitiveIterable.OfDouble actual = supplier.get().flatMapToDouble((double d) -> new SingletonIterable.OfDouble(index.next())); + assertIterableEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testFlatMapDoubleToInt(Supplier supplier) + { + Range expected = new Range((int) supplier.get().count()); + Range.RangeIterator index = expected.iterator(); + PrimitiveIterable.OfInt actual = supplier.get().flatMapToInt((double d) -> new SingletonIterable.OfInt(index.next())); + assertIterableEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testFlatMapDoubleToLong(Supplier supplier) + { + Range range = new Range((int) supplier.get().count()); + PrimitiveIterable.OfLong expected = range.mapToLong((int i) -> (long) i); + Range.RangeIterator index = range.iterator(); + PrimitiveIterable.OfLong actual = supplier.get().flatMapToLong((double d) -> new SingletonIterable.OfLong(index.next())); + assertIterableEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getSingletonReducibles") + default void testFlatMapDoubleToNull(Supplier supplier) + { + assertThrows(NullPointerException.class, () -> supplier.get().flatMap((double d) -> null).consume()); + assertThrows(NullPointerException.class, () -> supplier.get().flatMapToDouble((double d) -> null).consume()); + assertThrows(NullPointerException.class, () -> supplier.get().flatMapToInt((double d) -> null).consume()); + assertThrows(NullPointerException.class, () -> supplier.get().flatMapToLong((double d) -> null).consume()); + } + + @Test + default void testFlatMapOfDouble_Null() + { + T iterator = getAnyReducible(); + assertThrows(NullPointerException.class, () -> iterator.flatMap((DoubleFunction>) null)); + assertThrows(NullPointerException.class, () -> iterator.flatMapToDouble((DoubleFunction) null)); + assertThrows(NullPointerException.class, () -> iterator.flatMapToInt((DoubleFunction) null)); + assertThrows(NullPointerException.class, () -> iterator.flatMapToLong((DoubleFunction) null)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + @DisplayName("forEach() yields same sequence as the underlying iterator.") + @Override + default void testForEachDoubleConsumer(Supplier supplier) + { + T expected = supplier.get(); + List actual = new ArrayList<>(); + supplier.get().forEach((DoubleConsumer) actual::add); + assertIterableEquals(unboxDouble(expected), unboxDouble(actual)); + } + + @Test + default void testConcatTypes() + { + // primitive with boxed signature + FunctionalIterable primitive = getAnyReducible(); + assertTrue(getAnyReducible().concat(primitive) instanceof FunctionalPrimitiveIterable.OfDouble); + // boxed + FunctionalIterable boxed = getAnyReducible().map((DoubleFunction) Double::valueOf); + assertFalse(getAnyReducible().concat(boxed) instanceof FunctionalPrimitiveIterable.OfDouble); + } + } + + + + interface OfInt extends FunctionalIterableTest, PrimitiveReducibleTest.OfInt + { + @ParameterizedTest + @MethodSource("getReducibles") + default void testFlatMapIntToObj(Supplier supplier) + { + FunctionalIterable expected = supplier.get().map((IntFunction) String::valueOf); + FunctionalIterable actual = supplier.get().flatMap((int i) -> List.of(String.valueOf(i))); + assertIterableEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testFlatMapIntToDouble(Supplier supplier) + { + Range range = new Range((int) supplier.get().count()); + PrimitiveIterable.OfDouble expected = range.mapToDouble((int i) -> (double) i); + Range.RangeIterator index = range.iterator(); + PrimitiveIterable.OfDouble actual = supplier.get().flatMapToDouble((int i) -> new SingletonIterable.OfDouble(index.next())); + assertIterableEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testFlatMapIntToInt(Supplier supplier) + { + Range expected = new Range((int) supplier.get().count()); + Range.RangeIterator index = expected.iterator(); + PrimitiveIterable.OfInt actual = supplier.get().flatMapToInt((int i) -> new SingletonIterable.OfInt(index.next())); + assertIterableEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testFlatMapIntToLong(Supplier supplier) + { + Range range = new Range((int) supplier.get().count()); + PrimitiveIterable.OfLong expected = range.mapToLong((int i) -> (long) i); + Range.RangeIterator index = range.iterator(); + PrimitiveIterable.OfLong actual = supplier.get().flatMapToLong((int i) -> new SingletonIterable.OfLong(index.next())); + assertIterableEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getSingletonReducibles") + default void testFlatMapIntToNull(Supplier supplier) + { + assertThrows(NullPointerException.class, () -> supplier.get().flatMap((int i) -> null).consume()); + assertThrows(NullPointerException.class, () -> supplier.get().flatMapToDouble((int i) -> null).consume()); + assertThrows(NullPointerException.class, () -> supplier.get().flatMapToInt((int i) -> null).consume()); + assertThrows(NullPointerException.class, () -> supplier.get().flatMapToLong((int i) -> null).consume()); + } + + @Test + default void testFlatMapOfInt_Null() + { + T iterator = getAnyReducible(); + assertThrows(NullPointerException.class, () -> iterator.flatMap((IntFunction>) null)); + assertThrows(NullPointerException.class, () -> iterator.flatMapToDouble((IntFunction) null)); + assertThrows(NullPointerException.class, () -> iterator.flatMapToInt((IntFunction) null)); + assertThrows(NullPointerException.class, () -> iterator.flatMapToLong((IntFunction) null)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + @DisplayName("forEach() yields same sequence as the underlying iterator.") + @Override + default void testForEachIntConsumer(Supplier supplier) + { + T expected = supplier.get(); + List actual = new ArrayList<>(); + supplier.get().forEach((IntConsumer) actual::add); + assertIterableEquals(unboxInt(expected), unboxInt(actual)); + } + + @Test + default void testConcatTypes() + { + // primitive with boxed signature + FunctionalIterable primitive = getAnyReducible(); + assertTrue(getAnyReducible().concat(primitive) instanceof FunctionalPrimitiveIterable.OfInt); + // boxed + FunctionalIterable boxed = getAnyReducible().map((IntFunction) Integer::valueOf); + assertFalse(getAnyReducible().concat(boxed) instanceof FunctionalPrimitiveIterable.OfInt); + } + } + + + + interface OfLong extends FunctionalIterableTest, PrimitiveReducibleTest.OfLong + { + @ParameterizedTest + @MethodSource("getReducibles") + default void testFlatMapLongToObj(Supplier supplier) + { + FunctionalIterable expected = supplier.get().map((LongFunction) String::valueOf); + FunctionalIterable actual = supplier.get().flatMap((long l) -> List.of(String.valueOf(l))); + assertIterableEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testFlatMapLongToDouble(Supplier supplier) + { + Range range = new Range((int) supplier.get().count()); + PrimitiveIterable.OfDouble expected = range.mapToDouble((int i) -> (double) i); + Range.RangeIterator index = range.iterator(); + PrimitiveIterable.OfDouble actual = supplier.get().flatMapToDouble((long l) -> new SingletonIterable.OfDouble(index.next())); + assertIterableEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testFlatMapLongToInt(Supplier supplier) + { + Range expected = new Range((int) supplier.get().count()); + Range.RangeIterator index = expected.iterator(); + PrimitiveIterable.OfInt actual = supplier.get().flatMapToInt((long l) -> new SingletonIterable.OfInt(index.next())); + assertIterableEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testFlatMapLongToLong(Supplier supplier) + { + Range range = new Range((int) supplier.get().count()); + PrimitiveIterable.OfLong expected = range.mapToLong((int i) -> (long) i); + Range.RangeIterator index = range.iterator(); + PrimitiveIterable.OfLong actual = supplier.get().flatMapToLong((long l) -> new SingletonIterable.OfLong(index.next())); + assertIterableEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getSingletonReducibles") + default void testFlatMapLongToNull(Supplier supplier) + { + assertThrows(NullPointerException.class, () -> supplier.get().flatMap((long l) -> null).consume()); + assertThrows(NullPointerException.class, () -> supplier.get().flatMapToDouble((long l) -> null).consume()); + assertThrows(NullPointerException.class, () -> supplier.get().flatMapToInt((long l) -> null).consume()); + assertThrows(NullPointerException.class, () -> supplier.get().flatMapToLong((long l) -> null).consume()); + } + + @Test + default void testFlatMapOfLong_Null() + { + T iterator = getAnyReducible(); + assertThrows(NullPointerException.class, () -> iterator.flatMap((LongFunction>) null)); + assertThrows(NullPointerException.class, () -> iterator.flatMapToDouble((LongFunction) null)); + assertThrows(NullPointerException.class, () -> iterator.flatMapToInt((LongFunction) null)); + assertThrows(NullPointerException.class, () -> iterator.flatMapToLong((LongFunction) null)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + @DisplayName("forEach() yields same sequence as the underlying iterator.") + @Override + default void testForEachLongConsumer(Supplier supplier) + { + T expected = supplier.get(); + List actual = new ArrayList<>(); + supplier.get().forEach((LongConsumer) actual::add); + assertIterableEquals(unboxLong(expected), unboxLong(actual)); + } + + @Test + default void testConcatTypes() + { + // primitive with boxed signature + FunctionalIterable primitive = getAnyReducible(); + assertTrue(getAnyReducible().concat(primitive) instanceof FunctionalPrimitiveIterable.OfLong); + // boxed + FunctionalIterable boxed = getAnyReducible().map((LongFunction) Long::valueOf); + assertFalse(getAnyReducible().concat(boxed) instanceof FunctionalPrimitiveIterable.OfLong); + } + } +} diff --git a/prism/unit-tests/common/iterable/FunctionalPrimitiveIteratorTest.java b/prism/unit-tests/common/iterable/FunctionalPrimitiveIteratorTest.java new file mode 100644 index 0000000000..eba93c3571 --- /dev/null +++ b/prism/unit-tests/common/iterable/FunctionalPrimitiveIteratorTest.java @@ -0,0 +1,405 @@ +package common.iterable; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.*; +import java.util.function.*; + +import static common.iterable.Assertions.assertIterableEquals; +import static common.iterable.Assertions.*; +import static common.iterable.PrimitiveIterable.*; +import static org.junit.jupiter.api.Assertions.*; + +public interface FunctionalPrimitiveIteratorTest +{ + interface OfDouble extends FunctionalIteratorTest, PrimitiveReducibleTest.OfDouble + { + @ParameterizedTest + @MethodSource("getReducibles") + default void testFlatMapDoubleToObj(Supplier supplier) + { + FunctionalIterator expected = supplier.get().map((DoubleFunction) String::valueOf); + Iterator actual = supplier.get().flatMap((double d) -> List.of(String.valueOf(d)).iterator()); + assertIteratorEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testFlatMapDoubleToDouble(Supplier supplier) + { + Range range = new Range((int) supplier.get().count()); + PrimitiveIterator.OfDouble expected = range.iterator().mapToDouble((int i) -> (double) i); + Range.RangeIterator index = range.iterator(); + PrimitiveIterator.OfDouble actual = supplier.get().flatMapToDouble((double d) -> new SingletonIterator.OfDouble(index.next())); + assertIteratorEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testFlatMapDoubleToInt(Supplier supplier) + { + Range range = new Range((int) supplier.get().count()); + PrimitiveIterator.OfInt expected = range.iterator(); + Range.RangeIterator index = range.iterator(); + PrimitiveIterator.OfInt actual = supplier.get().flatMapToInt((double d) -> new SingletonIterator.OfInt(index.next())); + assertIteratorEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testFlatMapDoubleToLong(Supplier supplier) + { + Range range = new Range((int) supplier.get().count()); + PrimitiveIterator.OfLong expected = range.iterator().mapToLong((int i) -> (long) i); + Range.RangeIterator index = range.iterator(); + PrimitiveIterator.OfLong actual = supplier.get().flatMapToLong((double d) -> new SingletonIterator.OfLong(index.next())); + assertIteratorEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getSingletonReducibles") + default void testFlatMapDoubleToNull(Supplier supplier) + { + assertThrows(NullPointerException.class, () -> supplier.get().flatMap((double d) -> null).consume()); + assertThrows(NullPointerException.class, () -> supplier.get().flatMapToDouble((double d) -> null).consume()); + assertThrows(NullPointerException.class, () -> supplier.get().flatMapToInt((double d) -> null).consume()); + assertThrows(NullPointerException.class, () -> supplier.get().flatMapToLong((double d) -> null).consume()); + } + + @Test + @Override + default void testFlatMapOfDouble_Null() + { + T iterator = getAnyReducible(); + assertThrows(NullPointerException.class, () -> iterator.flatMap((DoubleFunction>) null)); + assertThrows(NullPointerException.class, () -> iterator.flatMapToDouble((DoubleFunction) null)); + assertThrows(NullPointerException.class, () -> iterator.flatMapToInt((DoubleFunction) null)); + assertThrows(NullPointerException.class, () -> iterator.flatMapToLong((DoubleFunction) null)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + @DisplayName("forEach() yields same sequence as forEachRemaining().") + @Override + default void testForEachDoubleConsumer(Supplier supplier) + { + List expected = new ArrayList<>(); + supplier.get().forEachRemaining((DoubleConsumer) expected::add); + T iterator = supplier.get(); + List actual = new ArrayList<>(); + iterator.forEach((DoubleConsumer) actual::add); + assertTrue(iterator.isEmpty()); + assertIterableEquals(unboxDouble(expected), unboxDouble(actual)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + @DisplayName("forEachRemaining() yields same sequence as the underlying iterator.") + default void testForEachRemainingDoubleConsumer(Supplier supplier) + { + List expected = collectElements(supplier); + T iterator = supplier.get(); + List actual = new ArrayList<>(); + iterator.forEachRemaining((DoubleConsumer) actual::add); + assertTrue(iterator.isEmpty()); + assertIterableEquals(unboxDouble(expected), unboxDouble(actual)); + } + + @Test + default void testForEachRemainingDoubleConsumer_Null() + { + T iterator = getAnyReducible(); + assertThrows(NullPointerException.class, () -> iterator.forEachRemaining((DoubleConsumer) null)); + } + + @Test + default void testConcatTypes() + { + // primitive with boxed signature + FunctionalIterator primitive = getAnyReducible(); + assertTrue(getAnyReducible().concat(primitive) instanceof FunctionalPrimitiveIterator.OfDouble); + // boxed + FunctionalIterator boxed = getAnyReducible().map((DoubleFunction) Double::valueOf); + assertFalse(getAnyReducible().concat(boxed) instanceof FunctionalPrimitiveIterator.OfDouble); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testMin_Consumed(Supplier supplier) + { + OptionalDouble expected = OptionalDouble.empty(); + OptionalDouble actual = supplier.get().consume().min(); + assertEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testMax_Consumed(Supplier supplier) + { + OptionalDouble expected = OptionalDouble.empty(); + OptionalDouble actual = supplier.get().consume().max(); + assertEquals(expected, actual); + } + } + + + + interface OfInt extends FunctionalIteratorTest, PrimitiveReducibleTest.OfInt + { + @ParameterizedTest + @MethodSource("getReducibles") + default void testFlatMapIntToObj(Supplier supplier) + { + FunctionalIterator expected = supplier.get().map((IntFunction) String::valueOf); + Iterator actual = supplier.get().flatMap((int i) -> List.of(String.valueOf(i)).iterator()); + assertIteratorEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testFlatMapIntToDouble(Supplier supplier) + { + Range range = new Range((int) supplier.get().count()); + PrimitiveIterator.OfDouble expected = range.iterator().mapToDouble((int i) -> (double) i); + Range.RangeIterator index = range.iterator(); + PrimitiveIterator.OfDouble actual = supplier.get().flatMapToDouble((int i) -> new SingletonIterator.OfDouble(index.next())); + assertIteratorEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testFlatMapIntToInt(Supplier supplier) + { + Range range = new Range((int) supplier.get().count()); + PrimitiveIterator.OfInt expected = range.iterator(); + Range.RangeIterator index = range.iterator(); + PrimitiveIterator.OfInt actual = supplier.get().flatMapToInt((int i) -> new SingletonIterator.OfInt(index.next())); + assertIteratorEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testFlatMapIntToLong(Supplier supplier) + { + Range range = new Range((int) supplier.get().count()); + PrimitiveIterator.OfLong expected = range.iterator().mapToLong((int i) -> (long) i); + Range.RangeIterator index = range.iterator(); + PrimitiveIterator.OfLong actual = supplier.get().flatMapToLong((int i) -> new SingletonIterator.OfLong(index.next())); + assertIteratorEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getSingletonReducibles") + default void testFlatMapIntToNull(Supplier supplier) + { + assertThrows(NullPointerException.class, () -> supplier.get().flatMap((int i) -> null).consume()); + assertThrows(NullPointerException.class, () -> supplier.get().flatMapToDouble((int i) -> null).consume()); + assertThrows(NullPointerException.class, () -> supplier.get().flatMapToInt((int i) -> null).consume()); + assertThrows(NullPointerException.class, () -> supplier.get().flatMapToLong((int i) -> null).consume()); + } + + @Test + default void testFlatMapOfInt_Null() + { + T iterator = getAnyReducible(); + assertThrows(NullPointerException.class, () -> iterator.flatMap((IntFunction>) null)); + assertThrows(NullPointerException.class, () -> iterator.flatMapToDouble((IntFunction) null)); + assertThrows(NullPointerException.class, () -> iterator.flatMapToInt((IntFunction) null)); + assertThrows(NullPointerException.class, () -> iterator.flatMapToLong((IntFunction) null)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + @DisplayName("forEach() yields same sequence as the underlying iterator.") + @Override + default void testForEachIntConsumer(Supplier supplier) + { + List expected = new ArrayList<>(); + supplier.get().forEachRemaining((IntConsumer) expected::add); + T iterator = supplier.get(); + List actual = new ArrayList<>(); + iterator.forEach((IntConsumer) actual::add); + assertTrue(iterator.isEmpty()); + assertIterableEquals(unboxInt(expected), unboxInt(actual)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + @DisplayName("forEachRemaining() yields same sequence as the underlying iterator.") + default void testForEachRemainingIntConsumer(Supplier supplier) + { + List expected = collectElements(supplier); + List actual = new ArrayList<>(); + supplier.get().forEachRemaining((IntConsumer) actual::add); + assertIterableEquals(unboxInt(expected), unboxInt(actual)); + } + + @Test + default void testForEachRemainingIntConsumer_Null() + { + T iterator = getAnyReducible(); + assertThrows(NullPointerException.class, () -> iterator.forEachRemaining((IntConsumer) null)); + } + + @Test + default void testConcatTypes() + { + // primitive with boxed signature + FunctionalIterator primitive = getAnyReducible(); + assertTrue(getAnyReducible().concat(primitive) instanceof FunctionalPrimitiveIterator.OfInt); + // boxed + FunctionalIterator boxed = getAnyReducible().map((IntFunction) Integer::valueOf); + assertFalse(getAnyReducible().concat(boxed) instanceof FunctionalPrimitiveIterator.OfInt); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testMin_Consumed(Supplier supplier) + { + OptionalInt expected = OptionalInt.empty(); + OptionalInt actual = supplier.get().consume().min(); + assertEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testMax_Consumed(Supplier supplier) + { + OptionalInt expected = OptionalInt.empty(); + OptionalInt actual = supplier.get().consume().max(); + assertEquals(expected, actual); + } + } + + + + interface OfLong extends FunctionalIteratorTest, PrimitiveReducibleTest.OfLong + { + @ParameterizedTest + @MethodSource("getReducibles") + default void testFlatMapLongToObj(Supplier supplier) + { + FunctionalIterator expected = supplier.get().map((LongFunction) String::valueOf); + Iterator actual = supplier.get().flatMap((long l) -> List.of(String.valueOf(l)).iterator()); + assertIteratorEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testFlatMapLongToDouble(Supplier supplier) + { + Range range = new Range((int) supplier.get().count()); + PrimitiveIterator.OfDouble expected = range.iterator().mapToDouble((int i) -> (double) i); + Range.RangeIterator index = range.iterator(); + PrimitiveIterator.OfDouble actual = supplier.get().flatMapToDouble((long l) -> new SingletonIterator.OfDouble(index.next())); + assertIteratorEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testFlatMapLongToInt(Supplier supplier) + { + Range range = new Range((int) supplier.get().count()); + PrimitiveIterator.OfInt expected = range.iterator(); + Range.RangeIterator index = range.iterator(); + PrimitiveIterator.OfInt actual = supplier.get().flatMapToInt((long l) -> new SingletonIterator.OfInt(index.next())); + assertIteratorEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testFlatMapLongToLong(Supplier supplier) + { + Range range = new Range((int) supplier.get().count()); + PrimitiveIterator.OfLong expected = range.iterator().mapToLong((int i) -> (long) i); + Range.RangeIterator index = range.iterator(); + PrimitiveIterator.OfLong actual = supplier.get().flatMapToLong((long l) -> new SingletonIterator.OfLong(index.next())); + assertIteratorEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getSingletonReducibles") + default void testFlatMapLongToNull(Supplier supplier) + { + assertThrows(NullPointerException.class, () -> supplier.get().flatMap((long l) -> null).consume()); + assertThrows(NullPointerException.class, () -> supplier.get().flatMapToDouble((long l) -> null).consume()); + assertThrows(NullPointerException.class, () -> supplier.get().flatMapToInt((long l) -> null).consume()); + assertThrows(NullPointerException.class, () -> supplier.get().flatMapToLong((long l) -> null).consume()); + } + + @Test + default void testFlatMapOfLong_Null() + { + T iterator = getAnyReducible(); + assertThrows(NullPointerException.class, () -> iterator.flatMap((LongFunction>) null)); + assertThrows(NullPointerException.class, () -> iterator.flatMapToDouble((LongFunction) null)); + assertThrows(NullPointerException.class, () -> iterator.flatMapToInt((LongFunction) null)); + assertThrows(NullPointerException.class, () -> iterator.flatMapToLong((LongFunction) null)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + @DisplayName("forEach() yields same sequence as the underlying iterator.") + @Override + default void testForEachLongConsumer(Supplier supplier) + { + List expected = new ArrayList<>(); + supplier.get().forEachRemaining((LongConsumer) expected::add); + T iterator = supplier.get(); + List actual = new ArrayList<>(); + iterator.forEach((LongConsumer) actual::add); + assertTrue(iterator.isEmpty()); + assertIterableEquals(unboxLong(expected), unboxLong(actual)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + @DisplayName("forEachRemaining() yields same sequence as the underlying iterator.") + default void testForEachRemainingLongConsumer(Supplier supplier) + { + List expected = collectElements(supplier); + List actual = new ArrayList<>(); + supplier.get().forEachRemaining((LongConsumer) actual::add); + assertIterableEquals(unboxLong(expected), unboxLong(actual)); + } + + @Test + default void testForEachRemainingLongConsumer_Null() + { + T iterator = getAnyReducible(); + assertThrows(NullPointerException.class, () -> iterator.forEachRemaining((LongConsumer) null)); + } + + @Test + default void testConcatTypes() + { + // primitive with boxed signature + FunctionalIterator primitive = getAnyReducible(); + assertTrue(getAnyReducible().concat(primitive) instanceof FunctionalPrimitiveIterator.OfLong); + // boxed + FunctionalIterator boxed = getAnyReducible().map((LongFunction) Long::valueOf); + assertFalse(getAnyReducible().concat(boxed) instanceof FunctionalPrimitiveIterator.OfLong); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testMin_Consumed(Supplier supplier) + { + OptionalLong expected = OptionalLong.empty(); + OptionalLong actual = supplier.get().consume().min(); + assertEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testMax_Consumed(Supplier supplier) + { + OptionalLong expected = OptionalLong.empty(); + OptionalLong actual = supplier.get().consume().max(); + assertEquals(expected, actual); + } + } +} diff --git a/prism/unit-tests/common/iterable/IterableAdaptorTest.java b/prism/unit-tests/common/iterable/IterableAdaptorTest.java new file mode 100644 index 0000000000..b0436ca3f4 --- /dev/null +++ b/prism/unit-tests/common/iterable/IterableAdaptorTest.java @@ -0,0 +1,156 @@ +package common.iterable; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.*; + +import static common.iterable.Assertions.assertIterableEquals; +import static org.junit.jupiter.api.Assertions.assertIterableEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class IterableAdaptorTest +{ + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class Of implements FunctionalIterableTest.Of> + { + @Override + public IterableAdaptor.Of getReducible(Object[] objects) + { + return new IterableAdaptor.Of<>(Arrays.asList(objects)); + } + + @ParameterizedTest + @MethodSource("getArraysAsArguments") + @DisplayName("Adaptor yields same sequence as the underlying iterator.") + public void testOf(Object[] objects) + { + List expected = Arrays.asList(objects); + IterableAdaptor.Of actual = new IterableAdaptor.Of<>(expected); + assertIterableEquals(expected, actual); + } + + @Test + @DisplayName("Adapter on null throws NullPointerException.") + public void testOf_Null() + { + assertThrows(NullPointerException.class, () -> new IterableAdaptor.Of<>(null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfDouble implements FunctionalPrimitiveIterableTest.OfDouble + { + @Override + public IterableAdaptor.OfDouble getReducible(double[] numbers) + { + PrimitiveIterable.OfDouble iterable = asNonFunctionalIterable(numbers); + return new IterableAdaptor.OfDouble(iterable); + } + + @ParameterizedTest + @MethodSource("getArraysOfDouble") + @DisplayName("Adaptor yields same sequence as the underlying iterator.") + public void testOfDouble(double[] numbers) + { + PrimitiveIterable.OfDouble expected = asNonFunctionalIterable(numbers); + IterableAdaptor.OfDouble actual = new IterableAdaptor.OfDouble(expected); + assertIterableEquals(expected, actual); + } + + @Test + @DisplayName("Adapter on null throws NullPointerException.") + public void testOfDouble_Null() + { + assertThrows(NullPointerException.class, () -> new IterableAdaptor.OfDouble(null)); + } + + private PrimitiveIterable.OfDouble asNonFunctionalIterable(double[] numbers) + { + List boxed = FunctionalIterator.ofDouble(numbers).collect(new ArrayList<>()); + return PrimitiveIterable.unboxDouble(boxed); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfInt implements FunctionalPrimitiveIterableTest.OfInt + { + @Override + public IterableAdaptor.OfInt getReducible(int[] numbers) + { + PrimitiveIterable.OfInt iterable = asNonFunctionalIterable(numbers); + return new IterableAdaptor.OfInt(iterable); + } + + @ParameterizedTest + @MethodSource("getArraysOfInt") + @DisplayName("Adaptor yields same sequence as the underlying iterator.") + public void testOfInt(int[] numbers) + { + PrimitiveIterable.OfInt expected = asNonFunctionalIterable(numbers); + IterableAdaptor.OfInt actual = new IterableAdaptor.OfInt(expected); + assertIterableEquals(expected, actual); + } + + @Test + @DisplayName("Adapter on null throws NullPointerException.") + public void testOfInt_Null() + { + assertThrows(NullPointerException.class, () -> new IterableAdaptor.OfInt(null)); + } + + private PrimitiveIterable.OfInt asNonFunctionalIterable(int[] numbers) + { + List boxed = FunctionalIterator.ofInt(numbers).collect(new ArrayList<>()); + return PrimitiveIterable.unboxInt(boxed); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfLong implements FunctionalPrimitiveIterableTest.OfLong + { + @Override + public IterableAdaptor.OfLong getReducible(long[] numbers) + { + PrimitiveIterable.OfLong iterable = asNonFunctionalIterable(numbers); + return new IterableAdaptor.OfLong(iterable); + } + + @ParameterizedTest + @MethodSource("getArraysOfLong") + @DisplayName("Adaptor yields same sequence as the underlying iterator.") + public void testOfLong(long[] numbers) + { + PrimitiveIterable.OfLong expected = asNonFunctionalIterable(numbers); + IterableAdaptor.OfLong actual = new IterableAdaptor.OfLong(expected); + assertIterableEquals(expected, actual); + } + + @Test + @DisplayName("Adapter on null throws NullPointerException.") + public void testOfLong_Null() + { + assertThrows(NullPointerException.class, () -> new IterableAdaptor.OfLong(null)); + } + + private PrimitiveIterable.OfLong asNonFunctionalIterable(long[] numbers) + { + List boxed = FunctionalIterator.ofLong(numbers).collect(new ArrayList<>()); + return PrimitiveIterable.unboxLong(boxed); + } + } +} diff --git a/prism/unit-tests/common/iterable/IterableArrayTest.java b/prism/unit-tests/common/iterable/IterableArrayTest.java new file mode 100644 index 0000000000..041b26b146 --- /dev/null +++ b/prism/unit-tests/common/iterable/IterableArrayTest.java @@ -0,0 +1,239 @@ +package common.iterable; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.Optional; + +import static common.iterable.Assertions.assertIterableEquals; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertIterableEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +interface IterableArrayTest +{ + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class Of implements IterableArrayTest, FunctionalIterableTest.Of> + { + @Override + public IterableArray.Of getReducible(Object[] objects) + { + return new IterableArray.Of<>(objects); + } + + @ParameterizedTest + @MethodSource("getArraysAsArguments") + public void testOfArray(Object[] array) + { + IterableArray.Of iterator = new IterableArray.Of<>(array); + Object[] actual = iterator.collect(new Object[array.length]); + assertArrayEquals(array, actual); + } + + @ParameterizedTest + @MethodSource("getArraysAsArguments") + public void testOfArrayIntInt_All(Object[] array) + { + IterableArray.Of expected = new IterableArray.Of<>(array); + IterableArray.Of actual = new IterableArray.Of<>(array, 0, array.length); + assertIterableEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource({"getMultitonArraysAsArguments"}) + public void testOfArrayIntInt_Range(Object[] array) + { + FunctionalIterable expected = new Range(1, array.length - 1).map((int i) -> array[i]); + IterableArray.Of actual = new IterableArray.Of<>(array, 1, array.length - 1); + assertIterableEquals(expected, actual); + } + + @Test + public void testOf_Errors() + { + Optional any = getMultitonArraysOfObject().findAny(); + assert any.isPresent(); + Object[] array = any.get(); + int length = array.length; + assertThrows(NullPointerException.class, () -> new IterableArray.Of<>((Object[]) null)); + assertThrows(NullPointerException.class, () -> new IterableArray.Of<>(null, 0, 0)); + assertThrows(IndexOutOfBoundsException.class, () -> new IterableArray.Of<>(array, -1, -1)); + assertThrows(IndexOutOfBoundsException.class, () -> new IterableArray.Of<>(array, -1, length)); + assertThrows(IndexOutOfBoundsException.class, () -> new IterableArray.Of<>(array, 1, 0)); + assertThrows(IndexOutOfBoundsException.class, () -> new IterableArray.Of<>(array, 0, length+1)); + assertThrows(IndexOutOfBoundsException.class, () -> new IterableArray.Of<>(array, length+1, length+1)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfDouble implements IterableArrayTest, FunctionalPrimitiveIterableTest.OfDouble + { + @Override + public IterableArray.OfDouble getReducible(double[] numbers) + { + return new IterableArray.OfDouble(numbers); + } + + @ParameterizedTest + @MethodSource({"getEmptyArraysOfDouble", "getSingletonArraysOfDouble", "getMultitonArraysOfDouble"}) + public void testOfDouble(double[] array) + { + IterableArray.OfDouble iterator = new IterableArray.OfDouble(array); + double[] actual = iterator.collect(new double[array.length]); + assertArrayEquals(array, actual); + } + + @ParameterizedTest + @MethodSource({"getEmptyArraysOfDouble", "getSingletonArraysOfDouble", "getMultitonArraysOfDouble"}) + public void testOfDoubleArrayIntInt_All(double[] array) + { + IterableArray.OfDouble expected = new IterableArray.OfDouble(array); + IterableArray.OfDouble actual = new IterableArray.OfDouble(array, 0, array.length); + assertIterableEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource({"getMultitonArraysOfDouble"}) + public void testOfDoubleArrayIntInt_Range(double[] array) + { + FunctionalPrimitiveIterable.OfDouble expected = new Range(1, array.length - 1).mapToDouble((int i) -> array[i]); + IterableArray.OfDouble actual = new IterableArray.OfDouble(array, 1, array.length - 1); + assertIterableEquals(expected, actual); + } + + @Test + public void testOfDouble_Errors() + { + Optional any = getMultitonArraysOfDouble().findAny(); + assert any.isPresent(); + double[] array = any.get(); + int length = array.length; + assertThrows(NullPointerException.class, () -> new IterableArray.OfDouble((double[]) null)); + assertThrows(NullPointerException.class, () -> new IterableArray.OfDouble(null, 0, 0)); + assertThrows(IndexOutOfBoundsException.class, () -> new IterableArray.OfDouble(array, -1, -1)); + assertThrows(IndexOutOfBoundsException.class, () -> new IterableArray.OfDouble(array, -1, length)); + assertThrows(IndexOutOfBoundsException.class, () -> new IterableArray.OfDouble(array, 1, 0)); + assertThrows(IndexOutOfBoundsException.class, () -> new IterableArray.OfDouble(array, 0, length+1)); + assertThrows(IndexOutOfBoundsException.class, () -> new IterableArray.OfDouble(array, length+1, length+1)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfInt implements IterableArrayTest, FunctionalPrimitiveIterableTest.OfInt + { + @Override + public IterableArray.OfInt getReducible(int[] numbers) + { + return new IterableArray.OfInt(numbers); + } + + @ParameterizedTest + @MethodSource({"getEmptyArraysOfInt", "getSingletonArraysOfInt", "getMultitonArraysOfInt"}) + public void testOfInt(int[] array) + { + IterableArray.OfInt iterator = new IterableArray.OfInt(array); + int[] actual = iterator.collect(new int[array.length]); + assertArrayEquals(array, actual); + } + + @ParameterizedTest + @MethodSource({"getEmptyArraysOfInt", "getSingletonArraysOfInt", "getMultitonArraysOfInt"}) + public void testOfIntArrayIntInt_All(int[] array) + { + IterableArray.OfInt expected = new IterableArray.OfInt(array); + IterableArray.OfInt actual = new IterableArray.OfInt(array, 0, array.length); + assertIterableEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource({"getMultitonArraysOfInt"}) + public void testOfIntArrayIntInt_Range(int[] array) + { + FunctionalPrimitiveIterable.OfInt expected = new Range(1, array.length - 1).mapToInt((int i) -> array[i]); + IterableArray.OfInt actual = new IterableArray.OfInt(array, 1, array.length - 1); + assertIterableEquals(expected, actual); + } + + @Test + public void testOfInt_Errors() + { + Optional any = getMultitonArraysOfInt().findAny(); + assert any.isPresent(); + int[] array = any.get(); + int length = array.length; + assertThrows(NullPointerException.class, () -> new IterableArray.OfInt((int[]) null)); + assertThrows(NullPointerException.class, () -> new IterableArray.OfInt(null, 0, 0)); + assertThrows(IndexOutOfBoundsException.class, () -> new IterableArray.OfInt(array, -1, -1)); + assertThrows(IndexOutOfBoundsException.class, () -> new IterableArray.OfInt(array, -1, length)); + assertThrows(IndexOutOfBoundsException.class, () -> new IterableArray.OfInt(array, 1, 0)); + assertThrows(IndexOutOfBoundsException.class, () -> new IterableArray.OfInt(array, 0, length+1)); + assertThrows(IndexOutOfBoundsException.class, () -> new IterableArray.OfInt(array, length+1, length+1)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfLong implements IterableArrayTest, FunctionalPrimitiveIterableTest.OfLong + { + @Override + public IterableArray.OfLong getReducible(long[] numbers) + { + return new IterableArray.OfLong(numbers); + } + + @ParameterizedTest + @MethodSource({"getEmptyArraysOfLong", "getSingletonArraysOfLong", "getMultitonArraysOfLong"}) + public void testOfLong(long[] array) + { + IterableArray.OfLong iterator = new IterableArray.OfLong(array); + long[] actual = iterator.collect(new long[array.length]); + assertArrayEquals(array, actual); + } + + @ParameterizedTest + @MethodSource({"getEmptyArraysOfLong", "getSingletonArraysOfLong", "getMultitonArraysOfLong"}) + public void testOfLongArrayIntInt_All(long[] array) + { + IterableArray.OfLong expected = new IterableArray.OfLong(array); + IterableArray.OfLong actual = new IterableArray.OfLong(array, 0, array.length); + assertIterableEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource({"getMultitonArraysOfLong"}) + public void testOfLongArrayIntInt_Range(long[] array) + { + FunctionalPrimitiveIterable.OfLong expected = new Range(1, array.length - 1).mapToLong((int i) -> array[i]); + IterableArray.OfLong actual = new IterableArray.OfLong(array, 1, array.length - 1); + assertIterableEquals(expected, actual); + } + + @Test + public void testOfLong_Errors() + { + Optional any = getMultitonArraysOfLong().findAny(); + assert any.isPresent(); + long[] array = any.get(); + int length = array.length; + assertThrows(NullPointerException.class, () -> new IterableArray.OfLong((long[]) null)); + assertThrows(NullPointerException.class, () -> new IterableArray.OfLong(null, 0, 0)); + assertThrows(IndexOutOfBoundsException.class, () -> new IterableArray.OfLong(array, -1, -1)); + assertThrows(IndexOutOfBoundsException.class, () -> new IterableArray.OfLong(array, -1, length)); + assertThrows(IndexOutOfBoundsException.class, () -> new IterableArray.OfLong(array, 1, 0)); + assertThrows(IndexOutOfBoundsException.class, () -> new IterableArray.OfLong(array, 0, length+1)); + assertThrows(IndexOutOfBoundsException.class, () -> new IterableArray.OfLong(array, length+1, length+1)); + } + } +} \ No newline at end of file diff --git a/prism/unit-tests/common/iterable/IteratorAdaptorTest.java b/prism/unit-tests/common/iterable/IteratorAdaptorTest.java new file mode 100644 index 0000000000..9f4cdfdac1 --- /dev/null +++ b/prism/unit-tests/common/iterable/IteratorAdaptorTest.java @@ -0,0 +1,198 @@ +package common.iterable; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.*; + +import static common.iterable.Assertions.assertIteratorEquals; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class IteratorAdaptorTest +{ + @Nested + @TestInstance(Lifecycle.PER_CLASS) + class Of implements FunctionalIteratorTest.Of> + { + @Override + public IteratorAdaptor.Of getReducible(Object[] objects) + { + return new IteratorAdaptor.Of<>(Arrays.asList(objects).iterator()); + } + + @ParameterizedTest + @MethodSource("getArraysAsArguments") + @DisplayName("Adaptor yields same sequence as the underlying iterator.") + public void testOf(Object[] objects) + { + List iterable = Arrays.asList(objects); + Iterator expected = iterable.iterator(); + IteratorAdaptor.Of actual = new IteratorAdaptor.Of<>(iterable.iterator()); + assertIteratorEquals(expected, actual); + } + + @Test + @DisplayName("Adapter on null throws NullPointerException.") + public void testOf_Null() + { + assertThrows(NullPointerException.class, () -> new IteratorAdaptor.Of<>(null)); + } + + @ParameterizedTest + @MethodSource("getArraysAsArguments") + @DisplayName("unwrap() answers the underlying iterator.") + public void testUnwrap(Object[] objects) + { + Iterator expected = Arrays.asList(objects).iterator(); + Iterator actual = new IteratorAdaptor.Of<>(expected).unwrap(); + assertSame(expected, actual); + } + } + + + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + class OfDouble implements FunctionalPrimitiveIteratorTest.OfDouble + { + @Override + public IteratorAdaptor.OfDouble getReducible(double[] numbers) + { + PrimitiveIterable.OfDouble iterable = asNonFunctionalIterable(numbers); + return new IteratorAdaptor.OfDouble(iterable.iterator()); + } + + @ParameterizedTest + @MethodSource("getArraysOfDouble") + @DisplayName("Adaptor yields same sequence as the underlying iterator.") + public void testOfDouble(double[] numbers) + { + PrimitiveIterable.OfDouble expected = asNonFunctionalIterable(numbers); + IteratorAdaptor.OfDouble actual = new IteratorAdaptor.OfDouble(expected.iterator()); + assertIteratorEquals(expected.iterator(), actual); + } + + @Test + @DisplayName("Adapter on null throws NullPointerException.") + public void testOfDouble_Null() + { + assertThrows(NullPointerException.class, () -> new IteratorAdaptor.OfDouble(null)); + } + + @ParameterizedTest + @MethodSource("getArraysOfDouble") + @DisplayName("unwrap() answers the underlying iterator.") + public void testUnwrap(double[] numbers) + { + PrimitiveIterator.OfDouble expected = asNonFunctionalIterable(numbers).iterator(); + PrimitiveIterator.OfDouble actual = new IteratorAdaptor.OfDouble(expected).unwrap(); + assertSame(expected, actual); + } + + private PrimitiveIterable.OfDouble asNonFunctionalIterable(double[] numbers) + { + List boxed = FunctionalIterator.ofDouble(numbers).collect(new ArrayList<>()); + return PrimitiveIterable.unboxDouble(boxed); + } + } + + + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + class OfInt implements FunctionalPrimitiveIteratorTest.OfInt + { + @Override + public IteratorAdaptor.OfInt getReducible(int[] numbers) + { + PrimitiveIterable.OfInt iterable = asNonFunctionalIterable(numbers); + return new IteratorAdaptor.OfInt(iterable.iterator()); + } + + @ParameterizedTest + @MethodSource("getArraysOfInt") + @DisplayName("Adaptor yields same sequence as the underlying iterator.") + public void testOfInt(int[] numbers) + { + PrimitiveIterable.OfInt expected = asNonFunctionalIterable(numbers); + IteratorAdaptor.OfInt actual = new IteratorAdaptor.OfInt(expected.iterator()); + assertIteratorEquals(expected.iterator(), actual); + } + + @Test + @DisplayName("Adapter on null throws NullPointerException.") + public void testOfInt_Null() + { + assertThrows(NullPointerException.class, () -> new IteratorAdaptor.OfInt(null)); + } + + @ParameterizedTest + @MethodSource("getArraysOfInt") + @DisplayName("unwrap() answers the underlying iterator.") + public void testUnwrap(int[] numbers) + { + PrimitiveIterator.OfInt expected = asNonFunctionalIterable(numbers).iterator(); + PrimitiveIterator.OfInt actual = new IteratorAdaptor.OfInt(expected).unwrap(); + assertSame(expected, actual); + } + + private PrimitiveIterable.OfInt asNonFunctionalIterable(int[] numbers) + { + List boxed = FunctionalIterator.ofInt(numbers).collect(new ArrayList<>()); + return PrimitiveIterable.unboxInt(boxed); + } + } + + + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + class OfLong implements FunctionalPrimitiveIteratorTest.OfLong + { + @Override + public IteratorAdaptor.OfLong getReducible(long[] numbers) + { + PrimitiveIterable.OfLong iterable = asNonFunctionalIterable(numbers); + return new IteratorAdaptor.OfLong(iterable.iterator()); + } + + @ParameterizedTest + @MethodSource("getArraysOfLong") + @DisplayName("Adaptor yields same sequence as the underlying iterator.") + public void testOfLong(long[] numbers) + { + PrimitiveIterable.OfLong expected = asNonFunctionalIterable(numbers); + IteratorAdaptor.OfLong actual = new IteratorAdaptor.OfLong(expected.iterator()); + assertIteratorEquals(expected.iterator(), actual); + } + + @Test + @DisplayName("Adapter on null throws NullPointerException.") + public void testOfLong_Null() + { + assertThrows(NullPointerException.class, () -> new IteratorAdaptor.OfLong(null)); + } + + @ParameterizedTest + @MethodSource("getArraysOfLong") + @DisplayName("unwrap() answers the underlying iterator.") + public void testUnwrap(long[] numbers) + { + PrimitiveIterator.OfLong expected = asNonFunctionalIterable(numbers).iterator(); + PrimitiveIterator.OfLong actual = new IteratorAdaptor.OfLong(expected).unwrap(); + assertSame(expected, actual); + } + + private PrimitiveIterable.OfLong asNonFunctionalIterable(long[] numbers) + { + List boxed = FunctionalIterator.ofLong(numbers).collect(new ArrayList<>()); + return PrimitiveIterable.unboxLong(boxed); + } + } +} diff --git a/prism/unit-tests/common/iterable/MappingIterableTest.java b/prism/unit-tests/common/iterable/MappingIterableTest.java new file mode 100644 index 0000000000..a0792ef87a --- /dev/null +++ b/prism/unit-tests/common/iterable/MappingIterableTest.java @@ -0,0 +1,587 @@ +package common.iterable; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.*; + +import static common.iterable.Assertions.assertIterableEquals; +import static common.iterable.PrimitiveIterable.*; +import static org.junit.jupiter.api.Assertions.assertIterableEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +interface MappingIterableTest +{ + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class ObjToObj implements MappingIterableTest, FunctionalIterableTest.Of> + { + @Override + public MappingIterable.ObjToObj getReducible(Object[] objects) + { + Map lookup = new LinkedHashMap<>(); + for (int i=0, length=objects.length; i(lookup.keySet(), lookup::get); + } + + @ParameterizedTest + @MethodSource("getArraysAsArguments") + void testOf(Object[] objects) + { + ArrayList expected = new ArrayList<>(); + for (Object each : objects) { + expected.add(Objects.toString(each)); + } + Iterable iterable = new IterableArray.Of<>(objects); + Iterable actual = new MappingIterable.ObjToObj<>(iterable, Objects::toString); + assertIterableEquals(expected, actual); + } + + @Test + public void testOf_Null() + { + EmptyIterable.Of iterable = EmptyIterable.of(); + assertThrows(NullPointerException.class, () -> new MappingIterable.ObjToObj<>(null, each -> each)); + assertThrows(NullPointerException.class, () -> new MappingIterable.ObjToObj<>(iterable, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class ObjToDouble implements MappingIterableTest, FunctionalPrimitiveIterableTest.OfDouble> + { + @Override + public MappingIterable.ObjToDouble getReducible(double[] numbers) + { + List boxed = FunctionalIterable.ofDouble(numbers).collect(new ArrayList<>()); + return new MappingIterable.ObjToDouble<>(boxed, Double::doubleValue); + } + + @ParameterizedTest + @MethodSource("getArraysOfDouble") + public void testObjToDouble(double[] numbers) + { + ArrayList expected = new ArrayList<>(); + for (double d : numbers) { + expected.add(d); + } + FunctionalPrimitiveIterable.OfDouble actual = new MappingIterable.ObjToDouble<>(expected, each -> each); + assertIterableEquals(unboxDouble(expected), actual); + } + + @Test + public void testObjToDouble_Null() + { + EmptyIterable.Of iterable = EmptyIterable.of(); + assertThrows(NullPointerException.class, () -> new MappingIterable.ObjToDouble(null, each -> each)); + assertThrows(NullPointerException.class, () -> new MappingIterable.ObjToDouble<>(iterable, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class ObjToInt implements MappingIterableTest, FunctionalPrimitiveIterableTest.OfInt> + { + @Override + public MappingIterable.ObjToInt getReducible(int[] numbers) + { + List boxed = FunctionalIterable.ofInt(numbers).collect(new ArrayList<>()); + return new MappingIterable.ObjToInt<>(boxed, Integer::intValue); + } + + @ParameterizedTest + @MethodSource("getArraysOfInt") + public void testObjToInt(int[] numbers) + { + ArrayList expected = new ArrayList<>(); + for (int i : numbers) { + expected.add(i); + } + FunctionalPrimitiveIterable.OfInt actual = new MappingIterable.ObjToInt<>(expected, each -> each); + assertIterableEquals(unboxInt(expected), actual); + } + + @Test + public void testObjToInt_Null() + { + EmptyIterable.Of iterable = EmptyIterable.of(); + assertThrows(NullPointerException.class, () -> new MappingIterable.ObjToInt(null, each -> each)); + assertThrows(NullPointerException.class, () -> new MappingIterable.ObjToInt<>(iterable, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class ObjToLong implements MappingIterableTest, FunctionalPrimitiveIterableTest.OfLong> + { + @Override + public MappingIterable.ObjToLong getReducible(long[] numbers) + { + List boxed = FunctionalIterable.ofLong(numbers).collect(new ArrayList<>()); + return new MappingIterable.ObjToLong<>(boxed, Long::longValue); + } + + @ParameterizedTest + @MethodSource("getArraysOfLong") + public void testObjToLong(long[] numbers) + { + ArrayList expected = new ArrayList<>(); + for (long l : numbers) { + expected.add(l); + } + FunctionalPrimitiveIterable.OfLong actual = new MappingIterable.ObjToLong<>(expected, each -> each); + assertIterableEquals(unboxLong(expected), actual); + } + + @Test + public void testObjToLong_Null() + { + EmptyIterable.Of iterable = EmptyIterable.of(); + assertThrows(NullPointerException.class, () -> new MappingIterable.ObjToLong(null, each -> each)); + assertThrows(NullPointerException.class, () -> new MappingIterable.ObjToLong<>(iterable, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class DoubleToObj implements MappingIterableTest, FunctionalIterableTest.Of> + { + @Override + public MappingIterable.DoubleToObj getReducible(Object[] objects) + { + Map lookup = new LinkedHashMap<>(); + FunctionalIterable.of(objects).reduce(1.5, (d, e) -> {lookup.put(d, e); return d + 1;}); + return new MappingIterable.DoubleToObj<>(unboxDouble(lookup.keySet()), lookup::get); + } + + @ParameterizedTest + @MethodSource("getArraysOfDouble") + public void testDoubleToObj(double[] numbers) + { + ArrayList expected = new ArrayList<>(); + for (double d : numbers) { + expected.add(Objects.toString(d)); + } + IterableArray.OfDouble iterable = new IterableArray.OfDouble(numbers); + Iterable actual = new MappingIterable.DoubleToObj<>(iterable, Objects::toString); + assertIterableEquals(expected, actual); + } + + @Test + public void testDoubleToObj_Null() + { + EmptyIterable.OfDouble iterable = EmptyIterable.ofDouble(); + assertThrows(NullPointerException.class, () -> new MappingIterable.DoubleToObj<>(null, each -> each)); + assertThrows(NullPointerException.class, () -> new MappingIterable.DoubleToObj<>(iterable, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class DoubleToDouble implements MappingIterableTest, FunctionalPrimitiveIterableTest.OfDouble + { + @Override + public MappingIterable.DoubleToDouble getReducible(double[] numbers) + { + Map lookup = new LinkedHashMap<>(); + FunctionalIterable.ofDouble(numbers).reduce(1.5, (double d, double e) -> {lookup.put(d, e); return d + 1;}); + return new MappingIterable.DoubleToDouble(unboxDouble(lookup.keySet()), lookup::get); + } + + @ParameterizedTest + @MethodSource("getArraysOfDouble") + public void testDoubleToDouble(double[] numbers) + { + ArrayList expected = new ArrayList<>(); + for (double d : numbers) { + expected.add(d + 1.0); + } + IterableArray.OfDouble iterable = new IterableArray.OfDouble(numbers); + PrimitiveIterable.OfDouble actual = new MappingIterable.DoubleToDouble(iterable, d -> d + 1.0); + assertIterableEquals(unboxDouble(expected), actual); + } + + @Test + public void testDoubleToDouble_Null() + { + EmptyIterable.OfDouble iterable = EmptyIterable.ofDouble(); + assertThrows(NullPointerException.class, () -> new MappingIterable.DoubleToDouble(null, each -> each)); + assertThrows(NullPointerException.class, () -> new MappingIterable.DoubleToDouble(iterable, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class DoubleToInt implements MappingIterableTest, FunctionalPrimitiveIterableTest.OfInt + { + @Override + public MappingIterable.DoubleToInt getReducible(int[] numbers) + { + Map lookup = new LinkedHashMap<>(); + FunctionalIterable.ofInt(numbers).reduce(1.5, (Double d, Integer e) -> {lookup.put(d, e); return d + 1;}); + return new MappingIterable.DoubleToInt(unboxDouble(lookup.keySet()), lookup::get); + } + + @ParameterizedTest + @MethodSource("getArraysOfDouble") + public void testDoubleToInt(double[] numbers) + { + ArrayList expected = new ArrayList<>(); + for (double d : numbers) { + expected.add((int) d + 1); + } + IterableArray.OfDouble iterable = new IterableArray.OfDouble(numbers); + PrimitiveIterable.OfInt actual = new MappingIterable.DoubleToInt(iterable, d -> (int) d + 1); + assertIterableEquals(unboxInt(expected), actual); + } + + @Test + public void testDoubleToInt_Null() + { + EmptyIterable.OfDouble iterable = EmptyIterable.ofDouble(); + assertThrows(NullPointerException.class, () -> new MappingIterable.DoubleToInt(null, each -> (int) each)); + assertThrows(NullPointerException.class, () -> new MappingIterable.DoubleToInt(iterable, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class DoubleToLong implements MappingIterableTest, FunctionalPrimitiveIterableTest.OfLong + { + @Override + public MappingIterable.DoubleToLong getReducible(long[] numbers) + { + Map lookup = new LinkedHashMap<>(); + FunctionalIterable.ofLong(numbers).reduce(1.5, (double d, long e) -> {lookup.put(d, e); return d + 1;}); + return new MappingIterable.DoubleToLong(unboxDouble(lookup.keySet()), lookup::get); + } + + @ParameterizedTest + @MethodSource("getArraysOfDouble") + public void testDoubleToLong(double[] numbers) + { + ArrayList expected = new ArrayList<>(); + for (double d : numbers) { + expected.add((long) d + 1); + } + IterableArray.OfDouble iterable = new IterableArray.OfDouble(numbers); + PrimitiveIterable.OfLong actual = new MappingIterable.DoubleToLong(iterable, d -> (long) d + 1); + assertIterableEquals(unboxLong(expected), actual); + } + + @Test + public void testDoubleToLong_Null() + { + EmptyIterable.OfDouble iterable = EmptyIterable.ofDouble(); + assertThrows(NullPointerException.class, () -> new MappingIterable.DoubleToLong(null, each -> (long) each)); + assertThrows(NullPointerException.class, () -> new MappingIterable.DoubleToLong(iterable, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class IntToObj implements MappingIterableTest, FunctionalIterableTest.Of> + { + @Override + public MappingIterable.IntToObj getReducible(Object[] objects) + { + Map lookup = new LinkedHashMap<>(); + FunctionalIterable.of(objects).reduce(1, (int i, Object e) -> {lookup.put(i, e); return i + 1;}); + return new MappingIterable.IntToObj<>(unboxInt(lookup.keySet()), lookup::get); + } + + @ParameterizedTest + @MethodSource("getArraysOfInt") + public void testIntToObj(int[] numbers) + { + ArrayList expected = new ArrayList<>(); + for (int i : numbers) { + expected.add(Objects.toString(i)); + } + IterableArray.OfInt iterable = new IterableArray.OfInt(numbers); + Iterable actual = new MappingIterable.IntToObj<>(iterable, Objects::toString); + assertIterableEquals(expected, actual); + } + + @Test + public void testIntToObj_Null() + { + EmptyIterable.OfInt iterable = EmptyIterable.ofInt(); + assertThrows(NullPointerException.class, () -> new MappingIterable.IntToObj<>(null, each -> each)); + assertThrows(NullPointerException.class, () -> new MappingIterable.IntToObj<>(iterable, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class IntToDouble implements MappingIterableTest, FunctionalPrimitiveIterableTest.OfDouble + { + @Override + public MappingIterable.IntToDouble getReducible(double[] numbers) + { + Map lookup = new LinkedHashMap<>(); + FunctionalIterable.ofDouble(numbers).reduce(1, (int i, double e) -> {lookup.put(i, e); return i + 1;}); + return new MappingIterable.IntToDouble(unboxInt(lookup.keySet()), lookup::get); + } + + @ParameterizedTest + @MethodSource("getArraysOfInt") + public void testIntToDouble(int[] numbers) + { + ArrayList expected = new ArrayList<>(); + for (int i : numbers) { + expected.add(i + 1.0); + } + IterableArray.OfInt iterable = new IterableArray.OfInt(numbers); + PrimitiveIterable.OfDouble actual = new MappingIterable.IntToDouble(iterable, i -> i + 1.0); + assertIterableEquals(unboxDouble(expected), actual); + } + + @Test + public void testIntToDouble_Null() + { + EmptyIterable.OfInt iterable = EmptyIterable.ofInt(); + assertThrows(NullPointerException.class, () -> new MappingIterable.IntToDouble(null, each -> each)); + assertThrows(NullPointerException.class, () -> new MappingIterable.IntToDouble(iterable, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class IntToInt implements MappingIterableTest, FunctionalPrimitiveIterableTest.OfInt + { + @Override + public MappingIterable.IntToInt getReducible(int[] numbers) + { + Map lookup = new LinkedHashMap<>(); + FunctionalIterable.ofInt(numbers).reduce(1, (int i, int e) -> {lookup.put(i, e); return i + 1;}); + return new MappingIterable.IntToInt(unboxInt(lookup.keySet()), lookup::get); + } + + @ParameterizedTest + @MethodSource("getArraysOfInt") + public void testIntToInt(int[] numbers) + { + ArrayList expected = new ArrayList<>(); + for (int i : numbers) { + expected.add(i + 1); + } + IterableArray.OfInt iterable = new IterableArray.OfInt(numbers); + PrimitiveIterable.OfInt actual = new MappingIterable.IntToInt(iterable, i -> i + 1); + assertIterableEquals(unboxInt(expected), actual); + } + + @Test + public void testIntToInt_Null() + { + EmptyIterable.OfInt iterable = EmptyIterable.ofInt(); + assertThrows(NullPointerException.class, () -> new MappingIterable.IntToInt(null, each -> each)); + assertThrows(NullPointerException.class, () -> new MappingIterable.IntToInt(iterable, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class IntToLong implements MappingIterableTest, FunctionalPrimitiveIterableTest.OfLong + { + @Override + public MappingIterable.IntToLong getReducible(long[] numbers) + { + Map lookup = new LinkedHashMap<>(); + FunctionalIterable.ofLong(numbers).reduce(1, (Integer i, Long e) -> {lookup.put(i, e); return i + 1;}); + return new MappingIterable.IntToLong(unboxInt(lookup.keySet()), lookup::get); + } + + @ParameterizedTest + @MethodSource("getArraysOfInt") + public void testIntToLong(int[] numbers) + { + ArrayList expected = new ArrayList<>(); + for (int i : numbers) { + expected.add((long) i + 1); + } + IterableArray.OfInt iterable = new IterableArray.OfInt(numbers); + PrimitiveIterable.OfLong actual = new MappingIterable.IntToLong(iterable, i -> (long) i + 1); + assertIterableEquals(unboxLong(expected), actual); + } + + @Test + public void testIntToLong_Null() + { + EmptyIterable.OfInt iterable = EmptyIterable.ofInt(); + assertThrows(NullPointerException.class, () -> new MappingIterable.IntToLong(null, each -> (long) each)); + assertThrows(NullPointerException.class, () -> new MappingIterable.IntToLong(iterable, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class LongToObj implements MappingIterableTest, FunctionalIterableTest.Of> + { + @Override + public MappingIterable.LongToObj getReducible(Object[] objects) + { + Map lookup = new LinkedHashMap<>(); + FunctionalIterable.of(objects).reduce(1L, (long l, Object e) -> {lookup.put(l, e); return l + 1;}); + return new MappingIterable.LongToObj<>(unboxLong(lookup.keySet()), lookup::get); + } + + @ParameterizedTest + @MethodSource("getArraysOfLong") + public void testLongToObj(long[] numbers) + { + ArrayList expected = new ArrayList<>(); + for (long l : numbers) { + expected.add(Objects.toString(l)); + } + IterableArray.OfLong iterable = new IterableArray.OfLong(numbers); + Iterable actual = new MappingIterable.LongToObj<>(iterable, Objects::toString); + assertIterableEquals(expected, actual); + } + + @Test + public void testLongToObj_Null() + { + EmptyIterable.OfLong iterable = EmptyIterable.ofLong(); + assertThrows(NullPointerException.class, () -> new MappingIterable.LongToObj<>(null, each -> each)); + assertThrows(NullPointerException.class, () -> new MappingIterable.LongToObj<>(iterable, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class LongToDouble implements MappingIterableTest, FunctionalPrimitiveIterableTest.OfDouble + { + @Override + public MappingIterable.LongToDouble getReducible(double[] numbers) + { + Map lookup = new LinkedHashMap<>(); + FunctionalIterable.ofDouble(numbers).reduce(1L, (long l, double e) -> {lookup.put(l, e); return l + 1;}); + return new MappingIterable.LongToDouble(unboxLong(lookup.keySet()), lookup::get); + } + + @ParameterizedTest + @MethodSource("getArraysOfLong") + public void testLongToDouble(long[] numbers) + { + ArrayList expected = new ArrayList<>(); + for (long l : numbers) { + expected.add(l + 1.0); + } + IterableArray.OfLong iterable = new IterableArray.OfLong(numbers); + PrimitiveIterable.OfDouble actual = new MappingIterable.LongToDouble(iterable, l -> l + 1.0); + assertIterableEquals(unboxDouble(expected), actual); + } + + @Test + public void testLongToDouble_Null() + { + EmptyIterable.OfLong iterable = EmptyIterable.ofLong(); + assertThrows(NullPointerException.class, () -> new MappingIterable.LongToDouble(null, each -> each)); + assertThrows(NullPointerException.class, () -> new MappingIterable.LongToDouble(iterable, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class LongToInt implements MappingIterableTest, FunctionalPrimitiveIterableTest.OfInt + { + @Override + public MappingIterable.LongToInt getReducible(int[] numbers) + { + Map lookup = new LinkedHashMap<>(); + FunctionalIterable.ofInt(numbers).reduce(1L, (Long l, Integer e) -> {lookup.put(l, e); return l + 1;}); + return new MappingIterable.LongToInt(unboxLong(lookup.keySet()), lookup::get); + } + + @ParameterizedTest + @MethodSource("getArraysOfLong") + public void testLongToInt(long[] numbers) + { + ArrayList expected = new ArrayList<>(); + for (long l : numbers) { + expected.add((int) l + 1); + } + IterableArray.OfLong iterable = new IterableArray.OfLong(numbers); + PrimitiveIterable.OfInt actual = new MappingIterable.LongToInt(iterable, l -> (int) l + 1); + assertIterableEquals(unboxInt(expected), actual); + } + + @Test + public void testLongToInt_Null() + { + EmptyIterable.OfLong iterable = EmptyIterable.ofLong(); + assertThrows(NullPointerException.class, () -> new MappingIterable.LongToInt(null, each -> (int) each)); + assertThrows(NullPointerException.class, () -> new MappingIterable.LongToInt(iterable, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class LongToLong implements MappingIterableTest, FunctionalPrimitiveIterableTest.OfLong + { + @Override + public MappingIterable.LongToLong getReducible(long[] numbers) + { + Map lookup = new LinkedHashMap<>(); + FunctionalIterable.ofLong(numbers).reduce(1L, (long l, long e) -> {lookup.put(l, e); return l + 1;}); + return new MappingIterable.LongToLong(unboxLong(lookup.keySet()), lookup::get); + } + + @ParameterizedTest + @MethodSource("getArraysOfLong") + public void testLongToLong(long[] numbers) + { + ArrayList expected = new ArrayList<>(); + for (long l : numbers) { + expected.add(l + 1); + } + IterableArray.OfLong iterable = new IterableArray.OfLong(numbers); + PrimitiveIterable.OfLong actual = new MappingIterable.LongToLong(iterable, l -> l + 1); + assertIterableEquals(unboxLong(expected), actual); + } + + @Test + public void testLongToLong_Null() + { + EmptyIterable.OfLong iterable = EmptyIterable.ofLong(); + assertThrows(NullPointerException.class, () -> new MappingIterable.LongToLong(null, each -> each)); + assertThrows(NullPointerException.class, () -> new MappingIterable.LongToLong(iterable, null)); + } + } +} diff --git a/prism/unit-tests/common/iterable/MappingIteratorTest.java b/prism/unit-tests/common/iterable/MappingIteratorTest.java new file mode 100644 index 0000000000..33b5eaab11 --- /dev/null +++ b/prism/unit-tests/common/iterable/MappingIteratorTest.java @@ -0,0 +1,589 @@ +package common.iterable; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.*; + +import static common.iterable.Assertions.assertIteratorEquals; +import static common.iterable.PrimitiveIterable.*; +import static org.junit.jupiter.api.Assertions.assertThrows; + +interface MappingIteratorTest +{ + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class ObjToObj implements MappingIteratorTest, FunctionalIteratorTest.Of> + { + @Override + public MappingIterator.ObjToObj getReducible(Object[] objects) + { + Map lookup = new LinkedHashMap<>(); + for (int i=0, length=objects.length; i(lookup.keySet().iterator(), lookup::get); + } + + @ParameterizedTest + @MethodSource("getArraysAsArguments") + void testOf(Object[] objects) + { + ArrayList expected = new ArrayList<>(); + for (Object each : objects) { + expected.add(Objects.toString(each)); + } + Iterator iterator = new ArrayIterator.Of<>(objects); + Iterator actual = new MappingIterator.ObjToObj<>(iterator, Objects::toString); + assertIteratorEquals(expected.iterator(), actual); + } + + @Test + public void testOf_Null() + { + Iterator iterator = EmptyIterator.of(); + assertThrows(NullPointerException.class, () -> new MappingIterator.ObjToObj<>(null, each -> each)); + assertThrows(NullPointerException.class, () -> new MappingIterator.ObjToObj<>(iterator, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class ObjToDouble implements MappingIteratorTest, FunctionalPrimitiveIteratorTest.OfDouble> + { + @Override + public MappingIterator.ObjToDouble getReducible(double[] numbers) + { + List boxed = FunctionalIterator.ofDouble(numbers).collect(new ArrayList<>()); + return new MappingIterator.ObjToDouble<>(boxed.iterator(), Double::doubleValue); + } + + @ParameterizedTest + @MethodSource("getArraysOfDouble") + public void testObjToDouble(double[] numbers) + { + ArrayList expected = new ArrayList<>(); + for (double d : numbers) { + expected.add(d); + } + Iterator iterator = expected.iterator(); + FunctionalPrimitiveIterator.OfDouble actual = new MappingIterator.ObjToDouble<>(iterator, each -> each); + assertIteratorEquals(unboxDouble(expected.iterator()), actual); + } + + @Test + public void testObjToDouble_Null() + { + Iterator iterator = EmptyIterator.of(); + assertThrows(NullPointerException.class, () -> new MappingIterator.ObjToDouble(null, each -> each)); + assertThrows(NullPointerException.class, () -> new MappingIterator.ObjToDouble<>(iterator, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class ObjToInt implements MappingIteratorTest, FunctionalPrimitiveIteratorTest.OfInt> + { + @Override + public MappingIterator.ObjToInt getReducible(int[] numbers) + { + List boxed = FunctionalIterator.ofInt(numbers).collect(new ArrayList<>()); + return new MappingIterator.ObjToInt<>(boxed.iterator(), Integer::intValue); + } + + @ParameterizedTest + @MethodSource("getArraysOfInt") + public void testObjToInt(int[] numbers) + { + ArrayList expected = new ArrayList<>(); + for (int i : numbers) { + expected.add(i); + } + Iterator iterator = expected.iterator(); + FunctionalPrimitiveIterator.OfInt actual = new MappingIterator.ObjToInt<>(iterator, each -> each); + assertIteratorEquals(unboxInt(expected.iterator()), actual); + } + + @Test + public void testObjToInt_Null() + { + Iterator iterator = EmptyIterator.of(); + assertThrows(NullPointerException.class, () -> new MappingIterator.ObjToInt(null, each -> each)); + assertThrows(NullPointerException.class, () -> new MappingIterator.ObjToInt<>(iterator, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class ObjToLong implements MappingIteratorTest, FunctionalPrimitiveIteratorTest.OfLong> + { + @Override + public MappingIterator.ObjToLong getReducible(long[] numbers) + { + List boxed = FunctionalIterator.ofLong(numbers).collect(new ArrayList<>()); + return new MappingIterator.ObjToLong<>(boxed.iterator(), Long::longValue); + } + + @ParameterizedTest + @MethodSource("getArraysOfLong") + public void testObjToLong(long[] numbers) + { + ArrayList expected = new ArrayList<>(); + for (long l : numbers) { + expected.add(l); + } + Iterator iterator = expected.iterator(); + FunctionalPrimitiveIterator.OfLong actual = new MappingIterator.ObjToLong<>(iterator, each -> each); + assertIteratorEquals(unboxLong(expected.iterator()), actual); + } + + @Test + public void testObjToLong_Null() + { + Iterator iterator = EmptyIterator.of(); + assertThrows(NullPointerException.class, () -> new MappingIterator.ObjToLong(null, each -> each)); + assertThrows(NullPointerException.class, () -> new MappingIterator.ObjToLong<>(iterator, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class DoubleToObj implements MappingIteratorTest, FunctionalIteratorTest.Of> + { + @Override + public MappingIterator.DoubleToObj getReducible(Object[] objects) + { + Map lookup = new LinkedHashMap<>(); + FunctionalIterator.of(objects).reduce(1.5, (d, e) -> {lookup.put(d, e); return d + 1;}); + return new MappingIterator.DoubleToObj<>(unboxDouble(lookup.keySet().iterator()), lookup::get); + } + + @ParameterizedTest + @MethodSource("getArraysOfDouble") + public void testDoubleToObj(double[] numbers) + { + ArrayList expected = new ArrayList<>(); + for (double d : numbers) { + expected.add(Objects.toString(d)); + } + ArrayIterator.OfDouble iterator = new ArrayIterator.OfDouble(numbers); + Iterator actual = new MappingIterator.DoubleToObj<>(iterator, Objects::toString); + assertIteratorEquals(expected.iterator(), actual); + } + + @Test + public void testDoubleToObj_Null() + { + PrimitiveIterator.OfDouble iterator = EmptyIterator.ofDouble(); + assertThrows(NullPointerException.class, () -> new MappingIterator.DoubleToObj<>(null, each -> each)); + assertThrows(NullPointerException.class, () -> new MappingIterator.DoubleToObj<>(iterator, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class DoubleToDouble implements MappingIteratorTest, FunctionalPrimitiveIteratorTest.OfDouble + { + @Override + public MappingIterator.DoubleToDouble getReducible(double[] numbers) + { + Map lookup = new LinkedHashMap<>(); + FunctionalIterator.ofDouble(numbers).reduce(1.5, (double d, double e) -> {lookup.put(d, e); return d + 1;}); + return new MappingIterator.DoubleToDouble(unboxDouble(lookup.keySet().iterator()), lookup::get); + } + + @ParameterizedTest + @MethodSource("getArraysOfDouble") + public void testDoubleToDouble(double[] numbers) + { + ArrayList expected = new ArrayList<>(); + for (double d : numbers) { + expected.add(d + 1.0); + } + ArrayIterator.OfDouble iterator = new ArrayIterator.OfDouble(numbers); + PrimitiveIterator.OfDouble actual = new MappingIterator.DoubleToDouble(iterator, d -> d + 1.0); + assertIteratorEquals(expected.iterator(), actual); + } + + @Test + public void testDoubleToDouble_Null() + { + PrimitiveIterator.OfDouble iterator = EmptyIterator.ofDouble(); + assertThrows(NullPointerException.class, () -> new MappingIterator.DoubleToDouble(null, each -> each)); + assertThrows(NullPointerException.class, () -> new MappingIterator.DoubleToDouble(iterator, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class DoubleToInt implements MappingIteratorTest, FunctionalPrimitiveIteratorTest.OfInt + { + @Override + public MappingIterator.DoubleToInt getReducible(int[] numbers) + { + Map lookup = new LinkedHashMap<>(); + FunctionalIterator.ofInt(numbers).reduce(1.5, (Double d, Integer e) -> {lookup.put(d, e); return d + 1;}); + return new MappingIterator.DoubleToInt(unboxDouble(lookup.keySet().iterator()), lookup::get); + } + + @ParameterizedTest + @MethodSource("getArraysOfDouble") + public void testDoubleToInt(double[] numbers) + { + ArrayList expected = new ArrayList<>(); + for (double d : numbers) { + expected.add((int) d + 1); + } + ArrayIterator.OfDouble iterator = new ArrayIterator.OfDouble(numbers); + PrimitiveIterator.OfInt actual = new MappingIterator.DoubleToInt(iterator, d -> (int) d + 1); + assertIteratorEquals(expected.iterator(), actual); + } + + @Test + public void testDoubleToInt_Null() + { + PrimitiveIterator.OfDouble iterator = EmptyIterator.ofDouble(); + assertThrows(NullPointerException.class, () -> new MappingIterator.DoubleToInt(null, each -> (int) each)); + assertThrows(NullPointerException.class, () -> new MappingIterator.DoubleToInt(iterator, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class DoubleToLong implements MappingIteratorTest, FunctionalPrimitiveIteratorTest.OfLong + { + @Override + public MappingIterator.DoubleToLong getReducible(long[] numbers) + { + Map lookup = new LinkedHashMap<>(); + FunctionalIterator.ofLong(numbers).reduce(1.5, (double d, long e) -> {lookup.put(d, e); return d + 1;}); + return new MappingIterator.DoubleToLong(unboxDouble(lookup.keySet().iterator()), lookup::get); + } + + @ParameterizedTest + @MethodSource("getArraysOfDouble") + public void testDoubleToLong(double[] numbers) + { + ArrayList expected = new ArrayList<>(); + for (double d : numbers) { + expected.add((long) d + 1); + } + ArrayIterator.OfDouble iterator = new ArrayIterator.OfDouble(numbers); + PrimitiveIterator.OfLong actual = new MappingIterator.DoubleToLong(iterator, d -> (long) d + 1); + assertIteratorEquals(expected.iterator(), actual); + } + + @Test + public void testDoubleToLong_Null() + { + PrimitiveIterator.OfDouble iterator = EmptyIterator.ofDouble(); + assertThrows(NullPointerException.class, () -> new MappingIterator.DoubleToLong(null, each -> (long) each)); + assertThrows(NullPointerException.class, () -> new MappingIterator.DoubleToLong(iterator, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class IntToObj implements MappingIteratorTest, FunctionalIteratorTest.Of> + { + @Override + public MappingIterator.IntToObj getReducible(Object[] objects) + { + Map lookup = new LinkedHashMap<>(); + FunctionalIterator.of(objects).reduce(1, (int i, Object e) -> {lookup.put(i, e); return i + 1;}); + return new MappingIterator.IntToObj<>(unboxInt(lookup.keySet().iterator()), lookup::get); + } + + @ParameterizedTest + @MethodSource("getArraysOfInt") + public void testIntToObj(int[] numbers) + { + ArrayList expected = new ArrayList<>(); + for (int i : numbers) { + expected.add(Objects.toString(i)); + } + ArrayIterator.OfInt iterator = new ArrayIterator.OfInt(numbers); + Iterator actual = new MappingIterator.IntToObj<>(iterator, Objects::toString); + assertIteratorEquals(expected.iterator(), actual); + } + + @Test + public void testIntToObj_Null() + { + PrimitiveIterator.OfInt iterator = EmptyIterator.ofInt(); + assertThrows(NullPointerException.class, () -> new MappingIterator.IntToObj<>(null, each -> each)); + assertThrows(NullPointerException.class, () -> new MappingIterator.IntToObj<>(iterator, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class IntToDouble implements MappingIteratorTest, FunctionalPrimitiveIteratorTest.OfDouble + { + @Override + public MappingIterator.IntToDouble getReducible(double[] numbers) + { + Map lookup = new LinkedHashMap<>(); + FunctionalIterator.ofDouble(numbers).reduce(1, (int i, double e) -> {lookup.put(i, e); return i + 1;}); + return new MappingIterator.IntToDouble(unboxInt(lookup.keySet().iterator()), lookup::get); + } + + @ParameterizedTest + @MethodSource("getArraysOfInt") + public void testIntToDouble(int[] numbers) + { + ArrayList expected = new ArrayList<>(); + for (int i : numbers) { + expected.add(i + 1.0); + } + ArrayIterator.OfInt iterator = new ArrayIterator.OfInt(numbers); + PrimitiveIterator.OfDouble actual = new MappingIterator.IntToDouble(iterator, i -> i + 1.0); + assertIteratorEquals(expected.iterator(), actual); + } + + @Test + public void testIntToDouble_Null() + { + PrimitiveIterator.OfInt iterator = EmptyIterator.ofInt(); + assertThrows(NullPointerException.class, () -> new MappingIterator.IntToDouble(null, each -> each)); + assertThrows(NullPointerException.class, () -> new MappingIterator.IntToDouble(iterator, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class IntToInt implements MappingIteratorTest, FunctionalPrimitiveIteratorTest.OfInt + { + @Override + public MappingIterator.IntToInt getReducible(int[] numbers) + { + Map lookup = new LinkedHashMap<>(); + FunctionalIterator.ofInt(numbers).reduce(1, (int i, int e) -> {lookup.put(i, e); return i + 1;}); + return new MappingIterator.IntToInt(unboxInt(lookup.keySet().iterator()), lookup::get); + } + + @ParameterizedTest + @MethodSource("getArraysOfInt") + public void testIntToInt(int[] numbers) + { + ArrayList expected = new ArrayList<>(); + for (int i : numbers) { + expected.add(i + 1); + } + ArrayIterator.OfInt iterator = new ArrayIterator.OfInt(numbers); + PrimitiveIterator.OfInt actual = new MappingIterator.IntToInt(iterator, i -> i + 1); + assertIteratorEquals(expected.iterator(), actual); + } + + @Test + public void testIntToInt_Null() + { + PrimitiveIterator.OfInt iterator = EmptyIterator.ofInt(); + assertThrows(NullPointerException.class, () -> new MappingIterator.IntToInt(null, each -> each)); + assertThrows(NullPointerException.class, () -> new MappingIterator.IntToInt(iterator, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class IntToLong implements MappingIteratorTest, FunctionalPrimitiveIteratorTest.OfLong + { + @Override + public MappingIterator.IntToLong getReducible(long[] numbers) + { + Map lookup = new LinkedHashMap<>(); + FunctionalIterator.ofLong(numbers).reduce(1, (Integer i, Long e) -> {lookup.put(i, e); return i + 1;}); + return new MappingIterator.IntToLong(unboxInt(lookup.keySet().iterator()), lookup::get); + } + + @ParameterizedTest + @MethodSource("getArraysOfInt") + public void testIntToLong(int[] numbers) + { + ArrayList expected = new ArrayList<>(); + for (int i : numbers) { + expected.add((long) i + 1); + } + ArrayIterator.OfInt iterator = new ArrayIterator.OfInt(numbers); + PrimitiveIterator.OfLong actual = new MappingIterator.IntToLong(iterator, i -> (long) i + 1); + assertIteratorEquals(expected.iterator(), actual); + } + + @Test + public void testIntToLong_Null() + { + PrimitiveIterator.OfInt iterator = EmptyIterator.ofInt(); + assertThrows(NullPointerException.class, () -> new MappingIterator.IntToLong(null, each -> (long) each)); + assertThrows(NullPointerException.class, () -> new MappingIterator.IntToLong(iterator, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class LongToObj implements MappingIteratorTest, FunctionalIteratorTest.Of> + { + @Override + public MappingIterator.LongToObj getReducible(Object[] objects) + { + Map lookup = new LinkedHashMap<>(); + FunctionalIterator.of(objects).reduce(1L, (long l, Object e) -> {lookup.put(l, e); return l + 1;}); + return new MappingIterator.LongToObj<>(unboxLong(lookup.keySet().iterator()), lookup::get); + } + + @ParameterizedTest + @MethodSource("getArraysOfLong") + public void testLongToObj(long[] numbers) + { + ArrayList expected = new ArrayList<>(); + for (long l : numbers) { + expected.add(Objects.toString(l)); + } + ArrayIterator.OfLong iterator = new ArrayIterator.OfLong(numbers); + Iterator actual = new MappingIterator.LongToObj<>(iterator, Objects::toString); + assertIteratorEquals(expected.iterator(), actual); + } + + @Test + public void testLongToObj_Null() + { + PrimitiveIterator.OfLong iterator = EmptyIterator.ofLong(); + assertThrows(NullPointerException.class, () -> new MappingIterator.LongToObj<>(null, each -> each)); + assertThrows(NullPointerException.class, () -> new MappingIterator.LongToObj<>(iterator, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class LongToDouble implements MappingIteratorTest, FunctionalPrimitiveIteratorTest.OfDouble + { + @Override + public MappingIterator.LongToDouble getReducible(double[] numbers) + { + Map lookup = new LinkedHashMap<>(); + FunctionalIterator.ofDouble(numbers).reduce(1L, (long l, double e) -> {lookup.put(l, e); return l + 1;}); + return new MappingIterator.LongToDouble(unboxLong(lookup.keySet().iterator()), lookup::get); + } + + @ParameterizedTest + @MethodSource("getArraysOfLong") + public void testLongToDouble(long[] numbers) + { + ArrayList expected = new ArrayList<>(); + for (long l : numbers) { + expected.add(l + 1.0); + } + ArrayIterator.OfLong iterator = new ArrayIterator.OfLong(numbers); + PrimitiveIterator.OfDouble actual = new MappingIterator.LongToDouble(iterator, l -> l + 1.0); + assertIteratorEquals(expected.iterator(), actual); + } + + @Test + public void testLongToDouble_Null() + { + PrimitiveIterator.OfLong iterator = EmptyIterator.ofLong(); + assertThrows(NullPointerException.class, () -> new MappingIterator.LongToDouble(null, each -> each)); + assertThrows(NullPointerException.class, () -> new MappingIterator.LongToDouble(iterator, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class LongToInt implements MappingIteratorTest, FunctionalPrimitiveIteratorTest.OfInt + { + @Override + public MappingIterator.LongToInt getReducible(int[] numbers) + { + Map lookup = new LinkedHashMap<>(); + FunctionalIterator.ofInt(numbers).reduce(1L, (Long l, Integer e) -> {lookup.put(l, e); return l + 1;}); + return new MappingIterator.LongToInt(unboxLong(lookup.keySet().iterator()), lookup::get); + } + + @ParameterizedTest + @MethodSource("getArraysOfLong") + public void testLongToInt(long[] numbers) + { + ArrayList expected = new ArrayList<>(); + for (long l : numbers) { + expected.add((int) l + 1); + } + ArrayIterator.OfLong iterator = new ArrayIterator.OfLong(numbers); + PrimitiveIterator.OfInt actual = new MappingIterator.LongToInt(iterator, l -> (int) l + 1); + assertIteratorEquals(expected.iterator(), actual); + } + + @Test + public void testLongToInt_Null() + { + PrimitiveIterator.OfLong iterator = EmptyIterator.ofLong(); + assertThrows(NullPointerException.class, () -> new MappingIterator.LongToInt(null, each -> (int) each)); + assertThrows(NullPointerException.class, () -> new MappingIterator.LongToInt(iterator, null)); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class LongToLong implements MappingIteratorTest, FunctionalPrimitiveIteratorTest.OfLong + { + @Override + public MappingIterator.LongToLong getReducible(long[] numbers) + { + Map lookup = new LinkedHashMap<>(); + FunctionalIterator.ofLong(numbers).reduce(1L, (long l, long e) -> {lookup.put(l, e); return l + 1;}); + return new MappingIterator.LongToLong(unboxLong(lookup.keySet().iterator()), lookup::get); + } + + @ParameterizedTest + @MethodSource("getArraysOfLong") + public void testLongToLong(long[] numbers) + { + ArrayList expected = new ArrayList<>(); + for (long l : numbers) { + expected.add(l + 1); + } + ArrayIterator.OfLong iterator = new ArrayIterator.OfLong(numbers); + PrimitiveIterator.OfLong actual = new MappingIterator.LongToLong(iterator, l -> l + 1); + assertIteratorEquals(expected.iterator(), actual); + } + + @Test + public void testLongToLong_Null() + { + PrimitiveIterator.OfLong iterator = EmptyIterator.ofLong(); + assertThrows(NullPointerException.class, () -> new MappingIterator.LongToLong(null, each -> each)); + assertThrows(NullPointerException.class, () -> new MappingIterator.LongToLong(iterator, null)); + } + } +} diff --git a/prism/unit-tests/common/iterable/PrimitiveIterableTest.java b/prism/unit-tests/common/iterable/PrimitiveIterableTest.java new file mode 100644 index 0000000000..d5947038d5 --- /dev/null +++ b/prism/unit-tests/common/iterable/PrimitiveIterableTest.java @@ -0,0 +1,117 @@ +package common.iterable; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.PrimitiveIterator; + +import static common.iterable.Assertions.assertIteratorEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class PrimitiveIterableTest +{ + @Test + public void testUnboxDoubleIterable() + { + Iterable numbers = List.of(0.0, 1.0, 2.0); + PrimitiveIterable.OfDouble actual = PrimitiveIterable.unboxDouble(numbers); + PrimitiveIterator.OfDouble expected = PrimitiveIterable.unboxDouble(numbers.iterator()); + assertIteratorEquals(expected, actual.iterator()); + } + + @Test + public void testUnboxDoubleIterator() + { + Iterable numbers = List.of(0.0, 1.0, 2.0); + PrimitiveIterator.OfDouble actual = PrimitiveIterable.unboxDouble(numbers).iterator(); + for (double d : numbers) { + assertEquals(d, actual.nextDouble()); + } + } + + @Test + public void testUnboxDoubleIterator_NullValues() + { + Iterable numbers = Arrays.asList(new Double[] {null}); + PrimitiveIterator.OfDouble actual = PrimitiveIterable.unboxDouble(numbers).iterator(); + assertThrows(NullPointerException.class, actual::nextDouble); + } + + @Test + public void testUnboxDouble_Null() + { + assertThrows(NullPointerException.class, () -> PrimitiveIterable.unboxDouble((Iterator) null)); + assertThrows(NullPointerException.class, () -> PrimitiveIterable.unboxDouble((Iterable) null)); + } + + @Test + public void testUnboxIntIterable() + { + Iterable numbers = List.of(0, 1, 2); + PrimitiveIterable.OfInt actual = PrimitiveIterable.unboxInt(numbers); + PrimitiveIterator.OfInt expected = PrimitiveIterable.unboxInt(numbers.iterator()); + assertIteratorEquals(expected, actual.iterator()); + } + + @Test + public void testUnboxIntIterator() + { + Iterable numbers = List.of(0, 1, 2); + PrimitiveIterator.OfInt actual = PrimitiveIterable.unboxInt(numbers).iterator(); + for (int i : numbers) { + assertEquals(i, actual.nextInt()); + } + } + + @Test + public void testUnboxIntIterator_NullValues() + { + Iterable numbers = Arrays.asList(new Integer[] {null}); + PrimitiveIterator.OfInt actual = PrimitiveIterable.unboxInt(numbers).iterator(); + assertThrows(NullPointerException.class, actual::nextInt); + } + + @Test + public void testUnboxInt_Null() + { + assertThrows(NullPointerException.class, () -> PrimitiveIterable.unboxInt((Iterator) null)); + assertThrows(NullPointerException.class, () -> PrimitiveIterable.unboxInt((Iterable) null)); + } + + @Test + public void testLongDoubleIterable() + { + Iterable numbers = List.of(0L, 1L, 2L); + PrimitiveIterable.OfLong actual = PrimitiveIterable.unboxLong(numbers); + PrimitiveIterator.OfLong expected = PrimitiveIterable.unboxLong(numbers.iterator()); + assertIteratorEquals(expected, actual.iterator()); + } + + @Test + public void testUnboxLongIterator() + { + Iterable numbers = List.of(0L, 1L, 2L); + PrimitiveIterator.OfLong actual = PrimitiveIterable.unboxLong(numbers).iterator(); + for (long l : numbers) { + assertEquals(l, actual.nextLong()); + } + } + + @Test + public void testUnboxLongIterator_NullValues() + { + Iterable numbers = Arrays.asList(new Long[] {null}); + PrimitiveIterator.OfLong actual = PrimitiveIterable.unboxLong(numbers).iterator(); + assertThrows(NullPointerException.class, actual::nextLong); + } + + @Test + public void testUnboxLong_Null() + { + assertThrows(NullPointerException.class, () -> PrimitiveIterable.unboxLong((Iterator) null)); + assertThrows(NullPointerException.class, () -> PrimitiveIterable.unboxLong((Iterable) null)); + } +} diff --git a/prism/unit-tests/common/iterable/PrimitiveReducibleTest.java b/prism/unit-tests/common/iterable/PrimitiveReducibleTest.java new file mode 100644 index 0000000000..48da47f616 --- /dev/null +++ b/prism/unit-tests/common/iterable/PrimitiveReducibleTest.java @@ -0,0 +1,1889 @@ +package common.iterable; + +import common.functions.DoubleLongToDoubleFunction; +import common.functions.IntDoubleToIntFunction; +import common.functions.IntLongToIntFunction; +import common.functions.LongDoubleToLongFunction; +import common.functions.ObjDoubleFunction; +import common.functions.ObjIntFunction; +import common.functions.ObjLongFunction; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.*; +import java.util.function.*; +import java.util.stream.Stream; + +import static common.iterable.Assertions.assertIterableEquals; +import static common.iterable.Assertions.*; +import static common.iterable.PrimitiveIterable.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertIterableEquals; + +public interface PrimitiveReducibleTest +{ + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + interface OfDouble> extends ReducibleTest + { + @Override + default Stream> getDuplicatesReducibles() + { + return getDuplicatesArraysOfDouble().map(args-> () -> getReducible(args)); + } + + @Override + default Stream> getEmptyReducibles() + { + return getEmptyArraysOfDouble().map(args-> () -> getReducible(args)); + } + + @Override + default Stream> getSingletonReducibles() + { + return getSingletonArraysOfDouble().map(args-> () -> getReducible(args)); + } + + @Override + default Stream> getMultitonReducibles() + { + return getMultitonArraysOfDouble().map(args-> () -> getReducible(args)); + } + + T getReducible(double[] arguments); + + @Override + default Iterable getExcluded(T reducible) + { + List candidates = getExclusionListOfDouble(); + reducible.forEach((double d) -> { + candidates.remove(d); + if (d == 0.0) { + candidates.remove(-1 * d); + } + }); + List excluded = new ArrayList<>(); + excluded.addAll(getUniqueObjects()); + excluded.addAll(candidates); + return excluded; + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testCollectDoubleArray(Supplier supplier) + { + int n = (int) supplier.get().count(); + double[] expected = new double[n]; + Range.RangeIterator index = new Range(n).iterator(); + supplier.get().forEach((double d) -> expected[index.nextInt()] = d); + double[] actual = supplier.get().collect(new double[n]); + assertArrayEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testCollectDoubleArrayOffset(Supplier supplier) + { + int n = (int) supplier.get().count(), offset = 2, tail = 3; + double[] expected = new double[offset + n + tail]; + Range.RangeIterator index = new Range(offset, offset + n).iterator(); + supplier.get().forEach((double d) -> expected[index.nextInt()] = d); + double[] actual = supplier.get().collect(new double[offset + n + tail], offset); + assertArrayEquals(expected, actual); + } + + @Test + default void testCollectOfDouble_Null() + { + PrimitiveReducible.OfDouble reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.collect((double[]) null)); + assertThrows(NullPointerException.class, () -> reducible.collect((double[]) null, 0)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testCollectAndCountDoubleArray(Supplier supplier) + { + int n = (int) supplier.get().count(), tail = 3; + double[] expected = new double[n + tail]; + Range.RangeIterator index = new Range(n).iterator(); + supplier.get().forEach((double d) -> expected[index.nextInt()] = d); + double[] actual = new double[n + tail]; + long count = supplier.get().collectAndCount(actual); + assertEquals(n, count); + assertArrayEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testCollectAndCountDoubleArrayOffset(Supplier supplier) + { + int n = (int) supplier.get().count(), offset = 2, tail = 3; + double[] expected = new double[offset + n + tail]; + Range.RangeIterator index = new Range(offset, offset + n).iterator(); + supplier.get().forEach((double d) -> expected[index.nextInt()] = d); + double[] actual = new double[offset + n + tail]; + long count = supplier.get().collectAndCount(actual, offset); + assertEquals(n, count); + assertArrayEquals(expected, actual); + } + + @Test + default void testCollectAndCountOfDouble_Null() + { + PrimitiveReducible.OfDouble reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.collectAndCount((double[]) null)); + assertThrows(NullPointerException.class, () -> reducible.collectAndCount((double[]) null, 0)); + } + + @ParameterizedTest + @MethodSource({"getReducibles", "getDuplicatesReducibles"}) + @Override + default void testCollectDistinct(Supplier supplier) + { + Set expected = new HashSet<>(); + supplier.get().forEach((double d) -> { + if (!expected.contains(d) && !(d == 0.0 && expected.contains(-1.0 * d))) { + expected.add(d); + } + }); + List actual = supplier.get().collectDistinct().collect(new ArrayList<>()); + assertTrue(expected.containsAll(actual), "actual =< expected"); + assertTrue(actual.containsAll(expected), "actual >= expected"); + + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testFilterDouble(Supplier supplier) + { + ArrayList expected = new ArrayList<>(); + supplier.get().forEach((double d) -> { + if (d % 2 == 0) { + expected.add(d); + } + }); + PrimitiveReducible.OfDouble actual = supplier.get().filter((double d) -> d % 2 == 0); + assertIterableEquals(unboxDouble(expected), unboxDouble(actual.collect(new ArrayList<>()))); + } + + @Test + default void testFilterOfDouble_Null() + { + PrimitiveReducible.OfDouble reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.filter((DoublePredicate) null)); + } + + void testFlatMapDoubleToObj(Supplier supplier); + + void testFlatMapDoubleToDouble(Supplier supplier); + + void testFlatMapDoubleToInt(Supplier supplier); + + void testFlatMapDoubleToLong(Supplier supplier); + + void testFlatMapDoubleToNull(Supplier supplier); + + void testFlatMapOfDouble_Null(); + + @ParameterizedTest + @MethodSource("getReducibles") + default void testMapDoubleToObj(Supplier supplier) + { + String prefix = "Item: "; + List expected = new ArrayList<>(); + supplier.get().forEach((double d) -> expected.add(prefix + d)); + Reducible actual = supplier.get().map((double d) -> prefix + d); + assertIterableEquals(expected, actual.collect(new ArrayList<>())); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testMapDoubleToDouble(Supplier supplier) + { + Range range = new Range((int) supplier.get().count()); + PrimitiveIterable.OfDouble expected = unboxDouble(range.map((int i) -> (double) i)); + Range.RangeIterator index = range.iterator(); + PrimitiveReducible.OfDouble actual = supplier.get().mapToDouble((double d) -> index.next()); + assertIterableEquals(expected, unboxDouble(actual.collect(new ArrayList<>()))); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testMapDoubleToInt(Supplier supplier) + { + Range expected = new Range((int) supplier.get().count()); + Range.RangeIterator index = expected.iterator(); + PrimitiveReducible.OfInt actual = supplier.get().mapToInt((double d) -> index.next()); + assertIterableEquals(expected, unboxInt(actual.collect(new ArrayList<>()))); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testMapDoubleToLong(Supplier supplier) + { + Range range = new Range((int) supplier.get().count()); + PrimitiveIterable.OfLong expected = unboxLong(range.map((int i) -> (long) i)); + Range.RangeIterator index = range.iterator(); + PrimitiveReducible.OfLong actual = supplier.get().mapToLong((double d) -> index.next()); + assertIterableEquals(expected, unboxLong(actual.collect(new ArrayList<>()))); + } + + @Test + default void testMapOfDouble_Null() + { + PrimitiveReducible.OfDouble reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.map((DoubleFunction) null)); + assertThrows(NullPointerException.class, () -> reducible.mapToDouble((DoubleUnaryOperator) null)); + assertThrows(NullPointerException.class, () -> reducible.mapToInt((DoubleToIntFunction) null)); + assertThrows(NullPointerException.class, () -> reducible.mapToLong((DoubleToLongFunction) null)); + } + + void testForEachDoubleConsumer(Supplier supplier); + + @Test + default void testForEachDoubleConsumer_Null() + { + PrimitiveReducible.OfDouble reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.forEach((DoubleConsumer) null)); + } + + @ParameterizedTest + @MethodSource("getEmptyReducibles") + default void testReduceDoubleBinaryOperator_Empty(Supplier supplier) + { + DoubleBinaryOperator dummy = (res, each) -> Double.MIN_VALUE; + OptionalDouble actual = supplier.get().reduce(dummy); + assertEquals(OptionalDouble.empty(), actual); + } + + @ParameterizedTest + @MethodSource("getSingletonReducibles") + default void testReduceDoubleBinaryOperator_Singleton(Supplier supplier) + { + DoubleBinaryOperator dummy = (res, each) -> Double.MIN_VALUE; + double expected = supplier.get().detect((double d) -> true); + OptionalDouble actual = supplier.get().reduce(dummy); + assertTrue(actual.isPresent()); + assertEquals(expected, actual.getAsDouble()); + } + + @ParameterizedTest + @MethodSource("getMultitonReducibles") + default void testReduceDoubleBinaryOperator_Multiton(Supplier supplier) + { + List expected = supplier.get().collect(new ArrayList<>()); + List actual = new ArrayList<>(); + double probe = -31; // "unique" value + DoubleBinaryOperator collect = (res, each) -> { + if (actual.isEmpty()) { + actual.add(res); + actual.add(each); + return probe; + } else { + actual.add(each); + return res; + } + }; + OptionalDouble result = supplier.get().reduce(collect); + assertTrue(result.isPresent()); + assertEquals(probe, result.getAsDouble()); + assertIterableEquals(unboxDouble(expected), unboxDouble(actual)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testReduceIntDoubleToIntFunction(Supplier supplier) + { + List expected = supplier.get().collect(new ArrayList<>()); + int init = Integer.MIN_VALUE; + List actual = new ArrayList<>(); + IntDoubleToIntFunction collect = (res, each) -> {actual.add(each); return res;}; + int result = supplier.get().reduce(init, collect); + assertEquals(init, result); + assertIterableEquals(unboxDouble(expected), unboxDouble(actual)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testReduceLongDoubleToLongFunction(Supplier supplier) + { + List expected = supplier.get().collect(new ArrayList<>()); + long init = Long.MIN_VALUE; + List actual = new ArrayList<>(); + LongDoubleToLongFunction collect = (res, each) -> {actual.add(each); return res;}; + long result = supplier.get().reduce(init, collect); + assertEquals(init, result); + assertIterableEquals(unboxDouble(expected), unboxDouble(actual)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testReduceObjDouble(Supplier supplier) + { + List expected = supplier.get().collect(new ArrayList<>()); + ObjDoubleFunction, List> collect = (seq, each) -> {seq.add(each); return seq;}; + List actual = supplier.get().reduce(new ArrayList<>(), collect); + assertIterableEquals(unboxDouble(expected), unboxDouble(actual)); + assertDoesNotThrow(() -> supplier.get().reduce(null, (Object obj, double each) -> null)); + } + + @Test + default void testReduceOfDouble_Null() + { + PrimitiveReducible.OfDouble reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.reduce((DoubleBinaryOperator) null)); + assertThrows(NullPointerException.class, () -> reducible.reduce(new Object(), (ObjDoubleFunction) null)); + assertThrows(NullPointerException.class, () -> reducible.reduce(0.0, (DoubleBinaryOperator) null)); + assertThrows(NullPointerException.class, () -> reducible.reduce(0, (IntDoubleToIntFunction) null)); + assertThrows(NullPointerException.class, () -> reducible.reduce(0L, (LongDoubleToLongFunction) null)); + } + + void testConcatTypes(); + + @ParameterizedTest + @MethodSource({"getReducibles", "getDuplicatesReducibles"}) + @Override + default void testDistinct(Supplier supplier) + { + List expected = new ArrayList<>(); + supplier.get().forEach((double d) -> { + if (!expected.contains(d) && !(d == 0.0 && expected.contains(-1.0 * d))) { + expected.add(d); + } + }); + List actual = supplier.get().distinct().collect(new ArrayList<>()); + assertEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource({"getReducibles", "getDuplicatesReducibles"}) + default void testDedupe(Supplier supplier) + { + List expected = new ArrayList<>(); + supplier.get().forEach((double d) -> { + if (expected.isEmpty()) { + expected.add(d); + } else { + double last = expected.get(expected.size() - 1); + if (last != d && !(Double.isNaN(last) && Double.isNaN(d))) { + expected.add(d); + } + } + }); + List actual = supplier.get().dedupe().collect(new ArrayList<>()); + assertEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource({"getSingletonReducibles", "getMultitonReducibles"}) + default void testAllMatchDoublePredicate(Supplier supplier) + { + // match all elements + assertTrue(supplier.get().allMatch((double each) -> true), "Expected allMatch() == true"); + // match not all elements + DoublePredicate matchNotAll = new DoublePredicate() { + // match: no element if singleton, otherwise every odd element + boolean flag = supplier.get().count() == 1; + @Override + public boolean test(double d) + { + flag = !flag; + return flag; + } + }; + assertFalse(supplier.get().allMatch(matchNotAll), "Expected allMatch() == false"); + } + + @ParameterizedTest + @MethodSource("getEmptyReducibles") + default void testAllMatchDoublePredicate_Empty(Supplier supplier) + { + PrimitiveReducible.OfDouble reducible = supplier.get(); + assertTrue(reducible.allMatch((double each) -> false), "Exepted allMatch() == true if iterator is empty"); + } + + @Test + default void testAllMatchDoublePredicate_Null() + { + PrimitiveReducible.OfDouble reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.allMatch((DoublePredicate) null)); + } + + @ParameterizedTest + @MethodSource({"getSingletonReducibles", "getMultitonReducibles"}) + default void testAnyMatchDoublePredicate(Supplier supplier) + { + // match no element + assertFalse(supplier.get().anyMatch((double each) -> false), "Expected anyMatch() == false"); + // match some elements + DoublePredicate matchSome = new DoublePredicate() { + // match: first element if singleton, otherwise every even element + boolean flag = supplier.get().count() > 1; + @Override + public boolean test(double d) + { + flag = !flag; + return flag; + } + }; + assertTrue(supplier.get().anyMatch(matchSome), "Expected anyMatch() == true"); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testAnyMatchDoublePredicate_Empty(Supplier supplier) + { + PrimitiveReducible.OfDouble reducible = supplier.get(); + assertTrue(reducible.allMatch((double each) -> true), "Exepted anyMatch() == false if iterator is empty"); + } + + @Test + default void testAnyMatchDoublePredicate_Null() + { + PrimitiveReducible.OfDouble reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.anyMatch((DoublePredicate) null)); + } + + @ParameterizedTest + @MethodSource({"getSingletonReducibles", "getMultitonReducibles"}) + default void testNoneMatchDoublePredicate(Supplier supplier) + { + // match no element + assertTrue(supplier.get().noneMatch((double each) -> false), "Expected noneMatch() == true"); + // match some elements + DoublePredicate matchSome = new DoublePredicate() { + // match: first element if singleton, otherwise every even element + boolean flag = supplier.get().count() > 1; + @Override + public boolean test(double d) + { + flag = !flag; + return flag; + } + }; + assertFalse(supplier.get().noneMatch(matchSome), "Expected noneMatch() == false"); + } + + @ParameterizedTest + @MethodSource("getEmptyReducibles") + default void testNoneMatchDoublePredicate_Empty(Supplier supplier) + { + PrimitiveReducible.OfDouble reducible = supplier.get(); + assertTrue(reducible.allMatch((double each) -> false), "Exepted noneMatch() == false if iterator is empty"); + } + + @Test + default void testNoneMatchDoublePredicate_Null() + { + PrimitiveReducible.OfDouble reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.noneMatch((DoublePredicate) null)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + @Override + default void testContains(Supplier supplier) + { + assertFalse(supplier.get().contains(null)); + testContainsDouble(supplier); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testContainsDouble(Supplier supplier) + { + List numbers = supplier.get().collect(new ArrayList<>()); + for (Double each : numbers) { // boxed double to trigger contains(Double d) + assertTrue(supplier.get().contains(each), "Expected contains(" + each + ") == true"); + if (each == 0.0) { + assertTrue(supplier.get().contains(-1.0 * each), "Expected contains(" + (-1.0 * each) + ") == true"); + } + } + for (Object each : getExcluded(supplier.get())) { // boxed double to trigger contains(Double d) + assertFalse(supplier.get().contains(each), "Expected contains(" + each + ") == false"); + } + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testCountDoublePredicate(Supplier supplier) + { + long[] expected = new long[] {0L}; + supplier.get().forEach((double d) -> { + if (d % 2 == 1) { + expected[0]++; + } + }); + DoublePredicate odd = d -> d % 2 == 1; + long actual = supplier.get().count(odd); + assertEquals(expected[0], actual); + } + + @Test + default void testCountDoublePredicate_Null() + { + PrimitiveReducible.OfDouble reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.count((DoublePredicate) null)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testDetectDoublePredicate_AllFalse(Supplier supplier) + { + PrimitiveReducible.OfDouble reducible = supplier.get(); + assertThrows(NoSuchElementException.class, () -> reducible.detect((double each) -> false)); + } + + @ParameterizedTest + @MethodSource("getEmptyReducibles") + default void testDetectDoublePredicate_Empty(Supplier supplier) + { + PrimitiveReducible.OfDouble reducible = supplier.get(); + assertThrows(NoSuchElementException.class, () -> reducible.detect((double each) -> true)); + } + + @ParameterizedTest + @MethodSource("getSingletonReducibles") + default void testDetectDoublePredicate_Singleton(Supplier supplier) + { + // match first element + double expected = supplier.get().collect(new ArrayList<>()).get(0); + double actual = supplier.get().detect((double each) -> true); + assertEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getMultitonReducibles") + default void testDetectDoublePredicate_Multiton(Supplier supplier) + { + // match second element + double expected = supplier.get().collect(new ArrayList<>()).get(1); + DoublePredicate second = new DoublePredicate() { + boolean flag = true; + @Override + public boolean test(double d) + { + flag = !flag; + return flag; + } + }; + double actual = supplier.get().detect(second); + assertEquals(expected, actual); + } + + @Test + default void testDetectDoublePredicate_Null() + { + PrimitiveReducible.OfDouble reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.detect((DoublePredicate) null)); + } + + @ParameterizedTest + @MethodSource("getEmptyReducibles") + default void testMin_Empty(Supplier supplier) + { + OptionalDouble expected = OptionalDouble.empty(); + OptionalDouble actual = supplier.get().min(); + assertEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getSingletonReducibles") + default void testMin_Singleton(Supplier supplier) + { + OptionalDouble expected = OptionalDouble.of(supplier.get().detect((double d) -> true)); + OptionalDouble actual = supplier.get().min(); + assertTrue(actual.isPresent()); + assertDoubleEquals(expected.getAsDouble(), actual.getAsDouble()); + } + + @ParameterizedTest + @MethodSource("getMultitonReducibles") + default void testMin_Multiton(Supplier supplier) + { + double[] expected = new double[] {supplier.get().detect((double d) -> true)}; + supplier.get().forEach((double d) -> expected[0] = Math.min(expected[0], d)); + OptionalDouble actual = supplier.get().min(); + assertTrue(actual.isPresent()); + assertDoubleEquals(expected[0], actual.getAsDouble()); + } + + @ParameterizedTest + @MethodSource("getEmptyReducibles") + default void testMax_Empty(Supplier supplier) + { + OptionalDouble expected = OptionalDouble.empty(); + OptionalDouble actual = supplier.get().max(); + assertEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getSingletonReducibles") + default void testMax_Singleton(Supplier supplier) + { + OptionalDouble expected = OptionalDouble.of(supplier.get().detect((double d) -> true)); + OptionalDouble actual = supplier.get().max(); + assertTrue(actual.isPresent()); + assertDoubleEquals(expected.getAsDouble(), actual.getAsDouble()); + } + + @ParameterizedTest + @MethodSource("getMultitonReducibles") + default void testMax_Multiton(Supplier supplier) + { + double[] expected = new double[] {supplier.get().detect((double d) -> true)}; + supplier.get().forEach((double d) -> expected[0] = Math.max(expected[0], d)); + OptionalDouble actual = supplier.get().max(); + assertTrue(actual.isPresent()); + assertDoubleEquals(expected[0], actual.getAsDouble()); + } + + @ParameterizedTest + @MethodSource({"getReducibles"}) + default void testSum(Supplier supplier) + { + double[] expected = new double[] {0.0}; + supplier.get().forEach((double d) -> expected[0] += d); + double actual = supplier.get().sum(); + assertEquals(expected[0], actual, 1e-15); + } + + @ParameterizedTest + @MethodSource("getEmptyReducibles") + default void testSum_Empty(Supplier supplier) + { + double expected = 0.0; + double actual = supplier.get().sum(); + assertDoubleEquals(expected, actual); + } + } + + + + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + interface OfInt> extends ReducibleTest + { + @Override + default Stream> getDuplicatesReducibles() + { + return getDuplicatesArraysOfInt().map(args-> () -> getReducible(args)); + } + + @Override + default Stream> getEmptyReducibles() + { + return getEmptyArraysOfInt().map(args-> () -> getReducible(args)); + } + + @Override + default Stream> getSingletonReducibles() + { + return getSingletonArraysOfInt().map(args-> () -> getReducible(args)); + } + + @Override + default Stream> getMultitonReducibles() + { + return getMultitonArraysOfInt().map(args-> () -> getReducible(args)); + } + + T getReducible(int[] arguments); + + @Override + default Iterable getExcluded(T reducible) + { + List candidates = getExclusionListOfInt(); + reducible.forEach((Consumer) candidates::remove); + List excluded = new ArrayList<>(); + excluded.addAll(getUniqueObjects()); + excluded.addAll(candidates); + return excluded; + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testCollectIntArray(Supplier supplier) + { + int n = (int) supplier.get().count(); + int[] expected = new int[n]; + Range.RangeIterator index = new Range(n).iterator(); + supplier.get().forEach((int e) -> expected[index.nextInt()] = e); + int[] actual = supplier.get().collect(new int[n]); + assertArrayEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testCollectIntArrayOffset(Supplier supplier) + { + int n = (int) supplier.get().count(), offset = 2, tail = 3; + int[] expected = new int[offset + n + tail]; + Range.RangeIterator index = new Range(offset, offset + n).iterator(); + supplier.get().forEach((int i) -> expected[index.nextInt()] = i); + int[] actual = supplier.get().collect(new int[offset + n + tail], offset); + assertArrayEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testCollectBitSet(Supplier supplier) + { + BitSet expected = new BitSet(); + supplier.get().forEach((int i) -> {if (i >= 0) expected.set(i);}); + BitSet actual = supplier.get().filter((int i) -> i >= 0).collect(new BitSet()); + assertEquals(expected, actual); + } + + @Test + default void testCollectOfInt_Null() + { + PrimitiveReducible.OfInt reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.collect((int[]) null)); + assertThrows(NullPointerException.class, () -> reducible.collect((int[]) null, 0)); + assertThrows(NullPointerException.class, () -> reducible.collect((BitSet) null)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testCollectAndCountIntArray(Supplier supplier) + { + int n = (int) supplier.get().count(), tail = 3; + int[] expected = new int[n + tail]; + Range.RangeIterator index = new Range(n).iterator(); + supplier.get().forEach((int i) -> expected[index.nextInt()] = i); + int[] actual = new int[n + tail]; + long count = supplier.get().collectAndCount(actual); + assertEquals(n, count); + assertArrayEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testCollectAndCountIntArrayOffset(Supplier supplier) + { + int n = (int) supplier.get().count(), offset = 2, tail = 3; + int[] expected = new int[offset + n + tail]; + Range.RangeIterator index = new Range(offset, offset + n).iterator(); + supplier.get().forEach((int i) -> expected[index.nextInt()] = i); + int[] actual = new int[offset + n + tail]; + long count = supplier.get().collectAndCount(actual, offset); + assertEquals(n, count); + assertArrayEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testCollectAndCountBitSet(Supplier supplier) + { + int n = (int) supplier.get().filter((int i) -> i >= 0).count(); + BitSet expected = new BitSet(); + supplier.get().forEach((int i) -> {if (i >= 0) expected.set(i);}); + BitSet actual = new BitSet(); + long count = supplier.get().filter((int i) -> i >= 0).collectAndCount(actual); + assertEquals(n, count); + assertEquals(expected, actual); + } + + @Test + default void testCollectAndCountOfInt_Null() + { + PrimitiveReducible.OfInt reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.collectAndCount((int[]) null)); + assertThrows(NullPointerException.class, () -> reducible.collectAndCount((int[]) null, 0)); + assertThrows(NullPointerException.class, () -> reducible.collectAndCount((BitSet) null)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testFilterInt(Supplier supplier) + { + ArrayList expected = new ArrayList<>(); + supplier.get().forEach((int i) -> { + if (i % 2 == 0) { + expected.add(i); + } + }); + PrimitiveReducible.OfInt actual = supplier.get().filter((int i) -> i % 2 == 0); + assertIterableEquals(unboxInt(expected), unboxInt(actual.collect(new ArrayList<>()))); + } + + @Test + default void testFilterOfInt_Null() + { + PrimitiveReducible.OfInt reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.filter((IntPredicate) null)); + } + + void testFlatMapIntToObj(Supplier supplier); + + void testFlatMapIntToDouble(Supplier supplier); + + void testFlatMapIntToInt(Supplier supplier); + + void testFlatMapIntToLong(Supplier supplier); + + void testFlatMapIntToNull(Supplier supplier); + + void testFlatMapOfInt_Null(); + + @ParameterizedTest + @MethodSource("getReducibles") + default void testMapIntToObj(Supplier supplier) + { + String prefix = "Item: "; + List expected = new ArrayList<>(); + supplier.get().forEach((int i) -> expected.add(prefix + i)); + Reducible actual = supplier.get().map((int i) -> prefix + i); + assertIterableEquals(expected, actual.collect(new ArrayList<>())); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testMapIntToDouble(Supplier supplier) + { + Range range = new Range((int) supplier.get().count()); + PrimitiveIterable.OfDouble expected = unboxDouble(range.map((int i) -> (double) i)); + Range.RangeIterator index = range.iterator(); + PrimitiveReducible.OfDouble actual = supplier.get().mapToDouble((int i) -> index.next()); + assertIterableEquals(expected, unboxDouble(actual.collect(new ArrayList<>()))); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testMapIntToInt(Supplier supplier) + { + Range expected = new Range((int) supplier.get().count()); + Range.RangeIterator index = expected.iterator(); + PrimitiveReducible.OfInt actual = supplier.get().mapToInt((int i) -> index.next()); + assertIterableEquals(expected, unboxInt(actual.collect(new ArrayList<>()))); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testMapToLong(Supplier supplier) + { + Range range = new Range((int) supplier.get().count()); + PrimitiveIterable.OfLong expected = unboxLong(range.map((int i) -> (long) i)); + Range.RangeIterator index = range.iterator(); + PrimitiveReducible.OfLong actual = supplier.get().mapToLong((int i) -> index.next()); + assertIterableEquals(expected, unboxLong(actual.collect(new ArrayList<>()))); + } + + @Test + default void testMapOfInt_Null() + { + PrimitiveReducible.OfInt reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.map((IntFunction) null)); + assertThrows(NullPointerException.class, () -> reducible.mapToDouble((IntToDoubleFunction) null)); + assertThrows(NullPointerException.class, () -> reducible.mapToInt((IntUnaryOperator) null)); + assertThrows(NullPointerException.class, () -> reducible.mapToLong((IntToLongFunction) null)); + } + + void testForEachIntConsumer(Supplier supplier); + + @Test + default void testForEachIntConsumer_Null() + { + PrimitiveReducible.OfInt reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.forEach((IntConsumer) null)); + } + + @ParameterizedTest + @MethodSource("getEmptyReducibles") + default void testReduceIntBinaryOperator_Empty(Supplier supplier) + { + IntBinaryOperator dummy = (res, each) -> Integer.MIN_VALUE; + OptionalInt actual = supplier.get().reduce(dummy); + assertEquals(OptionalInt.empty(), actual); + } + + @ParameterizedTest + @MethodSource("getSingletonReducibles") + default void testReduceIntBinaryOperator_Singleton(Supplier supplier) + { + IntBinaryOperator dummy = (res, each) -> Integer.MIN_VALUE; + int expected = supplier.get().detect((int i) -> true); + OptionalInt actual = supplier.get().reduce(dummy); + assertTrue(actual.isPresent()); + assertEquals(expected, actual.getAsInt()); + } + + @ParameterizedTest + @MethodSource("getMultitonReducibles") + default void testReduceIntBinaryOperator_Multiton(Supplier supplier) + { + List expected = supplier.get().collect(new ArrayList<>()); + List actual = new ArrayList<>(); + int probe = -31; // "unique" value + IntBinaryOperator collect = (res, each) -> { + if (actual.isEmpty()) { + actual.add(res); + actual.add(each); + return probe; + } else { + actual.add(each); + return res; + } + }; + OptionalInt result = supplier.get().reduce(collect); + assertTrue(result.isPresent()); + assertEquals(probe, result.getAsInt()); + assertIterableEquals(unboxInt(expected), unboxInt(actual)); + } + + @ParameterizedTest + @MethodSource("getEmptyReducibles") + default void testReduceDoubleBinaryOperator_Empty(Supplier supplier) + { + DoubleBinaryOperator dummy = (res, each) -> Double.MIN_VALUE; + OptionalDouble actual = supplier.get().reduce(dummy); + assertEquals(OptionalDouble.empty(), actual); + } + + @ParameterizedTest + @MethodSource("getSingletonReducibles") + default void testReduceDoubleBinaryOperator_Singleton(Supplier supplier) + { + DoubleBinaryOperator dummy = (res, each) -> Double.MIN_VALUE; + double expected = supplier.get().detect((int i) -> true); + OptionalDouble actual = supplier.get().reduce(dummy); + assertTrue(actual.isPresent()); + assertEquals(expected, actual.getAsDouble()); + } + + @ParameterizedTest + @MethodSource("getMultitonReducibles") + default void testReduceDoubleBinaryOperator_Multiton(Supplier supplier) + { + List expected = supplier.get().mapToDouble((int i) -> (double) i).collect(new ArrayList<>()); + List actual = new ArrayList<>(); + double probe = -31; // "unique" value + DoubleBinaryOperator collect = (res, each) -> { + if (actual.isEmpty()) { + actual.add(res); + actual.add(each); + return probe; + } else { + actual.add(each); + return res; + } + }; + OptionalDouble result = supplier.get().reduce(collect); + assertTrue(result.isPresent()); + assertEquals(probe, result.getAsDouble()); + assertIterableEquals(unboxDouble(expected), unboxDouble(actual)); + } + + @ParameterizedTest + @MethodSource("getEmptyReducibles") + default void testReduceLongBinaryOperator_Empty(Supplier supplier) + { + LongBinaryOperator dummy = (res, each) -> Long.MIN_VALUE; + OptionalLong actual = supplier.get().reduce(dummy); + assertEquals(OptionalLong.empty(), actual); + } + + @ParameterizedTest + @MethodSource("getSingletonReducibles") + default void testReduceLongBinaryOperator_Singleton(Supplier supplier) + { + LongBinaryOperator dummy = (res, each) -> Long.MIN_VALUE; + long expected = supplier.get().detect((int i) -> true); + OptionalLong actual = supplier.get().reduce(dummy); + assertTrue(actual.isPresent()); + assertEquals(expected, actual.getAsLong()); + } + + @ParameterizedTest + @MethodSource("getMultitonReducibles") + default void testReduceLongBinaryOperator_Multiton(Supplier supplier) + { + List expected = supplier.get().mapToLong((int i) -> (long) i).collect(new ArrayList<>()); + List actual = new ArrayList<>(); + long probe = -31; // "unique" value + LongBinaryOperator collect = (res, each) -> { + if (actual.isEmpty()) { + actual.add(res); + actual.add(each); + return probe; + } else { + actual.add(each); + return res; + } + }; + OptionalLong result = supplier.get().reduce(collect); + assertTrue(result.isPresent()); + assertEquals(probe, result.getAsLong()); + assertIterableEquals(unboxLong(expected), unboxLong(actual)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testReduceObjIntFunction(Supplier supplier) + { + List expected = supplier.get().collect(new ArrayList<>()); + ObjIntFunction, List> collect = (seq, each) -> {seq.add(each); return seq;}; + List actual = supplier.get().reduce(new ArrayList<>(), collect); + assertIterableEquals(unboxInt(expected), unboxInt(actual)); + assertDoesNotThrow(() -> supplier.get().reduce(null, (Object obj, int each) -> null)); + } + + @Test + default void testReduceOfInt_Null() + { + PrimitiveReducible.OfInt reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.reduce((DoubleBinaryOperator) null)); + assertThrows(NullPointerException.class, () -> reducible.reduce((IntBinaryOperator) null)); + assertThrows(NullPointerException.class, () -> reducible.reduce((LongBinaryOperator) null)); + assertThrows(NullPointerException.class, () -> reducible.reduce(new Object(), (ObjIntFunction) null)); + assertThrows(NullPointerException.class, () -> reducible.reduce(0.0, (DoubleBinaryOperator) null)); + assertThrows(NullPointerException.class, () -> reducible.reduce(0, (IntBinaryOperator) null)); + assertThrows(NullPointerException.class, () -> reducible.reduce(0L, (LongBinaryOperator) null)); + } + + void testConcatTypes(); + + @ParameterizedTest + @MethodSource({"getSingletonReducibles", "getMultitonReducibles"}) + default void testAllMatchIntPredicate(Supplier supplier) + { + // match all elements + assertTrue(supplier.get().allMatch((int each) -> true), "Expected allMatch() == true"); + // match not all elements + IntPredicate matchNotAll = new IntPredicate() { + // match: no element if singleton, otherwise every odd element + boolean flag = supplier.get().count() == 1; + @Override + public boolean test(int i) + { + flag = !flag; + return flag; + } + }; + assertFalse(supplier.get().allMatch(matchNotAll), "Expected allMatch() == false"); + } + + @ParameterizedTest + @MethodSource("getEmptyReducibles") + default void testAllMatchIntPredicate_Empty(Supplier supplier) + { + PrimitiveReducible.OfInt reducible = supplier.get(); + assertTrue(reducible.allMatch((int each) -> false), "Exepted allMatch() == true if iterator is empty"); + } + + @Test + default void testAllMatchIntPredicate_Null() + { + PrimitiveReducible.OfInt reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.allMatch((IntPredicate) null)); + } + + @ParameterizedTest + @MethodSource({"getSingletonReducibles", "getMultitonReducibles"}) + default void testAnyMatchIntPredicate(Supplier supplier) + { + // match no element + assertFalse(supplier.get().anyMatch((int each) -> false), "Expected anyMatch() == false"); + // match some elements + IntPredicate matchSome = new IntPredicate() { + // match: first element if singleton, otherwise every even element + boolean flag = supplier.get().count() > 1; + @Override + public boolean test(int i) + { + flag = !flag; + return flag; + } + }; + assertTrue(supplier.get().anyMatch(matchSome), "Expected anyMatch() == true"); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testAnyMatchIntPredicate_Empty(Supplier supplier) + { + PrimitiveReducible.OfInt reducible = supplier.get(); + assertTrue(reducible.allMatch((int each) -> true), "Exepted anyMatch() == false if iterator is empty"); + } + + @Test + default void testAnyMatchIntPredicate_Null() + { + PrimitiveReducible.OfInt reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.anyMatch((IntPredicate) null)); + } + + @ParameterizedTest + @MethodSource({"getSingletonReducibles", "getMultitonReducibles"}) + default void testNoneMatchIntPredicate(Supplier supplier) + { + // match no element + assertTrue(supplier.get().noneMatch((int each) -> false), "Expected noneMatch() == true"); + // match some elements + IntPredicate matchSome = new IntPredicate() { + // match: first element if singleton, otherwise every even element + boolean flag = supplier.get().count() > 1; + @Override + public boolean test(int i) + { + flag = !flag; + return flag; + } + }; + assertFalse(supplier.get().noneMatch(matchSome), "Expected noneMatch() == false"); + } + + @ParameterizedTest + @MethodSource("getEmptyReducibles") + default void testNoneMatchIntPredicate_Empty(Supplier supplier) + { + PrimitiveReducible.OfInt reducible = supplier.get(); + assertTrue(reducible.allMatch((int each) -> false), "Exepted noneMatch() == false if iterator is empty"); + } + + @Test + default void testNoneMatchIntPredicate_Null() + { + PrimitiveReducible.OfInt reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.noneMatch((IntPredicate) null)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + @Override + default void testContains(Supplier supplier) + { + assertFalse(supplier.get().contains(null), "Expected contains(null) == false"); + testContainsInt(supplier); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testContainsInt(Supplier supplier) + { + List numbers = supplier.get().collect(new ArrayList<>()); + for (Integer each : numbers) { // boxed int to trigger contains(Integer i) + assertTrue(supplier.get().contains(each), "Expected contains(" + each + ") == true"); + } + for (Object each : getExcluded(supplier.get())) { // boxed int to trigger contains(Integer i) + assertFalse(supplier.get().contains(each), "Expected contains(" + each + ") == false"); + } + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testCountIntPredicate(Supplier supplier) + { + long[] expected = new long[] {0L}; + supplier.get().forEach((int i) -> { + if (i % 2 == 1) { + expected[0]++; + } + }); + IntPredicate odd = i -> i % 2 == 1; + long actual = supplier.get().count(odd); + assertEquals(expected[0], actual); + } + + @Test + default void testCountIntPredicate_Null() + { + PrimitiveReducible.OfInt reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.count((IntPredicate) null)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testDetectIntPredicate(Supplier supplier) + { + PrimitiveReducible.OfInt reducible = supplier.get(); + assertThrows(NoSuchElementException.class, () -> reducible.detect((int each) -> false)); + } + + @ParameterizedTest + @MethodSource("getEmptyReducibles") + default void testDetectIntPredicate_Empty(Supplier supplier) + { + PrimitiveReducible.OfInt reducible = supplier.get(); + assertThrows(NoSuchElementException.class, () -> reducible.detect((int each) -> true)); + } + + @ParameterizedTest + @MethodSource("getSingletonReducibles") + default void testDetectIntPredicate_Singleton(Supplier supplier) + { + // match first element + int expected = supplier.get().collect(new ArrayList<>()).get(0); + int actual = supplier.get().detect((int each) -> true); + assertEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getMultitonReducibles") + default void testDetectIntPredicate_Multiton(Supplier supplier) + { + // match second element + int expected = supplier.get().collect(new ArrayList<>()).get(1); + IntPredicate second = new IntPredicate() { + boolean flag = true; + @Override + public boolean test(int i) + { + flag = !flag; + return flag; + } + }; + int actual = supplier.get().detect(second); + assertEquals(expected, actual); + } + + @Test + default void testDetectIntPredicate_Null() + { + PrimitiveReducible.OfInt reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.detect((IntPredicate) null)); + } + + @ParameterizedTest + @MethodSource("getEmptyReducibles") + default void testMin_Empty(Supplier supplier) + { + OptionalInt expected = OptionalInt.empty(); + OptionalInt actual = supplier.get().min(); + assertEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getSingletonReducibles") + default void testMin_Singleton(Supplier supplier) + { + OptionalInt expected = OptionalInt.of(supplier.get().detect((int i) -> true)); + OptionalInt actual = supplier.get().min(); + assertTrue(actual.isPresent()); + assertEquals(expected.getAsInt(), actual.getAsInt()); + } + + @ParameterizedTest + @MethodSource("getMultitonReducibles") + default void testMin_Multiton(Supplier supplier) + { + int[] expected = new int[] {supplier.get().detect((int i) -> true)}; + supplier.get().forEach((int i) -> expected[0] = Math.min(expected[0], i)); + OptionalInt actual = supplier.get().min(); + assertTrue(actual.isPresent()); + assertEquals(expected[0], actual.getAsInt()); + } + + @ParameterizedTest + @MethodSource("getEmptyReducibles") + default void testMax_Empty(Supplier supplier) + { + OptionalInt expected = OptionalInt.empty(); + OptionalInt actual = supplier.get().max(); + assertEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getSingletonReducibles") + default void testMax_Singleton(Supplier supplier) + { + OptionalInt expected = OptionalInt.of(supplier.get().detect((int i) -> true)); + OptionalInt actual = supplier.get().max(); + assertTrue(actual.isPresent()); + assertEquals(expected.getAsInt(), actual.getAsInt()); + } + + @ParameterizedTest + @MethodSource("getMultitonReducibles") + default void testMax_Multiton(Supplier supplier) + { + int[] expected = new int[] {supplier.get().detect((int i) -> true)}; + supplier.get().forEach((int i) -> expected[0] = Math.max(expected[0], i)); + OptionalInt actual = supplier.get().max(); + assertTrue(actual.isPresent()); + assertEquals(expected[0], actual.getAsInt()); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testSum(Supplier supplier) + { + long[] expected = new long[] {0L}; + supplier.get().forEach((int i) -> expected[0] += i); + long actual = supplier.get().sum(); + assertEquals(expected[0], actual); + } + } + + + + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + interface OfLong> extends ReducibleTest + { + @Override + default Stream> getDuplicatesReducibles() + { + return getDuplicatesArraysOfLong().map(args-> () -> getReducible(args)); + } + + @Override + default Stream> getEmptyReducibles() + { + return getEmptyArraysOfLong().map(args-> () -> getReducible(args)); + } + + @Override + default Stream> getSingletonReducibles() + { + return getSingletonArraysOfLong().map(args-> () -> getReducible(args)); + } + + @Override + default Stream> getMultitonReducibles() + { + return getMultitonArraysOfLong().map(args-> () -> getReducible(args)); + } + + T getReducible(long[] numbers); + + @Override + default Iterable getExcluded(T reducible) + { + List candidates = getExclusionListOfLong(); + reducible.forEach((Consumer) candidates::remove); + List excluded = new ArrayList<>(); + excluded.addAll(getUniqueObjects()); + excluded.addAll(candidates); + return excluded; + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testCollectLongArray(Supplier supplier) + { + int n = (int) supplier.get().count(); + long[] expected = new long[n]; + Range.RangeIterator index = new Range(n).iterator(); + supplier.get().forEach((long l) -> expected[index.nextInt()] = l); + long[] actual = supplier.get().collect(new long[n]); + assertArrayEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testCollectLongArrayOffset(Supplier supplier) + { + int n = (int) supplier.get().count(), offset = 2, tail = 3; + long[] expected = new long[offset + n + tail]; + Range.RangeIterator index = new Range(offset, offset + n).iterator(); + supplier.get().forEach((long l) -> expected[index.nextInt()] = l); + long[] actual = supplier.get().collect(new long[offset + n + tail], offset); + assertArrayEquals(expected, actual); + } + + @Test + default void testCollectOfLong_Null() + { + PrimitiveReducible.OfLong reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.collect((long[]) null)); + assertThrows(NullPointerException.class, () -> reducible.collect((long[]) null, 0)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testCollectAndCountLongArray(Supplier supplier) + { + int n = (int) supplier.get().count(), tail = 3; + long[] expected = new long[n + tail]; + Range.RangeIterator index = new Range(n).iterator(); + supplier.get().forEach((long l) -> expected[index.nextInt()] = l); + long[] actual = new long[n + tail]; + long count = supplier.get().collectAndCount(actual); + assertEquals(n, count); + assertArrayEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testCollectAndCountArrayOffset(Supplier supplier) + { + int n = (int) supplier.get().count(), offset = 2, tail = 3; + long[] expected = new long[offset + n + tail]; + Range.RangeIterator index = new Range(offset, offset + n).iterator(); + supplier.get().forEach((long l) -> expected[index.nextInt()] = l); + long[] actual = new long[offset + n + tail]; + long count = supplier.get().collectAndCount(actual, offset); + assertEquals(n, count); + assertArrayEquals(expected, actual); + } + + @Test + default void testCollectAndCountOfLong_Null() + { + PrimitiveReducible.OfLong reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.collectAndCount((long[]) null)); + assertThrows(NullPointerException.class, () -> reducible.collectAndCount((long[]) null, 0)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testFilterLong(Supplier supplier) + { + ArrayList expected = new ArrayList<>(); + supplier.get().forEach((long l) -> { + if (l % 2 == 0) { + expected.add(l); + } + }); + PrimitiveReducible.OfLong actual = supplier.get().filter((long l) -> l % 2 == 0); + assertIterableEquals(unboxLong(expected), unboxLong(actual.collect(new ArrayList<>()))); + } + + @Test + default void testFilterOfLong_Null() + { + PrimitiveReducible.OfLong reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.filter((LongPredicate) null)); + } + + void testFlatMapLongToObj(Supplier supplier); + + void testFlatMapLongToDouble(Supplier supplier); + + void testFlatMapLongToInt(Supplier supplier); + + void testFlatMapLongToLong(Supplier supplier); + + void testFlatMapLongToNull(Supplier supplier); + + void testFlatMapOfLong_Null(); + + @ParameterizedTest + @MethodSource("getReducibles") + default void testMapLongToObj(Supplier supplier) + { + String prefix = "Item: "; + List expected = new ArrayList<>(); + supplier.get().forEach((long l) -> expected.add(prefix + l)); + Reducible actual = supplier.get().map((long l) -> prefix + l); + assertIterableEquals(expected, actual.collect(new ArrayList<>())); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testMapLongToDouble(Supplier supplier) + { + Range range = new Range((int) supplier.get().count()); + PrimitiveIterable.OfDouble expected = unboxDouble(range.map((int i) -> (double) i)); + Range.RangeIterator index = range.iterator(); + PrimitiveReducible.OfDouble actual = supplier.get().mapToDouble((long l) -> index.next()); + assertIterableEquals(expected, unboxDouble(actual.collect(new ArrayList<>()))); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testMapLongToInt(Supplier supplier) + { + Range expected = new Range((int) supplier.get().count()); + Range.RangeIterator index = expected.iterator(); + PrimitiveReducible.OfInt actual = supplier.get().mapToInt((long l) -> index.next()); + assertIterableEquals(expected, unboxInt(actual.collect(new ArrayList<>()))); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testMapToLong(Supplier supplier) + { + Range range = new Range((int) supplier.get().count()); + PrimitiveIterable.OfLong expected = unboxLong(range.map((int i) -> (long) i)); + Range.RangeIterator index = range.iterator(); + PrimitiveReducible.OfLong actual = supplier.get().mapToLong((long l) -> index.next()); + assertIterableEquals(expected, unboxLong(actual.collect(new ArrayList<>()))); + } + + @Test + default void testMapOfLong_Null() + { + PrimitiveReducible.OfLong reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.map((LongFunction) null)); + assertThrows(NullPointerException.class, () -> reducible.mapToDouble((LongToDoubleFunction) null)); + assertThrows(NullPointerException.class, () -> reducible.mapToInt((LongToIntFunction) null)); + assertThrows(NullPointerException.class, () -> reducible.mapToLong((LongUnaryOperator) null)); + } + + void testForEachLongConsumer(Supplier supplier); + + @Test + default void testForEachLongConsumer_Null() + { + PrimitiveReducible.OfLong reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.forEach((LongConsumer) null)); + } + + @ParameterizedTest + @MethodSource("getEmptyReducibles") + default void testReduceLongBinaryOperator_Empty(Supplier supplier) + { + LongBinaryOperator dummy = (res, each) -> Long.MIN_VALUE; + OptionalLong actual = supplier.get().reduce(dummy); + assertEquals(OptionalLong.empty(), actual); + } + + @ParameterizedTest + @MethodSource("getSingletonReducibles") + default void testReduceLongBinaryOperator_Singleton(Supplier supplier) + { + LongBinaryOperator dummy = (res, each) -> Long.MIN_VALUE; + long expected = supplier.get().detect((long l) -> true); + OptionalLong actual = supplier.get().reduce(dummy); + assertTrue(actual.isPresent()); + assertEquals(expected, actual.getAsLong()); + } + + @ParameterizedTest + @MethodSource("getMultitonReducibles") + default void testReduceLongBinaryOperator_Multiton(Supplier supplier) + { + List expected = supplier.get().collect(new ArrayList<>()); + List actual = new ArrayList<>(); + long probe = -31; // "unique" value + LongBinaryOperator collect = (res, each) -> { + if (actual.isEmpty()) { + actual.add(res); + actual.add(each); + return probe; + } else { + actual.add(each); + return res; + } + }; + OptionalLong result = supplier.get().reduce(collect); + assertTrue(result.isPresent()); + assertEquals(probe, result.getAsLong()); + assertIterableEquals(unboxLong(expected), unboxLong(actual)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testReduceDoubleLongToDoubleFunction(Supplier supplier) + { + List expected = supplier.get().collect(new ArrayList<>()); + double init = Double.MIN_VALUE; + List actual = new ArrayList<>(); + DoubleLongToDoubleFunction collect = (res, each) -> {actual.add(each); return res;}; + double result = supplier.get().reduce(init, collect); + assertEquals(init, result); + assertIterableEquals(unboxLong(expected), unboxLong(actual)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testReduceIntLongToIntFunction(Supplier supplier) + { + List expected = supplier.get().collect(new ArrayList<>()); + int init = Integer.MIN_VALUE; + List actual = new ArrayList<>(); + IntLongToIntFunction collect = (res, each) -> {actual.add(each); return res;}; + int result = supplier.get().reduce(init, collect); + assertEquals(init, result); + assertIterableEquals(unboxLong(expected), unboxLong(actual)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testReduceObjLong(Supplier supplier) + { + List expected = supplier.get().collect(new ArrayList<>()); + ObjLongFunction, List> collect = (seq, each) -> {seq.add(each); return seq;}; + List actual = supplier.get().reduce(new ArrayList<>(), collect); + assertIterableEquals(unboxLong(expected), unboxLong(actual)); + assertDoesNotThrow(() -> supplier.get().reduce(null, (Object obj, long each) -> null)); + } + + @Test + default void testReduceOfLong_Null() + { + PrimitiveReducible.OfLong reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.reduce((LongBinaryOperator) null)); + assertThrows(NullPointerException.class, () -> reducible.reduce(new Object(), (ObjLongFunction) null)); + assertThrows(NullPointerException.class, () -> reducible.reduce(0.0, (DoubleLongToDoubleFunction) null)); + assertThrows(NullPointerException.class, () -> reducible.reduce(0, (IntLongToIntFunction) null)); + assertThrows(NullPointerException.class, () -> reducible.reduce(0L, (LongBinaryOperator) null)); + } + + void testConcatTypes(); + + @ParameterizedTest + @MethodSource({"getSingletonReducibles", "getMultitonReducibles"}) + default void testAllMatchLongPredicate(Supplier supplier) + { + // match all elements + assertTrue(supplier.get().allMatch((long each) -> true), "Expected allMatch() == true"); + // match not all elements + LongPredicate matchNotAll = new LongPredicate() { + // match: no element if singleton, otherwise every odd element + boolean flag = supplier.get().count() == 1; + @Override + public boolean test(long i) + { + flag = !flag; + return flag; + } + }; + assertFalse(supplier.get().allMatch(matchNotAll), "Expected allMatch() == false"); + } + + @ParameterizedTest + @MethodSource("getEmptyReducibles") + default void testAllMatchLongPredicate_Empty(Supplier supplier) + { + PrimitiveReducible.OfLong reducible = supplier.get(); + assertTrue(reducible.allMatch((long each) -> false), "Exepted allMatch() == true if iterator is empty"); + } + + @Test + default void testAllMatchLongPredicate_Null() + { + PrimitiveReducible.OfLong reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.allMatch((LongPredicate) null)); + } + + @ParameterizedTest + @MethodSource({"getSingletonReducibles", "getMultitonReducibles"}) + default void testAnyMatchLongPredicate(Supplier supplier) + { + // match no element + assertFalse(supplier.get().anyMatch((long each) -> false), "Expected anyMatch() == false"); + // match some elements + LongPredicate matchSome = new LongPredicate() { + // match: first element if singleton, otherwise every even element + boolean flag = supplier.get().count() > 1; + @Override + public boolean test(long i) + { + flag = !flag; + return flag; + } + }; + assertTrue(supplier.get().anyMatch(matchSome), "Expected anyMatch() == true"); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testAnyMatchLongPredicate_Empty(Supplier supplier) + { + PrimitiveReducible.OfLong reducible = supplier.get(); + assertTrue(reducible.allMatch((long each) -> true), "Exepted anyMatch() == false if iterator is empty"); + } + + @Test + default void testAnyMatchLongPredicate_Null() + { + PrimitiveReducible.OfLong reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.anyMatch((LongPredicate) null)); + } + + @ParameterizedTest + @MethodSource({"getSingletonReducibles", "getMultitonReducibles"}) + default void testNoneMatchLongPredicate(Supplier supplier) + { + // match no element + assertTrue(supplier.get().noneMatch((long each) -> false), "Expected noneMatch() == true"); + // match some elements + LongPredicate matchSome = new LongPredicate() { + // match: first element if singleton, otherwise every even element + boolean flag = supplier.get().count() > 1; + @Override + public boolean test(long i) + { + flag = !flag; + return flag; + } + }; + assertFalse(supplier.get().noneMatch(matchSome), "Expected noneMatch() == false"); + } + + @ParameterizedTest + @MethodSource("getEmptyReducibles") + default void testNoneMatchLongPredicate_Empty(Supplier supplier) + { + PrimitiveReducible.OfLong reducible = supplier.get(); + assertTrue(reducible.allMatch((long each) -> false), "Exepted noneMatch() == false if iterator is empty"); + } + + @Test + default void testNoneMatchLongPredicate_Null() + { + PrimitiveReducible.OfLong reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.noneMatch((LongPredicate) null)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + @Override + default void testContains(Supplier supplier) + { + assertFalse(supplier.get().contains(null), "Expected contains(null) == false"); + testContainsLong(supplier); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testContainsLong(Supplier supplier) + { + List numbers = supplier.get().collect(new ArrayList<>()); + for (Long each : numbers) { // boxed long to trigger contains(Long l) + assertTrue(supplier.get().contains(each), "Expected contains(" + each + ") == true"); + } + for (Object each : getExcluded(supplier.get())) { // boxed long to trigger contains(Long l) + assertFalse(supplier.get().contains(each), "Expected contains(" + each + ") == false"); + } + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testCountLongPredicate(Supplier supplier) + { + long[] expected = new long[] {0L}; + supplier.get().forEach((long l) -> { + if (l % 2 == 1) { + expected[0]++; + } + }); + LongPredicate odd = l -> l % 2 == 1; + long actual = supplier.get().count(odd); + assertEquals(expected[0], actual); + } + + @Test + default void testCountLongPredicate_Null() + { + PrimitiveReducible.OfLong reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.count((LongPredicate) null)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testDetectLongPredicate(Supplier supplier) + { + PrimitiveReducible.OfLong reducible = supplier.get(); + assertThrows(NoSuchElementException.class, () -> reducible.detect((long each) -> false)); + } + + @ParameterizedTest + @MethodSource("getEmptyReducibles") + default void testDetectLongPredicate_Empty(Supplier supplier) + { + PrimitiveReducible.OfLong reducible = supplier.get(); + assertThrows(NoSuchElementException.class, () -> reducible.detect((long each) -> true)); + } + + @ParameterizedTest + @MethodSource("getSingletonReducibles") + default void testDetectLongPredicate_Singleton(Supplier supplier) + { + // match first element + long expected = supplier.get().collect(new ArrayList<>()).get(0); + long actual = supplier.get().detect((long each) -> true); + assertEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getMultitonReducibles") + default void testDetectLongPredicate_Multiton(Supplier supplier) + { + // match second element + long expected = supplier.get().collect(new ArrayList<>()).get(1); + LongPredicate second = new LongPredicate() { + boolean flag = true; + @Override + public boolean test(long l) + { + flag = !flag; + return flag; + } + }; + long actual = supplier.get().detect(second); + assertEquals(expected, actual); + } + + @Test + default void testDetectLongPredicate_Null() + { + PrimitiveReducible.OfLong reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.detect((LongPredicate) null)); + } + + @ParameterizedTest + @MethodSource("getEmptyReducibles") + default void testMin_Empty(Supplier supplier) + { + OptionalLong expected = OptionalLong.empty(); + OptionalLong actual = supplier.get().min(); + assertEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getSingletonReducibles") + default void testMin_Singleton(Supplier supplier) + { + OptionalLong expected = OptionalLong.of(supplier.get().detect((long l) -> true)); + OptionalLong actual = supplier.get().min(); + assertTrue(actual.isPresent()); + assertEquals(expected.getAsLong(), actual.getAsLong()); + } + + @ParameterizedTest + @MethodSource("getMultitonReducibles") + default void testMin_Multiton(Supplier supplier) + { + long[] expected = new long[] {supplier.get().detect((long l) -> true)}; + supplier.get().forEach((long l) -> expected[0] = Math.min(expected[0], l)); + OptionalLong actual = supplier.get().min(); + assertTrue(actual.isPresent()); + assertEquals(expected[0], actual.getAsLong()); + } + + @ParameterizedTest + @MethodSource("getEmptyReducibles") + default void testMax_Empty(Supplier supplier) + { + OptionalLong expected = OptionalLong.empty(); + OptionalLong actual = supplier.get().max(); + assertEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getSingletonReducibles") + default void testMax_Singleton(Supplier supplier) + { + OptionalLong expected = OptionalLong.of(supplier.get().detect((long l) -> true)); + OptionalLong actual = supplier.get().max(); + assertTrue(actual.isPresent()); + assertEquals(expected.getAsLong(), actual.getAsLong()); + } + + @ParameterizedTest + @MethodSource("getMultitonReducibles") + default void testMax_Multiton(Supplier supplier) + { + long[] expected = new long[] {supplier.get().detect((long l) -> true)}; + supplier.get().forEach((long l) -> expected[0] = Math.max(expected[0], l)); + OptionalLong actual = supplier.get().max(); + assertTrue(actual.isPresent()); + assertEquals(expected[0], actual.getAsLong()); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testSum(Supplier supplier) + { + long[] expected = new long[] {0L}; + supplier.get().forEach((long l) -> expected[0] += l); + long actual = supplier.get().sum(); + assertEquals(expected[0], actual); + } + } +} diff --git a/prism/unit-tests/common/iterable/RangeTest.java b/prism/unit-tests/common/iterable/RangeTest.java new file mode 100644 index 0000000000..9645e757eb --- /dev/null +++ b/prism/unit-tests/common/iterable/RangeTest.java @@ -0,0 +1,390 @@ +package common.iterable; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.ArrayList; +import java.util.List; +import java.util.PrimitiveIterator; +import java.util.function.Supplier; +import java.util.stream.Stream; + +import static common.iterable.PrimitiveReducibleTest.*; +import static org.junit.jupiter.api.Assertions.*; + +class RangeTest implements FunctionalPrimitiveIterableTest.OfInt +{ + static Range asRange(Arguments args) + { + Object[] params = args.get(); + return new Range((Integer) params[0], (Integer) params[1], (Integer) params[2]); + } + + static Stream getEmptyRangeArguments() + { + return Stream.of(Arguments.of(0, 0, 1), + Arguments.of(0, 0, -1), + Arguments.of(Integer.MAX_VALUE, Integer.MAX_VALUE, 1), + Arguments.of(Integer.MIN_VALUE, Integer.MIN_VALUE, -1)); + } + + static Stream getSingletonRangeArguments() + { + return Stream.of(Arguments.of(0, 1, 1), + Arguments.of(0, -1, -1), + Arguments.of(Integer.MAX_VALUE-1, Integer.MAX_VALUE, 1), + Arguments.of(Integer.MIN_VALUE+1, Integer.MIN_VALUE, -1)); + } + + static Stream getMultitonRangeArguments() + { + return Stream.of(Arguments.of(0, 10, 1), + Arguments.of(0, -10, -1), + Arguments.of(-10, 10, 3), + Arguments.of(10, -10, -3), + Arguments.of(Integer.MIN_VALUE, Integer.MIN_VALUE+20, 7), + Arguments.of(Integer.MAX_VALUE, Integer.MAX_VALUE-20, -7)); + } + + @Override + public Range getReducible(int[] arguments) + { + throw new RuntimeException("Should not be called"); + } + + @Override + public Stream> getDuplicatesReducibles() + { + return Stream.empty(); + } + + @Override + public Stream> getEmptyReducibles() + { + return getEmptyRangeArguments().map(args -> () -> asRange(args)); + } + + @Override + public Stream> getSingletonReducibles() + { + return getSingletonRangeArguments().map(args -> () -> asRange(args)); + } + + @Override + public Stream> getMultitonReducibles() + { + return getMultitonRangeArguments().map(args -> () -> asRange(args)); + } + + @Override + public Iterable getExcluded(Range range) + { + List excluded = new ArrayList<>(); + excluded.addAll(getUniqueObjects()); + // add lower and upper bounds + range.min().ifPresent(min -> { + if (min > Integer.MIN_VALUE) { + excluded.add(min - 1); + excluded.add(Integer.MIN_VALUE); + } + }); + range.max().ifPresent(max -> { + if (max < Integer.MAX_VALUE) { + excluded.add(max + 1); + excluded.add(Integer.MAX_VALUE); + } + }); + // add ints between first and last that are no steps + if (range.isAscending()) { + for (int i = range.first; i <= range.last; i++) { + if ((i - range.first) % range.step != 0) { + excluded.add((Integer) i); + } + } + } else { + for (int i = range.first; i >= range.last; i--) { + if ((i - range.first) % range.step != 0) { + excluded.add((Integer) i); + } + } + } + return excluded; + } + + public static void assertEqualsClosedForLoop(int start, int stop, int step, Range actual) + { + assertEqualsClosedForLoop(start, stop, step, actual.iterator()); + } + + public static void assertEqualsOpenForLoop(int start, int stop, int step, Range actual) + { + assertEqualsOpenForLoop(start, stop, step, actual.iterator()); + } + + public static void assertEqualsClosedForLoop(int start, int stop, int step, PrimitiveIterator.OfInt actual) + { + if (step > 0) { + // closed ascending loop: <= + for (int i = start; i <= stop; i = Math.addExact(i, step)) { + assertEquals(i, actual.nextInt()); + } + } else if (step < 0) { + // open descending loop: >= + for (int i = start; i >= stop; i = Math.addExact(i, step)) { + assertEquals(i, actual.nextInt()); + } + } else { + fail("expected step != 0"); + } + assertFalse(actual.hasNext(), "Expected exhausted iterator"); + } + + public static void assertEqualsOpenForLoop(int start, int stop, int step, PrimitiveIterator.OfInt actual) + { + if (step > 0) { + // open ascending loop: < + for (int i = start; i < stop; i = Math.addExact(i, step)) { + assertEquals(i, actual.nextInt()); + } + } else if (step < 0) { + // open descending loop: > + for (int i = start; i > stop; i = Math.addExact(i, step)) { + assertEquals(i, actual.nextInt()); + } + } else { + fail("expected step != 0"); + } + assertFalse(actual.hasNext(), "Expected exhausted iterator"); + } + + /** + * Test method for {@link common.iterable.Range#closed(int)}. + */ + @ParameterizedTest + @MethodSource({"getEmptyRangeArguments", "getSingletonRangeArguments", "getMultitonRangeArguments"}) + void testClosedInt(int start, int stop, int step) + { + if (step > 0 && start == 0) { + // range with positive step width starting at 0 + // adjust stop to maybe be included + int closed = (step > 0) ? stop - 1 : stop + 1; + Range actual = Range.closed(closed); + assertEqualsClosedForLoop(0, closed, 1, actual); + } + } + + /** + * Test method for {@link common.iterable.Range#closed(int, int)}. + */ + @ParameterizedTest + @MethodSource({"getEmptyRangeArguments", "getSingletonRangeArguments", "getMultitonRangeArguments"}) + void testClosedIntInt(int start, int stop, int step) + { + if (step > 0) { + // range with positive step width + // adjust stop to maybe be included + int closed = (step > 0) ? stop - 1 : stop + 1; + Range actual = Range.closed(start, closed); + assertEqualsClosedForLoop(start, closed, 1, actual); + } + } + + /** + * Test method for {@link common.iterable.Range#closed(int, int, int)}. + */ + @ParameterizedTest + @MethodSource({"getEmptyRangeArguments", "getSingletonRangeArguments", "getMultitonRangeArguments"}) + void testClosedIntIntInt(int start, int stop, int step) + { + // adjust stop to maybe be included + int closed = (step > 0) ? stop - 1 : stop + 1; + Range actual = Range.closed(start, closed, step); + assertEqualsClosedForLoop(start, closed, step, actual); + } + + /** + * Test method for {@link common.iterable.Range#Range(int)}. + */ + @ParameterizedTest + @MethodSource({"getEmptyRangeArguments", "getSingletonRangeArguments", "getMultitonRangeArguments"}) + void testRangeInt(int start, int stop, int step) + { + if (step > 0 && start == 0) { + // range with positive step width starting at 0 + Range actual = new Range(stop); + assertEqualsOpenForLoop(0, stop, 1, actual); + } + } + + /** + * Test method for {@link common.iterable.Range#Range(int, int)}. + */ + @ParameterizedTest + @MethodSource({"getEmptyRangeArguments", "getSingletonRangeArguments", "getMultitonRangeArguments"}) + void testRangeIntInt(int start, int stop, int step) + { + if (step > 0) { + // range with positive step width + Range actual = new Range(start, stop); + assertEqualsOpenForLoop(start, stop, 1, actual); + } + } + + /** + * Test method for {@link common.iterable.Range#Range(int, int, int, boolean)}. + */ + @ParameterizedTest + @MethodSource({"getEmptyRangeArguments", "getSingletonRangeArguments", "getMultitonRangeArguments"}) + void testRangeIntIntInt(int start, int stop, int step) + { + Range actual = new Range(start, stop, step); + assertEqualsOpenForLoop(start, stop, step, actual); + } + + @Test + void testRangeStepZero() + { + assertThrows(IllegalArgumentException.class, () -> new Range(1, 2, 0)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + void testIsAscending(Supplier supplier) + { + Range range = supplier.get(); + if (range.isEmpty() || range.isSingleton()) { + assertTrue(range.isAscending()); + } else if (range.step > 0) { + assertTrue(range.isAscending()); + } else if(range.step < 0) { + assertFalse(range.isAscending()); + } else { + fail("expected step != 0"); + } + } + + @ParameterizedTest + @MethodSource("getReducibles") + void testIsSingleton(Supplier supplier) + { + Range range = supplier.get(); + assertTrue(range.count() !=1 ^ range.isSingleton()); + } + + @ParameterizedTest + @MethodSource("getReducibles") + void testReversed(Supplier supplier) + { + Range range = supplier.get(); + if (range.first == Integer.MIN_VALUE && !range.isEmpty()) { + // reverse() at min value throws + assertThrows(ArithmeticException.class, range::reversed); + } else if (range.first == Integer.MAX_VALUE && !range.isEmpty()) { + // reverse() at min value throws + assertThrows(ArithmeticException.class, range::reversed); + } else { + assertEqualsClosedForLoop(range.last, range.first, -range.step, range.reversed()); + } + } + + /** + * Test method for {@link common.iterable.Range#toString()}. + */ + @ParameterizedTest + @MethodSource("getReducibles") + void testToString(Supplier supplier) + { + Range range = supplier.get(); + String expected = "Range.closed(" + range.first + ", " + range.last + ", " + range.step + ")"; + String actual = range.toString(); + assertEquals(expected, actual); + } + + @Test + void testEqualsAndHash() + { + Range range = Range.closed(-2, 4, 3); // {-2, 1, 4} + + // equal to itself + assertEquals(range, range); + + // equal to a clone + Range clone = Range.closed(-2, 4, 3); + assertEquals(range, clone); + assertEquals(range.hashCode(), clone.hashCode()); + + // not equal to null or other type + assertFalse(range.equals(null)); + assertFalse(range.equals("no")); + + // not equal to an arbitrary range + Range otherStart = Range.closed(-5, 4, 3); // {-5, -2, 1, 4} + assertNotEquals(otherStart, range); + Range otherStop = Range.closed(-2, 7, 3); // {-2, 1, 4, 7} + assertNotEquals(otherStop, range); + Range otherStep = Range.closed(-2, 4, 2); // {-2, 0, 2, 4} + assertNotEquals(otherStep, range); + } + + @ParameterizedTest + @MethodSource({"getEmptyRangeArguments"}) + void testEqualsAndHashEmpty(int start, int stop, int step) + { + Range expected = new Range(0); + Range actual = new Range(start, stop, step); + assertEquals(expected, actual); + assertEquals(expected.hashCode(), actual.hashCode()); + } + + @ParameterizedTest + @MethodSource({"getSingletonRangeArguments"}) + void testEqualsAndHashSingleton(int start, int stop, int step) + { + Range expected = new Range(start, stop, step > 0 ? 1 : -1); + Range actual = new Range(start, stop, step); + assertEquals(expected, actual); + assertEquals(expected.hashCode(), actual.hashCode()); + } + + + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + class RangeIteratorTest implements FunctionalPrimitiveIteratorTest.OfInt + { + @Override + public Range.RangeIterator getReducible(int[] arguments) + { + throw new RuntimeException("Should not be called"); + } + + @Override + public Stream> getDuplicatesReducibles() + { + return Stream.empty(); + } + + @Override + public Stream> getEmptyReducibles() + { + return getEmptyRangeArguments().map(args -> () -> asRange(args).iterator()); + } + + @Override + public Stream> getSingletonReducibles() + { + return getSingletonRangeArguments().map(args -> () -> asRange(args).iterator()); + } + + @Override + public Stream> getMultitonReducibles() + { + return getMultitonRangeArguments().map(args -> () -> asRange(args).iterator()); + } + } +} diff --git a/prism/unit-tests/common/iterable/ReducibleStaticTest.java b/prism/unit-tests/common/iterable/ReducibleStaticTest.java new file mode 100644 index 0000000000..68ed32871b --- /dev/null +++ b/prism/unit-tests/common/iterable/ReducibleStaticTest.java @@ -0,0 +1,440 @@ +package common.iterable; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.*; +import java.util.stream.Stream; + +import static common.iterable.Assertions.assertIterableEquals; +import static common.iterable.Assertions.assertIteratorEquals; +import static org.junit.jupiter.api.Assertions.assertIterableEquals; +import static org.junit.jupiter.api.Assertions.*; + +class ReducibleStaticTest +{ + static Stream> getIterables() + { + return Stream.of(Collections.singleton(null), + Collections.emptyList(), + Collections.singleton("one"), + Arrays.asList("one", "two", "three")); + } + + static Stream> getIterablesNull() + { + return Stream.of(Collections.singleton(null)); + } + + static Stream> getIterablesDouble() + { + return Stream.of(Collections.emptyList(), + Collections.singleton(1.0), + Arrays.asList(1.0, 2.0, 3.0)); + } + + static Stream> getIterablesInt() + { + return Stream.of(Collections.emptyList(), + Collections.singleton(1), + Arrays.asList(1, 2, 3)); + } + + static Stream> getIterablesLong() + { + return Stream.of(Collections.emptyList(), + Collections.singleton(1L), + Arrays.asList(1L, 2L, 3L)); + } + + @ParameterizedTest + @MethodSource("getIterables") + @DisplayName("extend() yields same sequence as the underlying iterable.") + void testExtendIterable(Iterable iterable) + { + FunctionalIterable actual = Reducible.extend(iterable); + assertIterableEquals(iterable, actual); + } + + @ParameterizedTest + @MethodSource("getIterables") + @DisplayName("extend() yields same sequence as the underlying iterator.") + void testExtendIterator(Iterable iterable) + { + Iterator expected = iterable.iterator(); + FunctionalIterator actual = Reducible.extend(iterable.iterator()); + assertIteratorEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getIterables") + @DisplayName("extend() does not extend a FunctionalIterable.") + void testExtendFunctionalIterable(Iterable iterable) + { + Iterable expected = Reducible.extend(iterable); + FunctionalIterable actual = Reducible.extend(expected); + assertSame(expected, actual); + } + + @ParameterizedTest + @MethodSource("getIterables") + @DisplayName("extend() does not extend a FunctionalIterator.") + void testExtendFunctionalIterator(Iterable iterable) + { + Iterator expected = Reducible.extend(iterable.iterator()); + FunctionalIterator actual = Reducible.extend(expected); + assertSame(expected, actual); + } + + @ParameterizedTest + @MethodSource("getIterablesDouble") + @DisplayName("extend() does not extend a FunctionalPrimitiveIterable.OfDouble.") + void testExtendFunctionalPrimitiveIterableOfDouble(Iterable iterable) + { + PrimitiveIterable.OfDouble expected = Reducible.extend(PrimitiveIterable.unboxDouble(iterable)); + FunctionalIterable functional = Reducible.extend(expected); + assertSame(expected, functional); + } + + @ParameterizedTest + @MethodSource("getIterablesDouble") + @DisplayName("extend() does not extend a FunctionalPrimitiveIterator.OfDouble.") + void testExtendFunctionalPrimitiveIteratorOfDouble(Iterable iterable) + { + PrimitiveIterator.OfDouble expected = Reducible.extend(PrimitiveIterable.unboxDouble(iterable.iterator())); + FunctionalIterator actual = Reducible.extend(expected); + assertSame(expected, actual); + } + + @ParameterizedTest + @MethodSource("getIterablesInt") + @DisplayName("extend() does not extend a FunctionalPrimitiveIterable.OfInt.") + void testExtendFunctionalPrimitiveIterableOfInt(Iterable iterable) + { + PrimitiveIterable.OfInt expected = Reducible.extend(PrimitiveIterable.unboxInt(iterable)); + FunctionalIterable actual = Reducible.extend(expected); + assertSame(expected, actual); + } + + @ParameterizedTest + @MethodSource("getIterablesInt") + @DisplayName("extend() does not extend a FunctionalPrimitiveIterator.OfInt.") + void testExtendFunctionalPrimitiveIteratorOfInt(Iterable iterable) + { + PrimitiveIterator.OfInt expected = Reducible.extend(PrimitiveIterable.unboxInt(iterable.iterator())); + FunctionalIterator actual = Reducible.extend(expected); + assertSame(expected, actual); + } + + @ParameterizedTest + @MethodSource("getIterablesLong") + @DisplayName("extend() does not extend a FunctionalPrimitiveIterable.OfLong.") + void testExtendFunctionalPrimitiveIterableOfLong(Iterable iterable) + { + PrimitiveIterable.OfLong expected = Reducible.extend(PrimitiveIterable.unboxLong(iterable)); + FunctionalIterable actual = Reducible.extend(expected); + assertSame(expected, actual); + } + + @ParameterizedTest + @MethodSource("getIterablesLong") + @DisplayName("extend() does not extend a FunctionalPrimitiveIterator.OfLong.") + void testExtendFunctionalPrimitiveIteratorOfLong(Iterable iterable) + { + PrimitiveIterator.OfLong expected = Reducible.extend(PrimitiveIterable.unboxLong(iterable).iterator()); + FunctionalIterator actual = Reducible.extend(expected); + assertSame(expected, actual); + } + + @ParameterizedTest + @MethodSource("getIterablesDouble") + @DisplayName("extend() extends OfDouble to FunctionalPrimitiveIterable.") + void testExtendPrimitiveIterableOfDouble(Iterable iterable) + { + Iterable primitive = PrimitiveIterable.unboxDouble(iterable); + FunctionalIterable actual = Reducible.extend(primitive); + assertTrue(actual instanceof FunctionalPrimitiveIterable); + } + + @ParameterizedTest + @MethodSource("getIterablesDouble") + @DisplayName("extend() extends OfDouble to FunctionalPrimitiveIterator.") + void testExtendPrimitiveIteratorOfDouble(Iterable iterable) + { + Iterator primitive = PrimitiveIterable.unboxDouble(iterable).iterator(); + FunctionalIterator actual = Reducible.extend(primitive); + assertTrue(actual instanceof FunctionalPrimitiveIterator); + } + + @ParameterizedTest + @MethodSource("getIterablesInt") + @DisplayName("extend() extends OfInt to FunctionalPrimitiveIterable.") + void testExtendPrimitiveIterableOfInt(Iterable iterable) + { + Iterable primitive = PrimitiveIterable.unboxInt(iterable); + FunctionalIterable actual = Reducible.extend(primitive); + assertTrue(actual instanceof FunctionalPrimitiveIterable); + } + + @ParameterizedTest + @MethodSource("getIterablesInt") + @DisplayName("extend() extends OfInt to FunctionalPrimitiveIterator.") + void testExtendPrimitiveIteratorOfInt(Iterable iterable) + { + Iterator primitive = PrimitiveIterable.unboxInt(iterable.iterator()); + FunctionalIterator actual = Reducible.extend(primitive); + assertTrue(actual instanceof FunctionalPrimitiveIterator); + } + + @ParameterizedTest + @MethodSource("getIterablesLong") + @DisplayName("extend() extends OfLong to FunctionalPrimitiveIterable.") + void testExtendPrimitiveIterableOfLong(Iterable iterable) + { + Iterable primitive = PrimitiveIterable.unboxLong(iterable); + FunctionalIterable actual = Reducible.extend(primitive); + assertTrue(actual instanceof FunctionalPrimitiveIterable); + } + + @ParameterizedTest + @MethodSource("getIterablesLong") + @DisplayName("extend() extends OfLong to FunctionalPrimitiveIterator.") + void testExtendPrimitiveIteratorOfLong(Iterable iterable) + { + Iterator primitive = PrimitiveIterable.unboxLong(iterable).iterator(); + FunctionalIterator actual = Reducible.extend(primitive); + assertTrue(actual instanceof FunctionalPrimitiveIterator); + } + + @Test + @DisplayName("extend() with null throws NullPointerException.") + void testExtendIterable_Null() + { + assertThrows(NullPointerException.class, () -> Reducible.extend((Iterable) null)); + } + + @Test + @DisplayName("extend() with null throws NullPointerException.") + void testExtendIterator_Null() + { + assertThrows(NullPointerException.class, () -> Reducible.extend((Iterator) null)); + } + + @ParameterizedTest + @MethodSource("getIterablesDouble") + @DisplayName("unboxDouble() yields same sequence as the underlying iterable.") + void testUnboxDoubleIterable(Iterable iterable) + { + PrimitiveIterable.OfDouble expected = PrimitiveIterable.unboxDouble(iterable); + FunctionalPrimitiveIterable.OfDouble actual = Reducible.unboxDouble(iterable); + assertIterableEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getIterablesDouble") + @DisplayName("unboxDouble() yields same sequence as the underlying iterator.") + void testUnboxDoubleIterator(Iterable iterable) + { + PrimitiveIterator.OfDouble expected = PrimitiveIterable.unboxDouble(iterable.iterator()); + FunctionalPrimitiveIterator.OfDouble actual = Reducible.unboxDouble(iterable.iterator()); + assertIteratorEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getIterablesDouble") + @DisplayName("unboxDouble() does not unbox a FunctionalPrimitiveIterable.OfDouble.") + void testUnboxDoubleIterableOfDouble(Iterable iterable) + { + PrimitiveIterable.OfDouble expected = Reducible.extend(PrimitiveIterable.unboxDouble(iterable)); + FunctionalPrimitiveIterable.OfDouble actual = Reducible.unboxDouble(expected); + assertSame(expected, actual); + } + + @ParameterizedTest + @MethodSource("getIterablesDouble") + @DisplayName("unboxDouble() does not unbox a FunctionalPrimitiveIterator.OfDouble.") + void testUnboxDoubleIteratorOfDouble(Iterable iterable) + { + PrimitiveIterator.OfDouble expected = Reducible.extend(PrimitiveIterable.unboxDouble(iterable.iterator())); + FunctionalPrimitiveIterator.OfDouble actual = Reducible.unboxDouble(expected); + assertSame(expected, actual); + } + + @Test + @DisplayName("unboxDouble() with null throws NullPointerException.") + void testUnboxDoubleIterable_Null() + { + assertThrows(NullPointerException.class, () -> Reducible.unboxDouble((Iterable) null)); + } + + @Test + @DisplayName("unboxDouble() with null throws NullPointerException.") + void testUnboxDoubleIterator_Null() + { + assertThrows(NullPointerException.class, () -> Reducible.unboxDouble((Iterator) null)); + } + + @ParameterizedTest + @MethodSource("getIterablesNull") + @DisplayName("unboxDouble() with an Iterable containing null throws NullPointerException.") + void testUnboxDoubleIterable_NullValues(Iterable iterable) + { + FunctionalPrimitiveIterable.OfDouble primitive = Reducible.unboxDouble(iterable); + assertThrows(NullPointerException.class, primitive::consume); + } + + @ParameterizedTest + @MethodSource("getIterablesNull") + @DisplayName("unboxDouble() with an Iterator containing null throws NullPointerException.") + void testUnboxDoubleIterator_NullValues(Iterable iterable) + { + FunctionalPrimitiveIterator.OfDouble primitive = Reducible.unboxDouble(iterable.iterator()); + assertThrows(NullPointerException.class, primitive::consume); + } + + @ParameterizedTest + @MethodSource("getIterablesInt") + @DisplayName("unboxInt() yields same sequence as the underlying iterable.") + void testUnboxIntIterable(Iterable iterable) + { + PrimitiveIterable.OfInt expected = PrimitiveIterable.unboxInt(iterable); + FunctionalPrimitiveIterable.OfInt actual = Reducible.unboxInt(iterable); + assertIterableEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getIterablesInt") + @DisplayName("unboxInt() yields same sequence as the underlying iterator.") + void testUnboxIntIterator(Iterable iterable) + { + PrimitiveIterator.OfInt expected = PrimitiveIterable.unboxInt(iterable.iterator()); + FunctionalPrimitiveIterator.OfInt actual = Reducible.unboxInt(iterable.iterator()); + assertIteratorEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getIterablesInt") + @DisplayName("unboxInt() does not unbox a FunctionalPrimitiveIterable.OfInt.") + void testUnboxIntIterableOfInt(Iterable iterable) + { + PrimitiveIterable.OfInt expected = Reducible.extend(PrimitiveIterable.unboxInt(iterable)); + FunctionalPrimitiveIterable.OfInt actual = Reducible.unboxInt(expected); + assertSame(expected, actual); + } + + @ParameterizedTest + @MethodSource("getIterablesInt") + @DisplayName("unboxInt() does not unbox a FunctionalPrimitiveIterator.OfInt.") + void testUnboxIntIteratorOfInt(Iterable iterable) + { + PrimitiveIterator.OfInt expected = Reducible.extend(PrimitiveIterable.unboxInt(iterable.iterator())); + FunctionalPrimitiveIterator.OfInt actual = Reducible.unboxInt(expected); + assertSame(expected, actual); + } + + @Test + @DisplayName("unboxInt() with null throws NullPointerException.") + void testUnboxIntIterable_Null() + { + assertThrows(NullPointerException.class, () -> Reducible.unboxInt((Iterable) null)); + } + + @Test + @DisplayName("unboxInt() with null throws NullPointerException.") + void testUnboxIntIterator_Null() + { + assertThrows(NullPointerException.class, () -> Reducible.unboxInt((Iterator) null)); + } + + @ParameterizedTest + @MethodSource("getIterablesNull") + @DisplayName("unboxInt() with an Iterable containing null throws NullPointerException.") + void testUnboxIntIterable_NullValues(Iterable iterable) + { + FunctionalPrimitiveIterable.OfInt primitive = Reducible.unboxInt(iterable); + assertThrows(NullPointerException.class, primitive::consume); + } + + @ParameterizedTest + @MethodSource("getIterablesNull") + @DisplayName("unboxInt() with an Iterator containing null throws NullPointerException.") + void testUnboxIntIterator_NullValues(Iterable iterable) + { + FunctionalPrimitiveIterator.OfInt primitive = Reducible.unboxInt(iterable.iterator()); + assertThrows(NullPointerException.class, primitive::consume); + } + + @ParameterizedTest + @MethodSource("getIterablesLong") + @DisplayName("unboxLong() yields same sequence as the underlying iterable.") + void testUnboxLongIterable(Iterable iterable) + { + PrimitiveIterable.OfLong expected = PrimitiveIterable.unboxLong(iterable); + FunctionalPrimitiveIterable.OfLong actual = Reducible.unboxLong(iterable); + assertIterableEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getIterablesLong") + @DisplayName("unboxLong() yields same sequence as the underlying iterator.") + void testUnboxLong(Iterable iterable) + { + PrimitiveIterator.OfLong expected = PrimitiveIterable.unboxLong(iterable.iterator()); + FunctionalPrimitiveIterator.OfLong actual = Reducible.unboxLong(iterable.iterator()); + assertIteratorEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getIterablesLong") + @DisplayName("unboxLong() does not unbox a FunctionalPrimitiveIterable.OfDouble.") + void testUnboxLongIterableOfLong(Iterable iterable) + { + PrimitiveIterable.OfLong expected = Reducible.extend(PrimitiveIterable.unboxLong(iterable)); + FunctionalPrimitiveIterable.OfLong actual = Reducible.unboxLong(expected); + assertSame(expected, actual); + } + + @ParameterizedTest + @MethodSource("getIterablesLong") + @DisplayName("unboxLong() does not unbox a FunctionalPrimitiveIterator.OfDouble.") + void testUnboxLongIteratorOfLong(Iterable iterable) + { + PrimitiveIterator.OfLong expected = Reducible.extend(PrimitiveIterable.unboxLong(iterable.iterator())); + FunctionalPrimitiveIterator.OfLong actual = Reducible.unboxLong(expected); + assertSame(expected, actual); + } + + @Test + @DisplayName("unboxLong() with null throws NullPointerException.") + void testUnboxLongIterable_Null() + { + assertThrows(NullPointerException.class, () -> Reducible.unboxLong((Iterable) null)); + } + + @Test + @DisplayName("unboxLong() with null throws NullPointerException.") + void testUnboxLongIterator_Null() + { + assertThrows(NullPointerException.class, () -> Reducible.unboxLong((Iterator) null)); + } + + @ParameterizedTest + @MethodSource("getIterablesNull") + @DisplayName("unboxInt() with an Iterable containing null throws NullPointerException.") + void testUnboxLongIterable_NullValues(Iterable iterable) + { + FunctionalPrimitiveIterable.OfLong primitive = Reducible.unboxLong(iterable); + assertThrows(NullPointerException.class, primitive::consume); + } + + @ParameterizedTest + @MethodSource("getIterablesNull") + @DisplayName("unboxInt() with an Iterator containing null throws NullPointerException.") + void testUnboxLongIterator_NullValues(Iterable iterable) + { + FunctionalPrimitiveIterator.OfLong primitive = Reducible.unboxLong(iterable.iterator()); + assertThrows(NullPointerException.class, primitive::consume); + } +} diff --git a/prism/unit-tests/common/iterable/ReducibleTest.java b/prism/unit-tests/common/iterable/ReducibleTest.java new file mode 100644 index 0000000000..6932b474a9 --- /dev/null +++ b/prism/unit-tests/common/iterable/ReducibleTest.java @@ -0,0 +1,920 @@ +package common.iterable; + +import common.functions.DoubleObjToDoubleFunction; +import common.functions.IntObjToIntFunction; +import common.functions.LongObjToLongFunction; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.*; +import java.util.function.*; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.*; + +public interface ReducibleTest> +{ + default T getAnyReducible() + { + Optional> any = getReducibles().findAny(); + assert any.isPresent(); + return any.get().get(); + } + + default Stream> getReducibles() + { + return Stream.concat(Stream.concat(getEmptyReducibles(), getSingletonReducibles()), getMultitonReducibles()); + } + + Stream> getDuplicatesReducibles(); + + Stream> getEmptyReducibles(); + + Stream> getSingletonReducibles(); + + Stream> getMultitonReducibles(); + + Iterable getExcluded(T reducible); + + + + @ParameterizedTest + @MethodSource("getReducibles") + default void testCollectArray(Supplier supplier) + { + int n = (int) supplier.get().count(); + Object[] expected = new Object[n]; + Range.RangeIterator index = new Range(n).iterator(); + supplier.get().forEach(e -> expected[index.nextInt()] = e); + Object[] actual = supplier.get().collect((E[]) new Object[n]); // exploit that E[] is Object[] at runtime + assertArrayEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testCollectArrayOffset(Supplier supplier) + { + int n = (int) supplier.get().count(), offset = 2, tail = 3; + Object[] expected = new Object[offset + n + tail]; + Range.RangeIterator index = new Range(offset, offset + n).iterator(); + supplier.get().forEach(e -> expected[index.nextInt()] = e); + Object[] actual = supplier.get().collect((E[]) new Object[offset + n + tail], offset); // exploit that E[] is Object[] at runtime + assertArrayEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testCollectCollection(Supplier supplier) + { + List expected = new ArrayList<>(); + supplier.get().forEach(expected::add); + List actual = supplier.get().collect(new ArrayList<>()); + assertIterableEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testCollectSupplier(Supplier supplier) + { + List expected = new ArrayList<>(); + supplier.get().forEach(expected::add); + List actual = supplier.get().collect((Supplier>) ArrayList::new); + assertIterableEquals(expected, actual); + } + + @Test + default void testCollect_Null() + { + Reducible reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.collect((E[]) null)); + assertThrows(NullPointerException.class, () -> reducible.collect(null, 0)); + assertThrows(NullPointerException.class, () -> reducible.collect((Collection) null)); + assertThrows(NullPointerException.class, () -> reducible.collect((Supplier>) null)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testCollectAndCountArray(Supplier supplier) + { + int n = (int) supplier.get().count(), tail = 3; + Object[] expected = new Object[n + tail]; + Range.RangeIterator index = new Range(n).iterator(); + supplier.get().forEach(e -> expected[index.nextInt()] = e); + Object[] actual = new Object[n + tail]; + long count = supplier.get().collectAndCount((E[]) actual); // exploit that E[] is Object[] at runtime + assertEquals(n, count); + assertArrayEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testCollectAndCountArrayOffset(Supplier supplier) + { + int n = (int) supplier.get().count(), offset = 2, tail = 3; + Object[] expected = new Object[offset + n + tail]; + Range.RangeIterator index = new Range(offset, offset + n).iterator(); + supplier.get().forEach(e -> expected[index.nextInt()] = e); + Object[] actual = new Object[offset + n + tail]; + long count = supplier.get().collectAndCount((E[]) actual, offset); // exploit that E[] is Object[] at runtime + assertEquals(n, count); + assertArrayEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testCollectAndCountCollection(Supplier supplier) + { + List expected = new ArrayList<>(); + supplier.get().forEach(expected::add); + List actual = new ArrayList<>(); + long count = supplier.get().collectAndCount(actual); + assertEquals(expected.size(), count); + assertIterableEquals(expected, actual); + } + + @Test + default void testCollectAndCount_Null() + { + Reducible reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.collectAndCount((E[]) null)); + assertThrows(NullPointerException.class, () -> reducible.collectAndCount(null, 0)); + assertThrows(NullPointerException.class, () -> reducible.collectAndCount((Collection) null)); + } + + @ParameterizedTest + @MethodSource({"getReducibles", "getDuplicatesReducibles"}) + default void testCollectDistinct(Supplier supplier) + { + Set expected = new HashSet<>(); + supplier.get().forEach(expected::add); + List actual = supplier.get().collectDistinct().collect(new ArrayList<>()); + assertTrue(expected.containsAll(actual), "actual =< expected"); + assertTrue(actual.containsAll(expected), "actual >= expected"); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testConsume(Supplier supplier) + { + // Just test that consume yields the receiver. + // There is no way to test whether consume does anything beyond this. + T expected = supplier.get(); + Reducible actual = expected.consume(); + assertSame(expected, actual); + } + + void testConcat(Supplier supplier); + + @ParameterizedTest + @MethodSource({"getReducibles", "getDuplicatesReducibles"}) + default void testDistinct(Supplier supplier) + { + List expected = new ArrayList<>(); + supplier.get().forEach(e -> {if (! expected.contains(e)) expected.add(e);}); + List actual = supplier.get().distinct().collect(new ArrayList<>()); + assertEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource({"getReducibles", "getDuplicatesReducibles"}) + default void testDedupe(Supplier supplier) + { + List expected = new ArrayList<>(); + supplier.get().forEach(e -> { + Object last = expected.isEmpty() ? new Object() : expected.get(expected.size() - 1); + if (! Objects.equals(last, e)) { + expected.add(e); + } + }); + List actual = supplier.get().dedupe().collect(new ArrayList<>()); + assertEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testFilter(Supplier supplier) + { + ArrayList expected = new ArrayList<>(); + int n = supplier.get().reduce(0, (int c, E e) -> { + if (c % 2 == 0) expected.add(e); + return ++c; + }); + Range.RangeIterator index = new Range(n).iterator(); + Reducible actual = supplier.get().filter(e -> index.nextInt() % 2 == 0); + assertIterableEquals(expected, actual.collect(new ArrayList<>())); + } + + @Test + default void testFilter_Null() + { + Reducible reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.filter(null)); + } + + void testFlatMap(Supplier supplier); + + void testFlatMapToDouble(Supplier supplier); + + void testFlatMapToInt(Supplier supplier); + + void testFlatMapToLong(Supplier supplier); + + void testFlatMapToNull(Supplier supplier); + + void testFlatMap_Null(); + + @ParameterizedTest + @MethodSource("getReducibles") + default void testMap(Supplier supplier) + { + String prefix = "Item: "; + List expected = new ArrayList<>(); + supplier.get().forEach(e -> expected.add(prefix + e)); + Reducible actual = supplier.get().map(e -> prefix + e); + assertIterableEquals(expected, actual.collect(new ArrayList<>())); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testMapToDouble(Supplier supplier) + { + Range range = new Range((int) supplier.get().count()); + FunctionalIterable expected = range.map((int i) -> (double) i); + Range.RangeIterator index = range.iterator(); + PrimitiveReducible.OfDouble actual = supplier.get().mapToDouble(e -> index.next()); + assertIterableEquals(expected, actual.collect(new ArrayList<>())); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testMapToInt(Supplier supplier) + { + Range expected = new Range((int) supplier.get().count()); + Range.RangeIterator index = expected.iterator(); + PrimitiveReducible.OfInt actual = supplier.get().mapToInt(e -> index.next()); + assertIterableEquals(expected, actual.collect(new ArrayList<>())); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testMapToLong(Supplier supplier) + { + Range range = new Range((int) supplier.get().count()); + FunctionalIterable expected = range.map((int i) -> (long) i); + Range.RangeIterator index = range.iterator(); + PrimitiveReducible.OfLong actual = supplier.get().mapToLong(e -> index.next()); + assertIterableEquals(expected, actual.collect(new ArrayList<>())); + } + + @Test + default void testMap_Null() + { + Reducible reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.map(null)); + assertThrows(NullPointerException.class, () -> reducible.mapToDouble(null)); + assertThrows(NullPointerException.class, () -> reducible.mapToInt(null)); + assertThrows(NullPointerException.class, () -> reducible.mapToLong(null)); + } + + void testForEach(Supplier supplier); + + @Test + default void testForEach_Null() + { + Reducible reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.forEach(null)); + } + + @ParameterizedTest + @MethodSource("getEmptyReducibles") + default void testIsEmpty_Empty(Supplier supplier) + { + assertTrue(supplier.get().isEmpty()); + } + + @ParameterizedTest + @MethodSource({"getSingletonReducibles", "getMultitonReducibles"}) + default void testIsEmpty_NonEmpty(Supplier supplier) + { + assertFalse(supplier.get().isEmpty()); + } + + @ParameterizedTest + @MethodSource("getEmptyReducibles") + default void testReduceBinaryOperatorOfE_Empty(Supplier supplier) + { + BinaryOperator nop = (res, each) -> null; + Optional actual = supplier.get().reduce(nop); + assertEquals(Optional.empty(), actual); + } + + @ParameterizedTest + @MethodSource("getSingletonReducibles") + default void testReduceBinaryOperatorOfE_Singleton(Supplier supplier) + { + BinaryOperator nop = (res, each) -> null; + E expected = supplier.get().detect(e -> true); + if (expected == null) { + assertThrows(NullPointerException.class, () -> supplier.get().reduce(nop)); + } else { + Optional actual = supplier.get().reduce(nop); + assertTrue(actual.isPresent()); + assertEquals(expected, actual.get()); + } + } + + @ParameterizedTest + @MethodSource("getMultitonReducibles") + default void testReduceBinaryOperatorOfE_Multiton(Supplier supplier) + { + ArrayList expected = supplier.get().collect(new ArrayList<>()); + List actual = new ArrayList<>(); + E probe = (E) new Object(); // "unique" value, exploit that E is Object at runtime + BinaryOperator collect = (res, each) -> { + if (actual.isEmpty()) { + actual.add(res); + actual.add(each); + return (E) probe; + } else { + actual.add(each); + return res; + } + }; + Optional result = supplier.get().reduce(collect); + assertTrue(result.isPresent()); + assertEquals(probe, result.get()); + assertIterableEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getMultitonReducibles") + default void testReduceBinary_ResultNull(Supplier supplier) + { + Reducible reducible = supplier.get(); + assertThrows(NullPointerException.class, () -> reducible.reduce((res, each) -> null)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testReduce(Supplier supplier) + { + ArrayList expected = supplier.get().collect(new ArrayList<>()); + BiFunction, E, List> collect = (seq, each) -> {seq.add(each); return seq;}; + List actual = supplier.get().reduce(new ArrayList<>(), collect); + assertIterableEquals(expected, actual); + assertDoesNotThrow(() -> supplier.get().reduce(null, (obj, each) -> null)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testReduceDouble(Supplier supplier) + { + List expected = supplier.get().collect(new ArrayList<>()); + List actual = new ArrayList<>(); + DoubleObjToDoubleFunction collect = (res, each) -> {actual.add(each); return res;}; + double result = supplier.get().reduce(Double.MIN_VALUE, collect); + assertEquals(Double.MIN_VALUE, result); + assertIterableEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testReduceInt(Supplier supplier) + { + List expected = supplier.get().collect(new ArrayList<>()); + List actual = new ArrayList<>(); + IntObjToIntFunction collect = (res, each) -> {actual.add(each); return res;}; + int result = supplier.get().reduce(Integer.MIN_VALUE, collect); + assertEquals(Integer.MIN_VALUE, result); + assertIterableEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testReduceLong(Supplier supplier) + { + List expected = supplier.get().collect(new ArrayList<>()); + List actual = new ArrayList<>(); + LongObjToLongFunction collect = (res, each) -> {actual.add(each); return res;}; + long result = supplier.get().reduce(Long.MIN_VALUE, collect); + assertEquals(Long.MIN_VALUE, result); + assertIterableEquals(expected, actual); + } + + @Test + default void testReduce_Null() + { + Reducible reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.reduce(null)); + assertThrows(NullPointerException.class, () -> reducible.reduce(new Object(),null)); + assertThrows(NullPointerException.class, () -> reducible.reduce(0.0, null)); + assertThrows(NullPointerException.class, () -> reducible.reduce(0, (IntObjToIntFunction) null)); + assertThrows(NullPointerException.class, () -> reducible.reduce(0L, (LongObjToLongFunction) null)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testNonNull(Supplier supplier) + { + List expected = new ArrayList<>(); + supplier.get().forEach(e -> {if (e != null) expected.add(e);}); + Reducible actual = supplier.get().nonNull(); + assertIterableEquals(expected, actual.collect(new ArrayList<>())); + } + + @ParameterizedTest + @MethodSource({"getSingletonReducibles", "getMultitonReducibles"}) + default void testAllMatch(Supplier supplier) + { + // match all elements + assertTrue(supplier.get().allMatch(each -> true), "Expected allMatch() == true"); + // match not all elements + Predicate matchNotAll = new Predicate<>() { + // match: no element if singleton, otherwise every odd element + boolean flag = supplier.get().count() == 1; + @Override + public boolean test(E t) + { + flag = !flag; + return flag; + } + }; + assertFalse(supplier.get().allMatch(matchNotAll), "Expected allMatch() == false"); + } + + @ParameterizedTest + @MethodSource("getEmptyReducibles") + default void testAllMatch_Empty(Supplier supplier) + { + Reducible reducible = supplier.get(); + assertTrue(reducible.allMatch(each -> false), "Exepted allMatch() == true if reducible is empty"); + } + + @Test + default void testAllMatch_Null() + { + Reducible reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.allMatch(null)); + } + + @ParameterizedTest + @MethodSource({"getSingletonReducibles", "getMultitonReducibles"}) + default void testAnyMatch(Supplier supplier) + { + // match no element + assertFalse(supplier.get().anyMatch(each -> false), "Expected anyMatch() == false"); + // match some elements + Predicate matchSome = new Predicate<>() { + // match: first element if singleton, otherwise every even element + boolean flag = supplier.get().count() > 1; + @Override + public boolean test(E t) + { + flag = !flag; + return flag; + } + }; + assertTrue(supplier.get().anyMatch(matchSome), "Expected anyMatch() == true"); + } + + @ParameterizedTest + @MethodSource("getEmptyReducibles") + default void testAnyMatch_Empty(Supplier supplier) + { + Reducible reducible = supplier.get(); + assertFalse(reducible.anyMatch(each -> true), "Exepted anyMatch() == false if reducible is empty"); + } + + @Test + default void testAnyMatch_Null() + { + Reducible reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.anyMatch(null)); + } + + @ParameterizedTest + @MethodSource({"getSingletonReducibles", "getMultitonReducibles"}) + default void testNoneMatch(Supplier supplier) + { + // match no element + assertTrue(supplier.get().noneMatch(each -> false), "Expected noneMatch() == true"); + // match some elements + Predicate matchSome = new Predicate<>() { + // match: first element if singleton, otherwise every even element + boolean flag = supplier.get().count() > 1; + @Override + public boolean test(E t) + { + flag = !flag; + return flag; + } + }; + assertFalse(supplier.get().noneMatch(matchSome), "Expected noneMatch() == false"); + } + + @ParameterizedTest + @MethodSource("getEmptyReducibles") + default void testNoneMatch_Empty(Supplier supplier) + { + Reducible reducible = supplier.get(); + assertTrue(reducible.allMatch(each -> false), "Exepted noneMatch() == false if iterator is empty"); + } + + @Test + default void testNoneMatch_Null() + { + Reducible reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.noneMatch(null)); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testAsString(Supplier supplier) + { + String expected = "[" + supplier.get().reduce("", (str, each) -> str + (str.isEmpty() ? "" : ", ") + each) + "]"; + String actual = supplier.get().asString(); + assertEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testContains(Supplier supplier) + { + ArrayList elements = supplier.get().collect(new ArrayList<>()); + for (E each : elements) { + assertTrue(supplier.get().contains(each), "Expected contains(" + each + ") == true"); + } + for (Object each : getExcluded(supplier.get())) { + assertFalse(supplier.get().contains(each), "Expected contains(" + each + ") == false"); + } + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testCount(Supplier supplier) + { + ArrayList elements = supplier.get().collect(new ArrayList<>()); + long expected = elements.size(); + long actual = supplier.get().count(); + assertEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getReducibles") + default void testCountPredicate(Supplier supplier) + { + ArrayList elements = supplier.get().collect(new ArrayList<>()); + long expected = (elements.size() + 1) / 2; + Predicate odd = new Predicate<>() { + int i = 1; + @Override + public boolean test(E t) + { + return i++ % 2 == 1; + } + }; + long actual = supplier.get().count(odd); + assertEquals(expected, actual); + } + + @Test + default void testCountPredicate_Null() + { + Reducible reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.count(null)); + } + + + @ParameterizedTest + @MethodSource("getReducibles") + default void testDetect_AllFalse(Supplier supplier) + { + Reducible reducible = supplier.get(); + assertThrows(NoSuchElementException.class, () -> reducible.detect(each -> false)); + } + + @ParameterizedTest + @MethodSource("getEmptyReducibles") + default void testDetect_Empty(Supplier supplier) + { + Reducible reducible = supplier.get(); + assertThrows(NoSuchElementException.class, () -> reducible.detect(each -> true)); + } + + @ParameterizedTest + @MethodSource("getSingletonReducibles") + default void testDetect_Singleton(Supplier supplier) + { + // match first element + E expected = supplier.get().collect(new ArrayList<>()).get(0); + E actual = supplier.get().detect(each -> true); + assertEquals(expected, actual); + } + + @ParameterizedTest + @MethodSource("getMultitonReducibles") + default void testDetect_Multiton(Supplier supplier) + { + // match second element + E expected = supplier.get().collect(new ArrayList<>()).get(1); + Predicate second = new Predicate<>() { + boolean flag = true; + @Override + public boolean test(E each) + { + flag = !flag; + return flag; + } + }; + E actual = supplier.get().detect(second); + assertEquals(expected, actual); + } + + @Test + default void testDetect_Null() + { + Reducible reducible = getAnyReducible(); + assertThrows(NullPointerException.class, () -> reducible.detect(null)); + } + + + + interface Of> extends ReducibleTest + { + T getReducible(Object[] objects); + + @Override + default Stream> getDuplicatesReducibles() + { + return getDuplicatesArraysOfObject().map(args-> () -> getReducible(args)); + } + + @Override + default Stream> getEmptyReducibles() + { + return getEmptyArraysOfObject().map(args-> () -> getReducible(args)); + } + + @Override + default Stream> getSingletonReducibles() + { + return getSingletonArraysOfObject().map(args-> () -> getReducible(args)); + } + + @Override + default Stream> getMultitonReducibles() + { + return getMultitonArraysOfObject().map(args-> () -> getReducible(args)); + } + + @Override + default Iterable getExcluded(T iterable) + { + return getUniqueObjects(); + } + } + + + + // Test-data sets + + default Stream getArraysOfObject() + { + return Stream.concat(Stream.concat(getEmptyArraysOfObject(), getSingletonArraysOfObject()), getMultitonArraysOfObject()); + } + + /* Workaround to pass Object[] as argument */ + default Stream getArraysAsArguments() + { + return getArraysOfObject().map(array -> Arguments.of((Object) array)); + } + + default Stream getDuplicatesArraysOfObject() + { + return Stream.of( + new Object[] {null, null, + "first", "first", + "second", "second"}, + new Object[] {null, null, + "first", "first", + "third", "third", + "first", "first", + null, null}); + } + + default Stream getEmptyArraysOfObject() + { + return Stream.of(new Object[] {}); + } + + default Stream getSingletonArraysOfObject() + { + return Stream.of(new Object[] {"first"}, + new Object[] {null}); + } + + default Stream getMultitonArraysOfObject() + { + return Stream.of(new Object[] {"first", "second", "third"}, + new Object[] {null, "first", null, "second", null, "third", null}); + } + + /* Workaround to pass Object[] as argument */ + default Stream getMultitonArraysAsArguments() + { + return getMultitonArraysOfObject().map(array -> Arguments.of((Object) array)); + } + + default List getUniqueObjects() + { + return List.of(new Object(), new Object(), new Object()); + } + + default Stream getArraysOfDouble() + { + return Stream.concat(Stream.concat(getEmptyArraysOfDouble(), getSingletonArraysOfDouble()), getMultitonArraysOfDouble()); + } + + default Stream getDuplicatesArraysOfDouble() + { + return Stream.of(new double[] {-3.5, -3.5, + -2.0, -2.0, + -1.0, -1.0, + -0.0, +0.0, + +1.0, +1.0, + +2.0, +2.0, + +3.5, +3.5}, + new double[] {Double.NaN, Double.NaN, + Double.MIN_VALUE, Double.MIN_VALUE, + Double.MIN_NORMAL, Double.MIN_NORMAL, + Double.MAX_VALUE, Double.MAX_VALUE, + Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, + Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, + Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, + Double.MAX_VALUE, Double.MAX_VALUE, + Double.MIN_NORMAL, Double.MIN_NORMAL, + Double.MIN_VALUE, Double.MIN_VALUE, + Double.NaN, Double.NaN}); + } + + default Stream getEmptyArraysOfDouble() + { + return Stream.of(new double[] {}); + } + + default Stream getSingletonArraysOfDouble() + { + return Stream.of(new double[] {1.0}); + } + + default Stream getMultitonArraysOfDouble() + { + return Stream.of(new double[] {-3.5, -2.0, -1.0, 0.0, 1.0, 2.0, 3.5}, + new double[] {Double.NaN, + Double.MIN_VALUE, + Double.MIN_NORMAL, + Double.MAX_VALUE, + Double.NEGATIVE_INFINITY, + Double.POSITIVE_INFINITY,}); + } + + default List getExclusionListOfDouble() + { + List excluded = new ArrayList<>(); + excluded.add(Double.NaN); + excluded.add(Double.NEGATIVE_INFINITY); + excluded.add(-100000000.0); + excluded.add(-10000.0); + excluded.add(-100.0); + excluded.add(-10.0); + excluded.add(-2.0); + excluded.add(-1.0); + excluded.add(-0.0); + excluded.add(+0.0); + excluded.add(Double.MIN_VALUE); + excluded.add(Double.MIN_NORMAL); + excluded.add(1.0); + excluded.add(2.0); + excluded.add(10.0); + excluded.add(100.0); + excluded.add(10000.0); + excluded.add(100000000.0); + excluded.add(Double.MAX_VALUE); + excluded.add(Double.POSITIVE_INFINITY); + return excluded; + } + + default Stream getArraysOfInt() + { + return Stream.concat(Stream.concat(getEmptyArraysOfInt(), getSingletonArraysOfInt()), getMultitonArraysOfInt()); + } + + default Stream getDuplicatesArraysOfInt() + { + return Stream.of(new int[] {-3, -3, + -1, -1, + -2, -2, + -0, +0, + +1, +1, + +2, +2, + +3, +3}, + new int[] {Integer.MIN_VALUE, Integer.MIN_VALUE, + Integer.MAX_VALUE, Integer.MAX_VALUE, + Integer.MIN_VALUE, Integer.MIN_VALUE}); + } + + default Stream getEmptyArraysOfInt() + { + return Stream.of(new int[] {}); + } + + default Stream getSingletonArraysOfInt() + { + return Stream.of(new int[] {1}); + } + + default Stream getMultitonArraysOfInt() + { + return Stream.of(new int[] {-3, -2, -1, 0, 1, 2, 3}, + new int[] {Integer.MIN_VALUE, Integer.MAX_VALUE}); + } + + default List getExclusionListOfInt() + { + List excluded = new ArrayList<>(); + excluded.add(Integer.MIN_VALUE); + excluded.add(-100000000); + excluded.add(-10000); + excluded.add(-100); + excluded.add(-10); + excluded.add(-2); + excluded.add(-1); + excluded.add(0); + excluded.add(1); + excluded.add(2); + excluded.add(10); + excluded.add(100); + excluded.add(10000); + excluded.add(100000000); + excluded.add(Integer.MAX_VALUE); + return excluded; + } + + default Stream getArraysOfLong() + { + return Stream.concat(Stream.concat(getEmptyArraysOfLong(), getSingletonArraysOfLong()), getMultitonArraysOfLong()); + } + + default Stream getDuplicatesArraysOfLong() + { + return Stream.of(new long [] {-3L, -3L, + -2L, -2L, + -1L, -1L, + -0L, +0L, + +1L, +1L, + +2L, +2L, + +3L, +3L}, + new long[] {Long.MIN_VALUE, Long.MIN_VALUE, + Long.MAX_VALUE, Long.MAX_VALUE, + Long.MIN_VALUE, Long.MIN_VALUE}); + } + + default Stream getEmptyArraysOfLong() + { + return Stream.of(new long [] {}); + } + + default Stream getSingletonArraysOfLong() + { + return Stream.of(new long [] {1L}); + } + + default Stream getMultitonArraysOfLong() + { + return Stream.of(new long [] {-3L, -2L, -1L, 0L, 1L, 2L, 3L}, + new long[] {Long.MIN_VALUE, Long.MAX_VALUE}); + } + + default List getExclusionListOfLong() + { + List excluded = new ArrayList<>(); + excluded.add(Long.MIN_VALUE); + excluded.add(-100000000L); + excluded.add(-10000L); + excluded.add(-100L); + excluded.add(-10L); + excluded.add(-2L); + excluded.add(-1L); + excluded.add(0L); + excluded.add(1L); + excluded.add(2L); + excluded.add(10L); + excluded.add(100L); + excluded.add(10000L); + excluded.add(100000000L); + excluded.add(Long.MAX_VALUE); + return excluded; + } +} diff --git a/prism/unit-tests/common/iterable/SingletonIterableTest.java b/prism/unit-tests/common/iterable/SingletonIterableTest.java new file mode 100644 index 0000000000..4e5a4469be --- /dev/null +++ b/prism/unit-tests/common/iterable/SingletonIterableTest.java @@ -0,0 +1,322 @@ +package common.iterable; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.TestInstance; + +import java.util.function.Supplier; +import java.util.stream.Stream; + +interface SingletonIterableTest> extends FunctionalIterableTest +{ + @Override + default void testAllMatch_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + default void testAnyMatch_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + default void testDetect_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + default void testDetect_Multiton(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + default void testNoneMatch_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + default void testIsEmpty_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + default void testReduceBinary_ResultNull(Supplier supplier) + { /* singletons hold exactly one value */} + + @Override + default void testReduceBinaryOperatorOfE_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + default void testReduceBinaryOperatorOfE_Multiton(Supplier supplier) + { /* singletons hold exactly one value */ } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class Of implements SingletonIterableTest>, FunctionalIterableTest.Of> + { + @Override + public SingletonIterable.Of getReducible(Object[] objects) + { + assert objects.length == 1 : "singleton array expected"; + return new SingletonIterable.Of<>(objects[0]); + } + + @Override + public Stream>> getDuplicatesReducibles() + { + return Stream.empty(); + } + + @Override + public Stream>> getEmptyReducibles() + { + return Stream.empty(); + } + + @Override + public Stream>> getMultitonReducibles() + { + return Stream.empty(); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfDouble implements SingletonIterableTest, FunctionalPrimitiveIterableTest.OfDouble + { + @Override + public SingletonIterable.OfDouble getReducible(double[] numbers) + { + assert numbers.length == 1 : "singleton array expected"; + return new SingletonIterable.OfDouble(numbers[0]); + } + + @Override + public Stream> getDuplicatesReducibles() + { + return Stream.empty(); + } + + @Override + public Stream> getEmptyReducibles() + { + return Stream.empty(); + } + + @Override + public Stream> getMultitonReducibles() + { + return Stream.empty(); + } + + @Override + public void testAllMatch_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testAllMatchDoublePredicate_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testDetectDoublePredicate_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testDetectDoublePredicate_Multiton(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testNoneMatchDoublePredicate_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testMax_Multiton(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testMin_Multiton(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testReduceDoubleBinaryOperator_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testReduceDoubleBinaryOperator_Multiton(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testSum_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testMin_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testMax_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfInt implements SingletonIterableTest, FunctionalPrimitiveIterableTest.OfInt + { + @Override + public SingletonIterable.OfInt getReducible(int[] numbers) + { + assert numbers.length == 1 : "singleton array expected"; + return new SingletonIterable.OfInt(numbers[0]); + } + + @Override + public Stream> getDuplicatesReducibles() + { + return Stream.empty(); + } + + @Override + public Stream> getEmptyReducibles() + { + return Stream.empty(); + } + + @Override + public Stream> getMultitonReducibles() + { + return Stream.empty(); + } + + @Override + public void testAllMatch_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testAllMatchIntPredicate_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testDetectIntPredicate_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testDetectIntPredicate_Multiton(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testMax_Multiton(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testMin_Multiton(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testNoneMatchIntPredicate_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testReduceDoubleBinaryOperator_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testReduceDoubleBinaryOperator_Multiton(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testReduceIntBinaryOperator_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testReduceIntBinaryOperator_Multiton(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testReduceLongBinaryOperator_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testReduceLongBinaryOperator_Multiton(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testMin_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testMax_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfLong implements SingletonIterableTest, FunctionalPrimitiveIterableTest.OfLong + { + @Override + public SingletonIterable.OfLong getReducible(long[] numbers) + { + assert numbers.length == 1 : "singleton array expected"; + return new SingletonIterable.OfLong(numbers[0]); + } + + @Override + public Stream> getDuplicatesReducibles() + { + return Stream.empty(); + } + + @Override + public Stream> getEmptyReducibles() + { + return Stream.empty(); + } + + @Override + public Stream> getMultitonReducibles() + { + return Stream.empty(); + } + + @Override + public void testAllMatchLongPredicate_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testDetectLongPredicate_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testDetectLongPredicate_Multiton(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testMax_Multiton(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testMin_Multiton(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testNoneMatchLongPredicate_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testReduceLongBinaryOperator_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testReduceLongBinaryOperator_Multiton(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testMin_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testMax_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + } +} diff --git a/prism/unit-tests/common/iterable/SingletonIteratorTest.java b/prism/unit-tests/common/iterable/SingletonIteratorTest.java new file mode 100644 index 0000000000..56f146052e --- /dev/null +++ b/prism/unit-tests/common/iterable/SingletonIteratorTest.java @@ -0,0 +1,322 @@ +package common.iterable; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.TestInstance; + +import java.util.function.Supplier; +import java.util.stream.Stream; + +interface SingletonIteratorTest> extends FunctionalIteratorTest +{ + @Override + default void testAllMatch_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + default void testAnyMatch_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + default void testDetect_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + default void testDetect_Multiton(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + default void testNoneMatch_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + default void testIsEmpty_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + default void testReduceBinary_ResultNull(Supplier supplier) + { /* singletons hold exactly one value */} + + @Override + default void testReduceBinaryOperatorOfE_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + default void testReduceBinaryOperatorOfE_Multiton(Supplier supplier) + { /* singletons hold exactly one value */ } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class Of implements SingletonIteratorTest>, FunctionalIteratorTest.Of> + { + @Override + public SingletonIterator.Of getReducible(Object[] objects) + { + assert objects.length == 1 : "singleton array expected"; + return new SingletonIterator.Of<>(objects[0]); + } + + @Override + public Stream>> getDuplicatesReducibles() + { + return Stream.empty(); + } + + @Override + public Stream>> getEmptyReducibles() + { + return Stream.empty(); + } + + @Override + public Stream>> getMultitonReducibles() + { + return Stream.empty(); + } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfDouble implements SingletonIteratorTest, FunctionalPrimitiveIteratorTest.OfDouble + { + @Override + public SingletonIterator.OfDouble getReducible(double[] numbers) + { + assert numbers.length == 1 : "singleton array expected"; + return new SingletonIterator.OfDouble(numbers[0]); + } + + @Override + public Stream> getDuplicatesReducibles() + { + return Stream.empty(); + } + + @Override + public Stream> getEmptyReducibles() + { + return Stream.empty(); + } + + @Override + public Stream> getMultitonReducibles() + { + return Stream.empty(); + } + + @Override + public void testAllMatch_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testAllMatchDoublePredicate_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testDetectDoublePredicate_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testDetectDoublePredicate_Multiton(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testNoneMatchDoublePredicate_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testMax_Multiton(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testMin_Multiton(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testReduceDoubleBinaryOperator_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testReduceDoubleBinaryOperator_Multiton(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testSum_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testMin_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testMax_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfInt implements SingletonIteratorTest, FunctionalPrimitiveIteratorTest.OfInt + { + @Override + public SingletonIterator.OfInt getReducible(int[] numbers) + { + assert numbers.length == 1 : "singleton array expected"; + return new SingletonIterator.OfInt(numbers[0]); + } + + @Override + public Stream> getDuplicatesReducibles() + { + return Stream.empty(); + } + + @Override + public Stream> getEmptyReducibles() + { + return Stream.empty(); + } + + @Override + public Stream> getMultitonReducibles() + { + return Stream.empty(); + } + + @Override + public void testAllMatch_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testAllMatchIntPredicate_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testDetectIntPredicate_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testDetectIntPredicate_Multiton(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testMax_Multiton(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testMin_Multiton(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testNoneMatchIntPredicate_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testReduceDoubleBinaryOperator_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testReduceDoubleBinaryOperator_Multiton(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testReduceIntBinaryOperator_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testReduceIntBinaryOperator_Multiton(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testReduceLongBinaryOperator_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testReduceLongBinaryOperator_Multiton(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testMin_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testMax_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + } + + + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class OfLong implements SingletonIteratorTest, FunctionalPrimitiveIteratorTest.OfLong + { + @Override + public SingletonIterator.OfLong getReducible(long[] numbers) + { + assert numbers.length == 1 : "singleton array expected"; + return new SingletonIterator.OfLong(numbers[0]); + } + + @Override + public Stream> getDuplicatesReducibles() + { + return Stream.empty(); + } + + @Override + public Stream> getEmptyReducibles() + { + return Stream.empty(); + } + + @Override + public Stream> getMultitonReducibles() + { + return Stream.empty(); + } + + @Override + public void testAllMatchLongPredicate_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testDetectLongPredicate_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testDetectLongPredicate_Multiton(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testMax_Multiton(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testMin_Multiton(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testNoneMatchLongPredicate_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testReduceLongBinaryOperator_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testReduceLongBinaryOperator_Multiton(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testMin_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + + @Override + public void testMax_Empty(Supplier supplier) + { /* singletons hold exactly one value */ } + } +}