diff --git a/src/main/java/spliterators/part3/exercise/ZipWithArraySpliterator.java b/src/main/java/spliterators/part3/exercise/ZipWithArraySpliterator.java index 292137e..e3062ed 100755 --- a/src/main/java/spliterators/part3/exercise/ZipWithArraySpliterator.java +++ b/src/main/java/spliterators/part3/exercise/ZipWithArraySpliterator.java @@ -2,47 +2,79 @@ import java.util.Spliterator; import java.util.Spliterators; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; import java.util.function.Consumer; public class ZipWithArraySpliterator extends Spliterators.AbstractSpliterator> { - private final Spliterator inner; private final B[] array; + private final AtomicLong startInclusive; + private final long endExclusive; public ZipWithArraySpliterator(Spliterator inner, B[] array) { - super(Long.MAX_VALUE, 0); // FIXME: + super(array.length, inner.characteristics()); // TODO - throw new UnsupportedOperationException(); + this.inner = inner; + this.array = array; + this.endExclusive = array.length; + startInclusive = new AtomicLong(); + } + + private ZipWithArraySpliterator(Spliterator inner, B[] array, long startInclusive, long endExclusive) { + super(array.length, inner.characteristics()); + // TODO + this.inner = inner; + this.array = array; + this.startInclusive = new AtomicLong(startInclusive); + this.endExclusive = endExclusive; } @Override public int characteristics() { // TODO - throw new UnsupportedOperationException(); + int characteristics = inner.characteristics(); + if (!inner.hasCharacteristics(SUBSIZED)) + throw new IllegalStateException(); + characteristics &= ~SORTED; + return characteristics; } @Override public boolean tryAdvance(Consumer> action) { // TODO - throw new UnsupportedOperationException(); + if (startInclusive.get() >= endExclusive) return false; + + inner.tryAdvance(v -> action.accept( + new Pair<>(v, array[(int) startInclusive.get()])) + ); + startInclusive.incrementAndGet(); + return true; } @Override public void forEachRemaining(Consumer> action) { // TODO - throw new UnsupportedOperationException(); + inner.forEachRemaining(v -> { + if (startInclusive.get() < array.length) + action.accept(new Pair<>(v, array[(int) startInclusive.getAndIncrement()])); + }); } @Override public Spliterator> trySplit() { // TODO - throw new UnsupportedOperationException(); + final Spliterator part = inner.trySplit(); + if (part != null) { + final long prevStartInclusive = startInclusive.getAndAdd(part.estimateSize()); + return new ZipWithArraySpliterator<>(part, array, prevStartInclusive, startInclusive.get()); + } else return null; } @Override public long estimateSize() { // TODO - throw new UnsupportedOperationException(); + return endExclusive - startInclusive.get(); } } diff --git a/src/test/java/spliterators/part2/example/ZipWithArraySpliteratorTest.java b/src/test/java/spliterators/part2/example/ZipWithArraySpliteratorTest.java new file mode 100644 index 0000000..a6d8f2f --- /dev/null +++ b/src/test/java/spliterators/part2/example/ZipWithArraySpliteratorTest.java @@ -0,0 +1,87 @@ +package spliterators.part2.example; + +import org.junit.Test; +import spliterators.part1.example.ArrayExample; +import spliterators.part3.exercise.Pair; +import spliterators.part3.exercise.ZipWithArraySpliterator; + +import java.util.*; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.*; + +public class ZipWithArraySpliteratorTest { + + private Integer[] getRandomArray(int length) { + final Integer[] result = new Integer[length]; + + for (int i = 0; i < length; i++) + result[i] = ThreadLocalRandom.current().nextInt(); + + return result; + } + + @Test + public void innerIsOfGreaterLengthSuccess() { + final Integer[] innerArray = getRandomArray(30); + final Integer[] array = getRandomArray(10); + + final ZipWithArraySpliterator spliterator = new ZipWithArraySpliterator<>( + Spliterators.spliterator(innerArray, 0), array); + + final List actual = StreamSupport.stream(spliterator, false) + .map(p -> new Pair<>(p.getA().hashCode() + 1, p.getB() + 1)) + .map(Pair::toString) + .collect(Collectors.toList()); + assertThat(actual.size(), is(10)); + } + + @Test + public void ArrayIsOfGreaterLengthSuccess() { + final Integer[] innerArray = getRandomArray(10); + final Integer[] array = getRandomArray(30); + + final ZipWithArraySpliterator spliterator = new ZipWithArraySpliterator<>( + Spliterators.spliterator(innerArray, 0), array); + + final List actual = StreamSupport.stream(spliterator, false) + .map(p -> new Pair<>(p.getA().hashCode() + 1, p.getB() + 1)) + .map(Pair::toString) + .collect(Collectors.toList()); + assertThat(actual.size(), is(10)); + } + + @Test + public void nonzeroLengthSuccess() { + final Integer[] innerArray = getRandomArray(10); + final Integer[] array = getRandomArray(10); + + final ZipWithArraySpliterator spliterator = new ZipWithArraySpliterator<>( + Spliterators.spliterator(innerArray, 0), array); + + final List actual = StreamSupport.stream(spliterator, false) + .map(p -> new Pair<>(p.getA().hashCode() + 1, p.getB() + 1)) + .map(Pair::toString) + .collect(Collectors.toList()); + assertThat(actual.size(), is(10)); + } + + @Test + public void zeroLengthSuccess() { + final Integer[] innerArray = getRandomArray(0); + final Integer[] array = getRandomArray(0); + + final ZipWithArraySpliterator spliterator = new ZipWithArraySpliterator<>( + Spliterators.spliterator(innerArray, 0), array); + + final List actual = StreamSupport.stream(spliterator, false) + .map(p -> new Pair<>(p.getA().hashCode() + 1, p.getB() + 1)) + .map(Pair::toString) + .collect(Collectors.toList()); + assertThat(actual.size(), is(0)); + } +}