diff --git a/src/main/java/spliterators/part1/exercise/RectangleSpliterator.java b/src/main/java/spliterators/part1/exercise/RectangleSpliterator.java index 678f4f5..9491eff 100755 --- a/src/main/java/spliterators/part1/exercise/RectangleSpliterator.java +++ b/src/main/java/spliterators/part1/exercise/RectangleSpliterator.java @@ -7,40 +7,112 @@ 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[][] array; + private int startOuterIncl; + private int endOuterExcl; + + private int innerLength; + + private int startInnerIncl; + private int endInnerExcl; public RectangleSpliterator(int[][] array) { - this(array, 0, array.length, 0); + this(array, 0, array.length, + 0, 0); + this.endInnerExcl = innerLength; } - private RectangleSpliterator(int[][] array, int startOuterInclusive, int endOuterExclusive, int startInnerInclusive) { - super(Long.MAX_VALUE, Spliterator.IMMUTABLE | Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.NONNULL); - - innerLength = array.length == 0 ? 0 : array[0].length; + private RectangleSpliterator(int[][] array, int startOuterIncl, int endOuterExcl, + int startInnerIncl, int endInnerExcl) { + super(Long.MAX_VALUE, + Spliterator.IMMUTABLE | + Spliterator.ORDERED | + Spliterator.SIZED | + Spliterator.SUBSIZED | + Spliterator.NONNULL); + this.innerLength = array.length == 0 ? 0 : array[0].length; this.array = array; - this.startOuterInclusive = startOuterInclusive; - this.endOuterExclusive = endOuterExclusive; - this.startInnerInclusive = startInnerInclusive; + this.startOuterIncl = startOuterIncl; + this.endOuterExcl = endOuterExcl; + + this.startInnerIncl = startInnerIncl; + this.endInnerExcl = endInnerExcl; } @Override public OfInt trySplit() { - // TODO - throw new UnsupportedOperationException(); + int rowNumber = endOuterExcl - startOuterIncl; + int estimatedSize = (int) estimateSize(); + + if (rowNumber < 2 && estimatedSize < 2) { + return null; + } + + int halfEstimatedSize = estimatedSize / 2; + int halfSizeWithoutStartLine = halfEstimatedSize - (innerLength - startInnerIncl); + + int midOuterIncl = startOuterIncl; + int midInnerIncl = startInnerIncl; + if (halfSizeWithoutStartLine > 0) { + int amountFullRows = halfSizeWithoutStartLine / innerLength; + if (halfSizeWithoutStartLine % innerLength > 0) { + midOuterIncl = midOuterIncl + amountFullRows + 1; + midInnerIncl = halfSizeWithoutStartLine - amountFullRows*innerLength; + } else { + midOuterIncl += amountFullRows; + midInnerIncl = innerLength; + } + } else { + midInnerIncl += halfEstimatedSize; + } + + final RectangleSpliterator rs = new RectangleSpliterator(array, startOuterIncl, midOuterIncl + 1, + startInnerIncl, midInnerIncl); + startOuterIncl = midInnerIncl == innerLength ? midOuterIncl + 1 : midOuterIncl; + startInnerIncl = midInnerIncl == innerLength ? 0 : midInnerIncl; + return rs; } @Override public long estimateSize() { - return ((long) endOuterExclusive - startOuterInclusive)*innerLength - startInnerInclusive; + int rowNumber = endOuterExcl - startOuterIncl; + if (rowNumber > 2) { + return innerLength - startInnerIncl + endInnerExcl + (rowNumber - 2) * innerLength; + } else if (rowNumber == 2) { + return innerLength - startInnerIncl + endInnerExcl; + } else { + return endInnerExcl - startInnerIncl; + } } @Override public boolean tryAdvance(IntConsumer action) { - // TODO - throw new UnsupportedOperationException(); + if (startOuterIncl == endOuterExcl - 1 && startInnerIncl >= endInnerExcl || startOuterIncl >= endOuterExcl) { + return false; + } + + int value = array[startOuterIncl][startInnerIncl]; + action.accept(value); + + startInnerIncl++; + if (startInnerIncl == innerLength) { + startInnerIncl = 0; + startOuterIncl++; + } + + return true; + } + + @Override + public void forEachRemaining(IntConsumer action) { + for (int out = startOuterIncl; out < endOuterExcl; out++) { + int endInnerLocalExcl = out == (endOuterExcl - 1) ? endInnerExcl : innerLength; + for (int in = startInnerIncl; in < endInnerLocalExcl; in++) { + action.accept(array[out][in]); + } + startInnerIncl = 0; + } + startOuterIncl = endOuterExcl; + startInnerIncl = endInnerExcl; } } diff --git a/src/main/resources/benchmark.txt b/src/main/resources/benchmark.txt new file mode 100644 index 0000000..f80f734 --- /dev/null +++ b/src/main/resources/benchmark.txt @@ -0,0 +1,5 @@ +Benchmark (consume) (count) (innerLength) (length) (outerLength) Mode Cnt Score Error Units +s.part1.exercise.RectangleSpliteratorExercise.baiseline_par N/A N/A 100 N/A 100 avgt 10 0.044 ± 0.001 ms/op +s.part1.exercise.RectangleSpliteratorExercise.baiseline_seq N/A N/A 100 N/A 100 avgt 10 0.016 ± 0.001 ms/op +s.part1.exercise.RectangleSpliteratorExercise.rectangle_par N/A N/A 100 N/A 100 avgt 10 0.040 ± 0.002 ms/op +s.part1.exercise.RectangleSpliteratorExercise.rectangle_seq N/A N/A 100 N/A 100 avgt 10 0.011 ± 0.001 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..5abd178 --- /dev/null +++ b/src/test/java/spliterators/part1/exercise/RectangleSpliteratorTest.java @@ -0,0 +1,172 @@ +package spliterators.part1.exercise; + +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Spliterator; +import java.util.function.Consumer; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +public class RectangleSpliteratorTest { + + private static RectangleSpliterator testedMain; + private int[][] testedArr = new int[][]{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; + + private List expectedFirstListOfSpl = Arrays.asList(1, 2, 3, 4); + private List expectedSecondListOfSpl = Arrays.asList(5, 6, 7, 8, 9); + + private List expectedFirstListOfSpliterator = Arrays.asList(1, 2); + private List expectedSecondListOfSpliterator = Arrays.asList(3, 4); + + private List expectedThirdListOfSpliterator = Arrays.asList(5, 6); + private List expectedFourthListOfSpliterator = Arrays.asList(7, 8, 9); + + @Before + public void initSpliterator() { + testedMain = new RectangleSpliterator(testedArr); + } + + @Test + public void testEstimatingSizeForFirstCreating() { + int expected = 9; + int actual = (int) testedMain.estimateSize(); + assertThat(actual, is(expected)); + } + + @Test + public void testFirstlySplittingOfEvenArrayRowsNumber() { + int[][] testedArr = new int[][]{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}}; + testedMain = new RectangleSpliterator(testedArr); + + Spliterator.OfInt firstSpl = testedMain.trySplit(); + Spliterator.OfInt secondSpl = testedMain; + + assertThat((int) firstSpl.estimateSize(), is(6)); + assertThat((int) secondSpl.estimateSize(), is(6)); + + List expectedFirstListOfSpl = Arrays.asList(1, 2, 3, 4, 5, 6); + List actualFirstListOfSpl = new ArrayList<>(); + while (firstSpl.tryAdvance((Consumer) actualFirstListOfSpl::add)) ; + assertEquals(expectedFirstListOfSpl, actualFirstListOfSpl); + + List expectedSecondListOfSpl = Arrays.asList(7, 8, 9, 10, 11, 12); + List actualSecondListOfSpl = new ArrayList<>(); + while (secondSpl.tryAdvance((Consumer) actualSecondListOfSpl::add)) ; + assertEquals(expectedSecondListOfSpl, actualSecondListOfSpl); + } + + + @Test + public void testFirstlySplittingAndForEachRemaining() { + Spliterator.OfInt firstSpl = testedMain.trySplit(); + Spliterator.OfInt secondSpl = testedMain; + + assertThat((int) secondSpl.estimateSize(), is(5)); + assertThat((int) firstSpl.estimateSize(), is(4)); + + List actualFirstListOfSpl = new ArrayList<>(); + firstSpl.forEachRemaining((Consumer) actualFirstListOfSpl::add); + assertEquals(expectedFirstListOfSpl, actualFirstListOfSpl); + + List actualSecondListOfSpl = new ArrayList<>(); + secondSpl.forEachRemaining((Consumer) actualSecondListOfSpl::add); + assertEquals(expectedSecondListOfSpl, actualSecondListOfSpl); + } + + @Test + public void testSecondlySplittingAndForEachRemaining() { + Spliterator.OfInt splitMain = testedMain.trySplit(); + + Spliterator.OfInt firstSpl = splitMain.trySplit(); + Spliterator.OfInt secondSpl = splitMain; + Spliterator.OfInt thirdSpl = testedMain.trySplit(); + Spliterator.OfInt fourthSpl = testedMain; + + assertThat((int) firstSpl.estimateSize(), is(2)); + assertThat((int) secondSpl.estimateSize(), is(2)); + assertThat((int) thirdSpl.estimateSize(), is(2)); + assertThat((int) fourthSpl.estimateSize(), is(3)); + + List actualFirstListOfSpl = new ArrayList<>(); + firstSpl.forEachRemaining((Consumer) actualFirstListOfSpl::add); + assertEquals(expectedFirstListOfSpliterator, actualFirstListOfSpl); + + List actualSecondListOfSpl = new ArrayList<>(); + secondSpl.forEachRemaining((Consumer) actualSecondListOfSpl::add); + assertEquals(expectedSecondListOfSpliterator, actualSecondListOfSpl); + + List actualThirdListOfSpl = new ArrayList<>(); + thirdSpl.forEachRemaining((Consumer) actualThirdListOfSpl::add); + assertEquals(expectedThirdListOfSpliterator, actualThirdListOfSpl); + + List actualFourthListOfSpl = new ArrayList<>(); + fourthSpl.forEachRemaining((Consumer) actualFourthListOfSpl::add); + assertEquals(expectedFourthListOfSpliterator, actualFourthListOfSpl); + } + + @Test + public void testThirdlySplitting() { + Spliterator.OfInt splitMain = testedMain.trySplit(); + + Spliterator.OfInt firstSpliteratorOfSeconlySplitting = splitMain.trySplit(); + Spliterator.OfInt secondSpliteratorOfSeconlySplitting = splitMain; + Spliterator.OfInt thirdSpliteratorOfSeconlySplitting = testedMain.trySplit(); + Spliterator.OfInt fourthSpliteratorOfSeconlySplitting = testedMain; + + Spliterator.OfInt firstSpliteratorOfThirdlySplitting = firstSpliteratorOfSeconlySplitting.trySplit(); + Spliterator.OfInt secondSpliteratorOfThirdlySplitting = firstSpliteratorOfSeconlySplitting; + Spliterator.OfInt thirdSpliteratorOfThirdlySplitting = secondSpliteratorOfSeconlySplitting.trySplit(); + Spliterator.OfInt fourthSpliteratorOfThirdlySplitting = secondSpliteratorOfSeconlySplitting; + Spliterator.OfInt fifthSpliteratorOfThirdlySplitting = thirdSpliteratorOfSeconlySplitting.trySplit(); + Spliterator.OfInt sixthSpliteratorOfThirdlySplitting = thirdSpliteratorOfSeconlySplitting; + Spliterator.OfInt seventhSpliteratorOfThirdlySplitting = fourthSpliteratorOfSeconlySplitting.trySplit(); + Spliterator.OfInt eighthSpliteratorOfThirdlySplitting = fourthSpliteratorOfSeconlySplitting; + + assertThat((int) firstSpliteratorOfThirdlySplitting.estimateSize(), is(1)); + assertThat((int) secondSpliteratorOfThirdlySplitting.estimateSize(), is(1)); + assertThat((int) thirdSpliteratorOfThirdlySplitting.estimateSize(), is(1)); + assertThat((int) fourthSpliteratorOfThirdlySplitting.estimateSize(), is(1)); + assertThat((int) fifthSpliteratorOfThirdlySplitting.estimateSize(), is(1)); + assertThat((int) sixthSpliteratorOfThirdlySplitting.estimateSize(), is(1)); + assertThat((int) seventhSpliteratorOfThirdlySplitting.estimateSize(), is(1)); + assertThat((int) eighthSpliteratorOfThirdlySplitting.estimateSize(), is(2)); + + } + + @Test + public void testFourthlySplitting() { + Spliterator.OfInt splitMain = testedMain.trySplit(); + Spliterator.OfInt firstSpliteratorOfSeconlySplitting = splitMain.trySplit(); + Spliterator.OfInt firstSpliteratorOfThirdlySplitting = firstSpliteratorOfSeconlySplitting.trySplit(); + + assertThat((int) firstSpliteratorOfThirdlySplitting.estimateSize(), is(1)); + + Spliterator.OfInt firstSpliteratorOfFourthlySplitting = firstSpliteratorOfThirdlySplitting.trySplit(); + + assertNull(firstSpliteratorOfFourthlySplitting); + } + + @Test + public void testTryAdvanceAfterFirstSplitting() { + Spliterator.OfInt firstSpl = testedMain.trySplit(); + Spliterator.OfInt secondSpl = testedMain; + + assertThat((int) secondSpl.estimateSize(), is(5)); + assertThat((int) firstSpl.estimateSize(), is(4)); + + List actualFirstListOfSpl = new ArrayList<>(); + while (firstSpl.tryAdvance((Consumer) actualFirstListOfSpl::add)) ; + assertEquals(expectedFirstListOfSpl, actualFirstListOfSpl); + + List actualSecondListOfSpl = new ArrayList<>(); + while (secondSpl.tryAdvance((Consumer) actualSecondListOfSpl::add)) ; + assertEquals(expectedSecondListOfSpl, actualSecondListOfSpl); + } +} \ No newline at end of file