/* * Copyright 2015, 2016 Tagir Valeev * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package one.util.streamex; import static org.junit.Assert.*; import static one.util.streamex.TestHelpers.*; import static java.util.Arrays.asList; import java.math.BigInteger; import java.util.Iterator; import java.util.function.BinaryOperator; import java.util.function.LongPredicate; import java.util.function.Predicate; import java.util.function.UnaryOperator; import one.util.streamex.DoubleStreamEx.DoubleEmitter; import one.util.streamex.IntStreamEx.IntEmitter; import one.util.streamex.LongStreamEx.LongEmitter; import one.util.streamex.StreamEx.Emitter; import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runners.MethodSorters; /** * @author Tagir Valeev */ @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class EmitterTest { // Like Java-9 Stream.iterate(seed, test, op) public static <T> Emitter<T> iterate(T seed, Predicate<? super T> test, UnaryOperator<T> op) { return test.test(seed) ? action -> { action.accept(seed); return iterate(op.apply(seed), test, op); } : null; } // Collatz sequence starting from given number public static Emitter<Integer> collatz(int start) { return action -> { action.accept(start); return start == 1 ? null : collatz(start % 2 == 0 ? start / 2 : start * 3 + 1); }; } public static IntEmitter collatzInt(int start) { return action -> { action.accept(start); return start == 1 ? null : collatzInt(start % 2 == 0 ? start / 2 : start * 3 + 1); }; } public static LongEmitter collatzLong(long start) { return action -> { action.accept(start); return start == 1 ? null : collatzLong(start % 2 == 0 ? start / 2 : start * 3 + 1); }; } // Stream of Fibonacci numbers public static StreamEx<BigInteger> fibonacci() { return fibonacci(BigInteger.ONE, BigInteger.ZERO).stream(); } private static Emitter<BigInteger> fibonacci(BigInteger first, BigInteger second) { return action -> { BigInteger next = first.add(second); action.accept(next); return fibonacci(second, next); }; } // Perform scanLeft on the iterator public static <T> Emitter<T> scanLeft(Iterator<T> iter, T initial, BinaryOperator<T> reducer) { return action -> { if (!iter.hasNext()) return null; T sum = reducer.apply(initial, iter.next()); action.accept(sum); return scanLeft(iter, sum, reducer); }; } public static Emitter<Integer> flatTest(int start) { return action -> { for (int i = 0; i < start; i++) action.accept(start); return start == 0 ? null : flatTest(start - 1); }; } public static IntEmitter flatTestInt(int start) { return action -> { for (int i = 0; i < start; i++) action.accept(start); return start == 0 ? null : flatTestInt(start - 1); }; } public static LongEmitter flatTestLong(int start) { return action -> { for (int i = 0; i < start; i++) action.accept(start); return start == 0 ? null : flatTestLong(start - 1); }; } public static DoubleEmitter flatTestDouble(int start) { return action -> { for (int i = 0; i < start; i++) action.accept(start); return start == 0 ? null : flatTestDouble(start - 1); }; } public static LongStreamEx primes() { return ((LongEmitter)(action -> { action.accept(2); return primes(3, x -> x % 2 != 0); })).stream(); } private static LongEmitter primes(long start, LongPredicate isPrime) { return action -> { long nextPrime = LongStreamEx.range(start, Long.MAX_VALUE, 2).findFirst(isPrime).getAsLong(); action.accept(nextPrime); return primes(nextPrime+2, isPrime.and(x -> x % nextPrime != 0)); }; } @Test public void testEmitter() { assertEquals(asList(17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1), collatz(17).stream().toList()); checkSpliterator("collatz", asList(17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1), collatz(17)::spliterator); assertArrayEquals(new int[] {17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1}, collatzInt(17).stream().toArray()); checkSpliterator("collatzInt", asList(17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1), collatzInt(17)::spliterator); assertArrayEquals(new long[] {17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1}, collatzLong(17).stream().toArray()); checkSpliterator("collatzLong", asList(17L, 52L, 26L, 13L, 40L, 20L, 10L, 5L, 16L, 8L, 4L, 2L, 1L), collatzLong(17)::spliterator); assertTrue(collatz(17).stream().has(1)); assertTrue(collatzInt(17).stream().has(1)); assertFalse(collatzLong(17).stream().has(0)); assertEquals(asList(1, 2, 3, 4, 5, 6, 7, 8, 9), iterate(1, x -> x < 10, x -> x + 1).stream().toList()); // Extracting to variables is necessary to work-around javac <8u40 bug String expected = "354224848179261915075"; String actual = fibonacci().skip(99).findFirst().get().toString(); assertEquals(expected, actual); assertEquals(asList(1, 1, 2, 3, 5, 8, 13, 21, 34, 55), fibonacci().map(BigInteger::intValueExact).limit(10) .toList()); assertEquals(asList("aa", "aabbb", "aabbbc"), scanLeft(asList("aa", "bbb", "c").iterator(), "", String::concat) .stream().toList()); assertEquals(asList(4, 4, 4, 4, 3, 3, 3, 2, 2, 1), flatTest(4).stream().toList()); assertEquals(asList(4, 4, 4, 4, 3, 3, 3, 2, 2), flatTest(4).stream().limit(9).toList()); checkSpliterator("flatTest", asList(4, 4, 4, 4, 3, 3, 3, 2, 2, 1), flatTest(4)::spliterator); checkSpliterator("flatTest", asList(4, 4, 4, 4, 3, 3, 3, 2, 2, 1), flatTestInt(4)::spliterator); checkSpliterator("flatTest", asList(4L, 4L, 4L, 4L, 3L, 3L, 3L, 2L, 2L, 1L), flatTestLong(4)::spliterator); checkSpliterator("flatTest", asList(4.0, 4.0, 4.0, 4.0, 3.0, 3.0, 3.0, 2.0, 2.0, 1.0), flatTestDouble(4)::spliterator); assertEquals(7919L, primes().skip(999).findFirst().getAsLong()); } }