import java.util.OptionalInt; import java.util.Random; import java.util.Spliterator; import java.util.Spliterators; import java.util.function.Consumer; import java.util.function.IntConsumer; import java.util.function.IntSupplier; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.IntStream; import java.util.stream.IntStream.Builder; import java.util.stream.StreamSupport; public class ProduceTest { public static IntStream produce(Supplier producer) { Spliterator.OfInt spliterator = new Spliterators.AbstractIntSpliterator( Long.MAX_VALUE, Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL) { boolean notFinished = true; @Override public boolean tryAdvance(IntConsumer action) { if (notFinished) { OptionalInt opt = producer.get(); opt.ifPresent(action); notFinished = opt.isPresent(); } return notFinished; } @Override public void forEachRemaining(IntConsumer action) { if (notFinished) { notFinished = false; for (OptionalInt opt = producer.get(); opt.isPresent(); opt = producer .get()) action.accept(opt.getAsInt()); } } }; return StreamSupport.intStream(spliterator, false); } public static IntStream produce(Predicate producer) { Spliterator.OfInt spliterator = new Spliterators.AbstractIntSpliterator( Long.MAX_VALUE, Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL) { boolean notFinished = true; @Override public boolean tryAdvance(IntConsumer action) { return notFinished && (notFinished = producer.test(action)); } @Override public void forEachRemaining(IntConsumer action) { if (notFinished) { notFinished = false; do { } while (producer.test(action)); } } }; return StreamSupport.intStream(spliterator, false); } public static IntStream produce(Consumer advancer) { Spliterator.OfInt spliterator = new Spliterators.AbstractIntSpliterator( Long.MAX_VALUE, Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL) { boolean notFinished = true; Spliterator.OfInt buffer; @Override public boolean tryAdvance(IntConsumer action) { if (notFinished) { if (buffer == null) { Builder builder = IntStream.builder(); advancer.accept(builder); buffer = builder.build().spliterator(); notFinished = false; } if (buffer.tryAdvance(action)) { notFinished = true; } else { buffer = null; } } return notFinished; } }; return StreamSupport.intStream(spliterator, false); } @FunctionalInterface interface IntEmitter { /** * Calls the supplied consumer zero or more times to emit some elements, * then returns the next emitter which will emit more, or null if nothing * more to emit. * * @param cons * consumer to be called to emit elements * @return next emitter or null */ IntEmitter next(IntConsumer cons); default Spliterator.OfInt spliterator() { return new Spliterators.AbstractIntSpliterator(Long.MAX_VALUE, Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL) { IntEmitter e = IntEmitter.this; Spliterator.OfInt buf; @Override public boolean tryAdvance(IntConsumer action) { if (!fillBuf()) return false; while (!buf.tryAdvance(action)) { buf = null; if (!fillBuf()) return false; } return true; } @Override public void forEachRemaining(IntConsumer action) { if (buf != null) { buf.forEachRemaining(action); buf = null; } IntEmitter e = this.e; this.e = null; while (e != null) e = e.next(action); } private boolean fillBuf() { while (buf == null) { if (e == null) return false; Builder b = IntStream.builder(); IntEmitter next = e.next(b); buf = b.build().spliterator(); e = next; } return true; } }; } default IntStream stream() { return StreamSupport.intStream(spliterator(), false); } } public static IntStream collatzSupplier(int start) { int[] cur = { -1 }; return produce(() -> cur[0] == 1 ? OptionalInt.empty() : OptionalInt .of(cur[0] = (cur[0] == -1 ? start : cur[0] % 2 == 0 ? cur[0] / 2 : cur[0] * 3 + 1))); } public static void collatzLoop(int start) { int val = start; System.out.println(val); while (val != 1) { val = val % 2 == 0 ? val / 2 : val * 3 + 1; System.out.println(val); } } public static IntStream collatzConsumer(int start) { int[] cur = { -1 }; return produce(action -> { if (cur[0] == -1) action.accept(cur[0] = start); if (cur[0] != 1) action.accept((cur[0] = cur[0] % 2 == 0 ? cur[0] / 2 : cur[0] * 3 + 1)); }); } public static IntStream collatzPredicate(int start) { int[] cur = { -1 }; return produce(action -> { if (cur[0] == 1) return false; action.accept(cur[0] = (cur[0] == -1 ? start : cur[0] % 2 == 0 ? cur[0] / 2 : cur[0] * 3 + 1)); return true; }); } public static IntEmitter collatzEmitter(int val) { return action -> { action.accept(val); return val == 1 ? null : collatzEmitter(val % 2 == 0 ? val / 2 : val * 3 + 1); }; } public static IntEmitter crapsEmitter(IntSupplier dice, int point) { return action -> { int roll = dice.getAsInt(); action.accept(roll); return roll == 7 || (point == 0 && (roll > 10 || roll < 4)) || (point != 0 && roll == point) ? null : crapsEmitter(dice, point == 0 ? roll : point); }; } public static void main(String[] args) { System.out.println("Loop"); collatzLoop(17); System.out.println("Consumer"); collatzConsumer(17).forEach(System.out::println); System.out.println("Supplier"); collatzSupplier(17).forEach(System.out::println); System.out.println("Predicate"); collatzPredicate(17).forEach(System.out::println); System.out.println("Emitter"); collatzEmitter(17).stream().forEach(System.out::println); System.out.println("Craps"); Random r = new Random(); IntSupplier dice = () -> r.nextInt(6) + r.nextInt(6) + 2; crapsEmitter(dice, 0).stream().forEach(System.out::println); } }