diff --git a/src/main/java/spliterators/part1/exercise/RectangleSpliterator.java b/src/main/java/spliterators/part1/exercise/RectangleSpliterator.java index 678f4f5..0634692 100755 --- a/src/main/java/spliterators/part1/exercise/RectangleSpliterator.java +++ b/src/main/java/spliterators/part1/exercise/RectangleSpliterator.java @@ -5,42 +5,106 @@ import java.util.Spliterators; import java.util.function.IntConsumer; +import static java.lang.Math.abs; + 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) { - super(Long.MAX_VALUE, Spliterator.IMMUTABLE | Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.NONNULL); + private RectangleSpliterator(int[][] array, int startOuterInclusive, int endOuterExclusive, int startInnerInclusive, 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.array = array; this.startOuterInclusive = startOuterInclusive; this.endOuterExclusive = endOuterExclusive; this.startInnerInclusive = startInnerInclusive; + this.endInnerExclusive = endInnerExclusive; } + @Override public OfInt trySplit() { - // TODO - throw new UnsupportedOperationException(); + int elements = abs((int) estimateSize()); + if (elements < 2) { + return null; + } + + int half = elements / 2; + int midPoint = (startInnerInclusive + half) % innerLength; + int newRows = (startInnerInclusive + half) / innerLength; + int newOuterStart = startOuterInclusive + newRows; + + RectangleSpliterator res = + new RectangleSpliterator(array, newOuterStart, endOuterExclusive, midPoint, endInnerExclusive); + + endInnerExclusive = midPoint; + endOuterExclusive = midPoint == 0 ? newOuterStart : newOuterStart + 1; + + return res; + } + + @Override + public void forEachRemaining(IntConsumer action) { + for (int i = startOuterInclusive; i < endOuterExclusive; i++) { + if (i == startOuterInclusive && i == endOuterExclusive - 1) { + for (int j = startInnerInclusive; j < (endInnerExclusive == 0 ? innerLength : endInnerExclusive); j++) { + action.accept(array[i][j]); + } + } else if (i == endOuterExclusive - 1) { + for (int j = 0; j < endInnerExclusive; j++) { + action.accept(array[i][j]); + } + } else if (i == startOuterInclusive) { + for (int j = startInnerInclusive; j < innerLength; j++) { + action.accept(array[i][j]); + } + } else { + for (int j = 0; j < innerLength; j++) { + action.accept(array[i][j]); + } + } + } } @Override public long estimateSize() { - return ((long) endOuterExclusive - startOuterInclusive)*innerLength - startInnerInclusive; + return ((long) endOuterExclusive - startOuterInclusive) * innerLength + - startInnerInclusive - (innerLength - endInnerExclusive); } @Override public boolean tryAdvance(IntConsumer action) { - // TODO - throw new UnsupportedOperationException(); + if (startOuterInclusive >= endOuterExclusive) { + return false; + } + + final int value = array[startOuterInclusive][startInnerInclusive]; + action.accept(value); + startInnerInclusive += 1; + + if (((endOuterExclusive - startOuterInclusive) > 1 && startInnerInclusive >= innerLength) || + ((endOuterExclusive - startOuterInclusive) == 1 && startInnerInclusive >= (endInnerExclusive == 0 ? innerLength : endInnerExclusive)) + ) { + startOuterInclusive += 1; + startInnerInclusive = 0; + } + + return true; } + } diff --git a/src/main/java/spliterators/part1/exercise/RectangleSpliteratorExercise.java b/src/main/java/spliterators/part1/exercise/RectangleSpliteratorExercise.java index 1316732..0671f28 100755 --- a/src/main/java/spliterators/part1/exercise/RectangleSpliteratorExercise.java +++ b/src/main/java/spliterators/part1/exercise/RectangleSpliteratorExercise.java @@ -15,10 +15,10 @@ @State(Scope.Thread) public class RectangleSpliteratorExercise { - @Param({"100"}) + @Param({"13000"}) public int outerLength; - @Param({"100"}) + @Param({"13000"}) public int innerLength; public int[][] array; diff --git a/src/main/java/spliterators/part1/exercise/benchmark_results.txt b/src/main/java/spliterators/part1/exercise/benchmark_results.txt new file mode 100644 index 0000000..f77ce9e --- /dev/null +++ b/src/main/java/spliterators/part1/exercise/benchmark_results.txt @@ -0,0 +1,5 @@ +Benchmark (innerLength) (outerLength) Mode Cnt Score Error Units +RectangleSpliteratorExercise.baiseline_par 13000 13000 avgt 10 46.978 ± 2.854 ms/op +RectangleSpliteratorExercise.baiseline_seq 13000 13000 avgt 10 77.890 ± 2.696 ms/op +RectangleSpliteratorExercise.rectangle_par 13000 13000 avgt 10 48.243 ± 1.727 ms/op +RectangleSpliteratorExercise.rectangle_seq 13000 13000 avgt 10 80.318 ± 3.265 ms/op 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..1ccbf95 --- /dev/null +++ b/src/test/java/spliterators/part1/exercise/RectangleSpliteratorTest.java @@ -0,0 +1,101 @@ +package spliterators.part1.exercise; + +import org.junit.Test; + +import java.util.Spliterator; +import java.util.function.IntConsumer; + +import static org.junit.Assert.*; + + +public class RectangleSpliteratorTest { + @Test + public void trySplit() throws Exception { + + final int[][] arr = { + {1, 2, 3, 4}, + {5, 6, 7, 8}, + {9, 10, 11, 12}, + {13, 14, 15, 16}, + }; + + RectangleSpliterator sp = new RectangleSpliterator(arr); + + Spliterator.OfInt ofInt1 = sp.trySplit(); + Spliterator.OfInt ofInt2 = ofInt1.trySplit(); + Spliterator.OfInt ofInt3 = ofInt2.trySplit(); + + boolean b1 = ofInt3.tryAdvance((IntConsumer) value -> assertEquals(15, value)); + boolean b2 = ofInt3.tryAdvance((IntConsumer) value -> assertEquals(16, value)); + boolean b3 = ofInt3.tryAdvance((IntConsumer) value -> System.out.println("This message you'll never see!")); + assertTrue(b1); + assertTrue(b2); + assertFalse(b3); + + boolean b4 = ofInt2.tryAdvance((IntConsumer) value -> assertEquals(13, value)); + boolean b5 = ofInt2.tryAdvance((IntConsumer) value -> assertEquals(14, value)); + boolean b6 = ofInt2.tryAdvance((IntConsumer) value -> System.out.println("This message you'll never see!")); + assertTrue(b4); + assertTrue(b5); + assertFalse(b6); + } + + + @Test + public void trySplit2() throws Exception { + final int[][] arr = { + {1, 2, 3, 4}, + {5, 6, 7, 8}, + {9, 10, 11, 12}, + {13, 14, 15, 16}, + {17, 18, 19, 20} + }; + + RectangleSpliterator sp = new RectangleSpliterator(arr); + + Spliterator.OfInt ofInt1 = sp.trySplit(); + Spliterator.OfInt ofInt2 = ofInt1.trySplit(); + Spliterator.OfInt ofInt3 = ofInt1.trySplit(); + + boolean b1 = ofInt1.tryAdvance((IntConsumer) value -> assertEquals(11, value)); + boolean b2 = ofInt1.tryAdvance((IntConsumer) value -> assertEquals(12, value)); + boolean b3 = ofInt1.tryAdvance((IntConsumer) value -> System.out.println("This message you'll never see!")); + assertTrue(b1); + assertTrue(b2); + assertFalse(b3); + + boolean b4 = ofInt3.tryAdvance((IntConsumer) value -> assertEquals(13, value)); + boolean b5 = ofInt3.tryAdvance((IntConsumer) value -> assertEquals(14, value)); + boolean b6 = ofInt3.tryAdvance((IntConsumer) value -> assertEquals(15, value)); + boolean b7 = ofInt3.tryAdvance((IntConsumer) value -> System.out.println("This message you'll never see!")); + assertTrue(b4); + assertTrue(b5); + assertTrue(b6); + assertFalse(b7); + } + + @Test + public void forEachRemaining() { + final int[][] arr = { + {1, 2, 3, 4}, + {5, 6, 7, 8}, + {9, 10, 11, 12}, + {13, 14, 15, 16}, + {17, 18, 19, 20} + }; + + RectangleSpliterator sp = new RectangleSpliterator(arr); + + Spliterator.OfInt ofInt1 = sp.trySplit(); + Spliterator.OfInt ofInt2 = ofInt1.trySplit(); + Spliterator.OfInt ofInt3 = ofInt1.trySplit(); + + System.out.println("ofInt1"); + ofInt1.forEachRemaining((IntConsumer) System.out::println); + System.out.println("ofInt2"); + ofInt2.forEachRemaining((IntConsumer) System.out::println); + System.out.println("ofInt3"); + ofInt3.forEachRemaining((IntConsumer) System.out::println); + } + +} \ No newline at end of file