diff --git a/java-batching-spliterator/README.MD b/java-batching-spliterator/README.MD new file mode 100644 index 0000000..e69de29 diff --git a/java-batching-spliterator/pom.xml b/java-batching-spliterator/pom.xml new file mode 100644 index 0000000..ea3dc73 --- /dev/null +++ b/java-batching-spliterator/pom.xml @@ -0,0 +1,64 @@ + + 4.0.0 + + com.pivovarit + 1.0 + java-batching-spliterator + + java-batching-spliterator + + + 1.35 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 21 + 21 + + + + maven-surefire-plugin + 2.19.1 + + + org.junit.platform + junit-platform-surefire-provider + 1.1.0 + + + + + + + + + org.junit.jupiter + junit-jupiter-engine + 5.8.2 + test + + + org.assertj + assertj-core + 3.22.0 + test + + + org.openjdk.jmh + jmh-core + ${jmh.version} + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh.version} + provided + + + diff --git a/java-batching-spliterator/src/main/java/com/pivovarit/stream/BatchingSpliterator.java b/java-batching-spliterator/src/main/java/com/pivovarit/stream/BatchingSpliterator.java new file mode 100644 index 0000000..3057198 --- /dev/null +++ b/java-batching-spliterator/src/main/java/com/pivovarit/stream/BatchingSpliterator.java @@ -0,0 +1,96 @@ +package com.pivovarit.stream; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Spliterator; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Stream; + +import static java.util.stream.Stream.empty; +import static java.util.stream.Stream.of; +import static java.util.stream.StreamSupport.stream; + +/** + * @author Grzegorz Piwowarek + */ +final class BatchingSpliterator implements Spliterator> { + + private final List source; + private final int maxChunks; + + private int chunks; + private int chunkSize; + private int consumed; + + private BatchingSpliterator(List list, int batches) { + if (batches < 1) { + throw new IllegalArgumentException("batches can't be lower than one"); + } + source = list; + chunks = batches; + maxChunks = Math.min(list.size(), batches); + chunkSize = (int) Math.ceil(((double) source.size()) / batches); + } + + static Stream> partitioned(List list, int numberOfParts) { + int size = list.size(); + + if (size <= numberOfParts) { + return asSingletonListStream(list); + } else if (size == 0) { + return empty(); + } else if (numberOfParts == 1) { + return of(list); + } else { + return stream(new BatchingSpliterator<>(list, numberOfParts), false); + } + } + + private static Stream> asSingletonListStream(List list) { + Stream.Builder> acc = Stream.builder(); + for (T t : list) { + acc.add(Collections.singletonList(t)); + } + return acc.build(); + } + + static Function, List> batching(Function mapper) { + return batch -> { + List list = new ArrayList<>(batch.size()); + for (T t : batch) { + list.add(mapper.apply(t)); + } + return list; + }; + } + + @Override + public boolean tryAdvance(Consumer> action) { + if (consumed < source.size() && chunks != 0) { + List batch = source.subList(consumed, consumed + chunkSize); + consumed += chunkSize; + chunkSize = (int) Math.ceil(((double) (source.size() - consumed)) / --chunks); + action.accept(batch); + return true; + } else { + return false; + } + } + + @Override + public Spliterator> trySplit() { + return null; + } + + @Override + public long estimateSize() { + return maxChunks; + } + + @Override + public int characteristics() { + return ORDERED | SIZED; + } +} diff --git a/pom.xml b/pom.xml index da6f3ab..c20fef1 100644 --- a/pom.xml +++ b/pom.xml @@ -23,6 +23,7 @@ java-archunit java-sealed-classes java-completable-future-timeouts + java-batching-spliterator java-event-sourcing java-completable-future-allof java-advanced-groupingby