diff --git a/src/main/java/spliterators/part1/exercise/RectangleSpliterator.java b/src/main/java/spliterators/part1/exercise/RectangleSpliterator.java index 678f4f5..144a63b 100755 --- a/src/main/java/spliterators/part1/exercise/RectangleSpliterator.java +++ b/src/main/java/spliterators/part1/exercise/RectangleSpliterator.java @@ -3,44 +3,86 @@ import java.util.Spliterator; import java.util.Spliterators; +import java.util.function.Consumer; import java.util.function.IntConsumer; public class RectangleSpliterator extends Spliterators.AbstractIntSpliterator { - private final int innerLength; private final int[][] array; - private final int startOuterInclusive; - private final int endOuterExclusive; - private final int startInnerInclusive; + private int startOuterInclusive; + private int endOuterExclusive; + private int startInnerInclusive; + private int endInnerExclusive; public RectangleSpliterator(int[][] array) { - this(array, 0, array.length, 0); + this(array, 0, array.length, 0, array.length == 0 ? 0 : array[0].length); } - private RectangleSpliterator(int[][] array, int startOuterInclusive, int endOuterExclusive, int startInnerInclusive) { + private RectangleSpliterator(final int[][] array, + final int startOuterInclusive, + final int endOuterExclusive, + final int startInnerInclusive, + final int endInnerExclusive) { super(Long.MAX_VALUE, Spliterator.IMMUTABLE | Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.NONNULL); - innerLength = array.length == 0 ? 0 : array[0].length; + this.endInnerExclusive = endInnerExclusive; this.array = array; this.startOuterInclusive = startOuterInclusive; this.endOuterExclusive = endOuterExclusive; this.startInnerInclusive = startInnerInclusive; + innerLength = array.length == 0 ? 0 : array[0].length; } @Override public OfInt trySplit() { - // TODO - throw new UnsupportedOperationException(); + final int length = endOuterExclusive - startOuterInclusive; + if (length < 2) { + final int inLength = endInnerExclusive - startInnerInclusive; + if (inLength < 5) { + return null; + } else { + final int mid = startInnerInclusive + inLength / 2; + final RectangleSpliterator res = + new RectangleSpliterator(array, startOuterInclusive, endOuterExclusive, startInnerInclusive, mid); + startInnerInclusive = mid; + return res; + } + } + + final int mid = startOuterInclusive + length / 2; + final RectangleSpliterator res = + new RectangleSpliterator(array, startOuterInclusive, mid, startInnerInclusive, endInnerExclusive); + startOuterInclusive = mid; + return res; } @Override public long estimateSize() { - return ((long) endOuterExclusive - startOuterInclusive)*innerLength - startInnerInclusive; + return ((long) endOuterExclusive - startOuterInclusive) * innerLength - startInnerInclusive; + } + + @Override + public boolean tryAdvance(final IntConsumer action) { + if (startOuterInclusive >= endOuterExclusive) { + return false; + } + + final int value = array[startOuterInclusive][startInnerInclusive]; + startInnerInclusive += 1; + if (startInnerInclusive == endInnerExclusive) { + startOuterInclusive++; + startInnerInclusive = 0; + } + action.accept(value); + return true; } @Override - public boolean tryAdvance(IntConsumer action) { - // TODO - throw new UnsupportedOperationException(); + public void forEachRemaining(final Consumer action) { + for (int i = startOuterInclusive; i < endOuterExclusive; i++) { + for (int j = startInnerInclusive; j < endInnerExclusive; j++) { + action.accept(array[i][j]); + } + } } } diff --git a/src/test/java/spliterators/part1/exercise/RectangleSpliteratorTest.java b/src/test/java/spliterators/part1/exercise/RectangleSpliteratorTest.java new file mode 100644 index 0000000..e29f7c0 --- /dev/null +++ b/src/test/java/spliterators/part1/exercise/RectangleSpliteratorTest.java @@ -0,0 +1,58 @@ +package spliterators.part1.exercise; + +import org.junit.Before; +import org.junit.Test; + +import java.util.Arrays; +import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.StreamSupport; + +import static org.junit.Assert.assertEquals; + +public class RectangleSpliteratorTest { + + private int[][] array; + + @Before + public void setup() { + final int outerLength = 100; + array = new int[outerLength][]; + + for (int i = 0; i < array.length; i++) { + final int innerLength = 100; + final int[] inner = new int[innerLength]; + array[i] = inner; + for (int j = 0; j < inner.length; j++) { + inner[j] = ThreadLocalRandom.current().nextInt();; + } + } + } + + @Test + public void test_seq() { + final long expected = Arrays.stream(array) + .sequential() + .flatMapToInt(Arrays::stream) + .asLongStream() + .sum(); + final long res = StreamSupport.intStream(new RectangleSpliterator(array), false) + .asLongStream() + .sum(); + + assertEquals(expected, res); + } + + @Test + public void test_par() { + final long expected = Arrays.stream(array) + .parallel() + .flatMapToInt(Arrays::stream) + .asLongStream() + .sum(); + final long res = StreamSupport.intStream(new RectangleSpliterator(array), true) + .asLongStream() + .sum(); + + assertEquals(expected, res); + } +} \ No newline at end of file