diff --git a/src/main/java/com/pivovarit/gatherers/LastGatherer.java b/src/main/java/com/pivovarit/gatherers/LastGatherer.java index 0ab3b0d..e28ba23 100644 --- a/src/main/java/com/pivovarit/gatherers/LastGatherer.java +++ b/src/main/java/com/pivovarit/gatherers/LastGatherer.java @@ -6,56 +6,99 @@ import java.util.function.Supplier; import java.util.stream.Gatherer; -record LastGatherer( - long n) implements Gatherer, T> { - - LastGatherer { - if (n <= 0) { - throw new IllegalArgumentException("number of elements can't be lower than one"); - } +final class LastGatherer { + private LastGatherer() { } - @Override - public Supplier> initializer() { - return () -> new LastGatherer.AppendOnlyCircularBuffer<>((int) n); + static Gatherer size(int n) { + return switch (n) { + case 1 -> new SingleElementLastGatherer<>(); + default -> new CircularBufferLastGatherer<>(n); + }; } - @Override - public Integrator, T, T> integrator() { - return Integrator.ofGreedy((state, element, _) -> { - state.add(element); - return true; - }); - } + private record CircularBufferLastGatherer( + long n) implements Gatherer, T> { - @Override - public BiConsumer, Downstream> finisher() { - return (state, downstream) -> state.forEach(downstream::push); - } + CircularBufferLastGatherer { + if (n <= 0) { + throw new IllegalArgumentException("number of elements can't be lower than one"); + } + } - static class AppendOnlyCircularBuffer { - private final T[] buffer; - private final int maxSize; - private final AtomicInteger endIdx = new AtomicInteger(0); - private final AtomicInteger size = new AtomicInteger(0); + @Override + public Supplier> initializer() { + return () -> new AppendOnlyCircularBuffer<>((int) n); + } - public AppendOnlyCircularBuffer(int size) { - this.maxSize = size; - this.buffer = (T[]) new Object[size]; + @Override + public Integrator, T, T> integrator() { + return Integrator.ofGreedy((state, element, _) -> { + state.add(element); + return true; + }); } - public void add(T element) { - buffer[endIdx.getAndIncrement() % maxSize] = element; - if (size.get() < maxSize) { - size.incrementAndGet(); - } + @Override + public BiConsumer, Downstream> finisher() { + return (state, downstream) -> state.forEach(downstream::push); } - public void forEach(Consumer consumer) { - int startIdx = (endIdx.get() - size.get() + maxSize) % maxSize; - for (int i = 0; i < size.get(); i++) { - consumer.accept(buffer[(startIdx + i) % maxSize]); + static class AppendOnlyCircularBuffer { + private final T[] buffer; + private final int maxSize; + private final AtomicInteger endIdx = new AtomicInteger(0); + private final AtomicInteger size = new AtomicInteger(0); + + public AppendOnlyCircularBuffer(int size) { + this.maxSize = size; + this.buffer = (T[]) new Object[size]; } + + public void add(T element) { + buffer[endIdx.getAndIncrement() % maxSize] = element; + if (size.get() < maxSize) { + size.incrementAndGet(); + } + } + + public void forEach(Consumer consumer) { + int startIdx = (endIdx.get() - size.get() + maxSize) % maxSize; + for (int i = 0; i < size.get(); i++) { + consumer.accept(buffer[(startIdx + i) % maxSize]); + } + } + } + } + + private record SingleElementLastGatherer() implements Gatherer, T> { + + @Override + public Supplier> initializer() { + return ValueHolder::new; + } + + @Override + public Integrator, T, T> integrator() { + return Integrator.ofGreedy((state, element, _) -> { + state.value = element; + state.isSet = true; + return true; + }); + } + + @Override + public BiConsumer, Downstream> finisher() { + return (state, downstream) -> { + if (state.isSet) { + downstream.push(state.value); + } + }; + } + + static class ValueHolder { + private T value; + private boolean isSet; } } } diff --git a/src/main/java/com/pivovarit/gatherers/MoreGatherers.java b/src/main/java/com/pivovarit/gatherers/MoreGatherers.java index ae9d84e..0aea9c6 100644 --- a/src/main/java/com/pivovarit/gatherers/MoreGatherers.java +++ b/src/main/java/com/pivovarit/gatherers/MoreGatherers.java @@ -22,7 +22,7 @@ private MoreGatherers() { * @return a {@link Gatherer} that collects the last {@code n} elements */ public static Gatherer last(int n) { - return new LastGatherer<>(n); + return LastGatherer.size(n); } /**