From 2c9f6c0d96ad86b59da812a30da78ee26c29c237 Mon Sep 17 00:00:00 2001 From: Ruslan Sennov Date: Wed, 2 Sep 2015 22:23:42 +0300 Subject: [PATCH 1/2] some TODOs in Iterator fixed #487 --- .../java/javaslang/collection/HashSet.java | 18 +- .../java/javaslang/collection/Iterator.java | 159 +++++++++++++++++- src/main/java/javaslang/collection/Seq.java | 3 +- .../java/javaslang/collection/Stream.java | 10 +- .../javaslang/collection/HashSetTest.java | 25 --- .../javaslang/collection/IteratorTest.java | 41 +++++ 6 files changed, 204 insertions(+), 52 deletions(-) diff --git a/src/main/java/javaslang/collection/HashSet.java b/src/main/java/javaslang/collection/HashSet.java index 321eef71cb..90df339aba 100644 --- a/src/main/java/javaslang/collection/HashSet.java +++ b/src/main/java/javaslang/collection/HashSet.java @@ -186,7 +186,7 @@ public HashSet filter(Predicate predicate) { @Override public Option findLast(Predicate predicate) { - throw new UnsupportedOperationException("TODO"); + return findFirst(predicate); } @Override @@ -212,7 +212,7 @@ public HashSet flatten() { @Override public U foldRight(U zero, BiFunction f) { - throw new UnsupportedOperationException("TODO"); + return foldLeft(zero, (u, t) -> f.apply(t, u)); } @Override @@ -292,16 +292,8 @@ public String mkString(CharSequence delimiter, @Override public Tuple2, HashSet> partition(Predicate predicate) { Objects.requireNonNull(predicate, "predicate is null"); - HashSet first = HashSet.empty(); - HashSet second = HashSet.empty(); - for (T t : this) { - if (predicate.test(t)) { - first = first.add(t); - } else { - second = second.add(t); - } - } - return Tuple.of(first, second); + final Tuple2, Iterator> p = iterator().partition(predicate); + return Tuple.of(HashSet.ofAll(p._1), HashSet.ofAll(p._2)); } @Override @@ -315,7 +307,7 @@ public HashSet peek(Consumer action) { @Override public T reduceRight(BiFunction op) { - throw new UnsupportedOperationException("TODO"); + return reduceLeft(op); } @Override diff --git a/src/main/java/javaslang/collection/Iterator.java b/src/main/java/javaslang/collection/Iterator.java index 4b8bcb13aa..fcf5808b06 100644 --- a/src/main/java/javaslang/collection/Iterator.java +++ b/src/main/java/javaslang/collection/Iterator.java @@ -715,7 +715,104 @@ public Long next() { } } - // TODO: add static factory methods similar to Stream.from, Stream.gen, ... + /** + * Returns an infinitely iterator of int values starting from {@code from}. + *

+ * The {@code Iterator} extends to {@code Integer.MIN_VALUE} when passing {@code Integer.MAX_VALUE}. + * + * @param value a start int value + * @return a new {@code Iterator} of int values starting from {@code from} + */ + static Iterator from(int value) { + return new AbstractIterator() { + private int next = value; + + @Override + public boolean hasNext() { + return true; + } + + @Override + public Integer next() { + return next++; + } + }; + } + + /** + * Returns an infinitely iterator of long values starting from {@code from}. + *

+ * The {@code Iterator} extends to {@code Long.MIN_VALUE} when passing {@code Long.MAX_VALUE}. + * + * @param value a start long value + * @return a new {@code Iterator} of long values starting from {@code from} + */ + static Iterator from(long value) { + return new AbstractIterator() { + private long next = value; + + @Override + public boolean hasNext() { + return true; + } + + @Override + public Long next() { + return next++; + } + }; + } + + /** + * Generates an infinitely iterator using a value Supplier. + * + * @param supplier A Supplier of iterator values + * @param value type + * @return A new {@code Iterator} + */ + @SuppressWarnings("unchecked") + static Iterator gen(Supplier supplier) { + Objects.requireNonNull(supplier, "supplier is null"); + return new AbstractIterator() { + @Override + public boolean hasNext() { + return true; + } + + @Override + public T next() { + return supplier.get(); + } + }; + } + + /** + * Generates an infinitely iterator using a function to calculate the next value + * based on the previous. + * + * @param seed The first value in the iterator + * @param f A function to calculate the next value based on the previous + * @param value type + * @return A new {@code Iterator} + */ + static Iterator gen(T seed, Function f) { + Objects.requireNonNull(f, "f is null"); + return new AbstractIterator() { + T next = seed; + + @Override + public boolean hasNext() { + return true; + } + + @Override + public T next() { + T result = next; + next = f.apply(next); + return result; + } + }; + } @Override default Iterator clear() { @@ -1095,8 +1192,14 @@ public U next() { @Override default Tuple2, Iterator> partition(Predicate predicate) { Objects.requireNonNull(predicate, "predicate is null"); - // TODO - throw new UnsupportedOperationException("TODO"); + if (!hasNext()) { + return Tuple.of(empty(), empty()); + } else { + final Stream that = Stream.ofAll(this); + final Iterator first = that.iterator().filter(predicate); + final Iterator second = that.iterator().filter(predicate.negate()); + return Tuple.of(first, second); + } } @Override @@ -1125,11 +1228,26 @@ public T next() { } } + @Override + default T reduceLeft(BiFunction op) { + Objects.requireNonNull(op, "op is null"); + if (isEmpty()) { + throw new NoSuchElementException("reduceLeft on Nil"); + } else { + Stream stream = Stream.ofAll(this); + return stream.tail().foldLeft(stream.head(), op::apply); + } + } + @Override default T reduceRight(BiFunction op) { Objects.requireNonNull(op, "op is null"); - // TODO - throw new UnsupportedOperationException("TODO"); + if (isEmpty()) { + throw new NoSuchElementException("reduceLeft on Nil"); + } else { + Stream reversed = Stream.ofAll(this).reverse(); + return reversed.tail().foldLeft(reversed.head(), (xs, x) -> op.apply(x, xs)); + } } @Override @@ -1334,8 +1452,35 @@ public T next() { @Override default Iterator takeRight(int n) { - // TODO - throw new UnsupportedOperationException("TODO"); + if (n <= 0) { + return empty(); + } else { + final Iterator that = this; + return new Iterator() { + private Queue queue = Queue.empty(); + + @Override + public boolean hasNext() { + while (that.hasNext()) { + queue = queue.append(that.next()); + if(queue.length() > n) { + queue = queue.dequeue()._2; + } + } + return queue.length() > 0; + } + + @Override + public T next() { + if (!hasNext()) { + EMPTY.next(); + } + final Tuple2> t = queue.dequeue(); + queue = t._2; + return t._1; + } + }; + } } @Override diff --git a/src/main/java/javaslang/collection/Seq.java b/src/main/java/javaslang/collection/Seq.java index 6cba1ce981..ccf21daf1d 100644 --- a/src/main/java/javaslang/collection/Seq.java +++ b/src/main/java/javaslang/collection/Seq.java @@ -726,8 +726,7 @@ default T reduceRight(BiFunction op) { if (isEmpty()) { throw new NoSuchElementException("reduceRight on Nil"); } else { - final Seq reversed = reverse(); - return reversed.tail().foldLeft(reversed.head(), (xs, x) -> op.apply(x, xs)); + return iterator().reduceRight(op); } } diff --git a/src/main/java/javaslang/collection/Stream.java b/src/main/java/javaslang/collection/Stream.java index 6841e2bcf3..780cbaeaab 100644 --- a/src/main/java/javaslang/collection/Stream.java +++ b/src/main/java/javaslang/collection/Stream.java @@ -123,7 +123,7 @@ static Collector, Stream> collector() { * @return a new Stream of int values starting from {@code from} */ static Stream from(int value) { - return new Cons<>(() -> value, () -> from(value + 1)); + return Stream.ofAll(Iterator.from(value)); } /** @@ -135,7 +135,7 @@ static Stream from(int value) { * @return a new Stream of long values starting from {@code from} */ static Stream from(long value) { - return new Cons<>(() -> value, () -> from(value + 1)); + return Stream.ofAll(Iterator.from(value)); } /** @@ -148,7 +148,7 @@ static Stream from(long value) { @SuppressWarnings("unchecked") static Stream gen(Supplier supplier) { Objects.requireNonNull(supplier, "supplier is null"); - return new Cons<>((Supplier) supplier, () -> gen(supplier)); + return Stream.ofAll(Iterator.gen(supplier)); } /** @@ -162,7 +162,7 @@ static Stream gen(Supplier supplier) { */ static Stream gen(T seed, Function f) { Objects.requireNonNull(f, "f is null"); - return new Stream.Cons<>(() -> seed, () -> gen(f.apply(seed), f)); + return Stream.ofAll(Iterator.gen(seed, f)); } /** @@ -1150,7 +1150,7 @@ default Stream takeRight(int n) { } else if (length() <= n) { return this; } else { - return reverse().take(n).reverse(); + return Stream.ofAll(iterator().takeRight(n)); } } diff --git a/src/test/java/javaslang/collection/HashSetTest.java b/src/test/java/javaslang/collection/HashSetTest.java index 03f805faa7..824dc3f0fe 100644 --- a/src/test/java/javaslang/collection/HashSetTest.java +++ b/src/test/java/javaslang/collection/HashSetTest.java @@ -345,16 +345,6 @@ public void shouldFoldRightNil() { // TODO } - @Override - public void shouldThrowWhenReduceRightNullOperator() { - throw new NullPointerException(); // TODO - } - - @Override - public void shouldThrowWhenReduceRightNil() { - throw new NoSuchElementException(); // TODO - } - @Override public void shouldFindLastOfNil() { // TODO @@ -385,16 +375,6 @@ public void shouldSerializeDeserializeNonNil() { // TODO } - @Override - public void shouldPartitionIntsInOddAndEvenHavingOddAndEventNumbers() { - // TODO - } - - @Override - public void shouldPartitionIntsInOddAndEvenHavingOnlyEvenNumbers() { - // TODO - } - @Override public void shouldSpanNonNil() { // TODO @@ -410,11 +390,6 @@ public void shouldReturnSomeTailWhenCallingTailOptionOnNonNil() { // TODO } - @Override - public void shouldPartitionIntsInOddAndEvenHavingOnlyOddNumbers() { -// TODO - } - @Override public void shouldSlideNonNilBySize1() { // TODO diff --git a/src/test/java/javaslang/collection/IteratorTest.java b/src/test/java/javaslang/collection/IteratorTest.java index 10a6ec4bae..ecec9d6759 100644 --- a/src/test/java/javaslang/collection/IteratorTest.java +++ b/src/test/java/javaslang/collection/IteratorTest.java @@ -108,4 +108,45 @@ boolean isThisLazyJavaslangObject() { int getPeekNonNilPerformingAnAction() { return 3; } + + // -- static from(int) + + @Test + public void shouldGenerateIntStream() { + assertThat(Iterator.from(-1).take(3)).isEqualTo(Iterator.of(-1, 0, 1)); + } + + @Test + public void shouldGenerateTerminatingIntStream() { + //noinspection NumericOverflow + assertThat(Iterator.from(Integer.MAX_VALUE).take(2)).isEqualTo(Iterator.of(Integer.MAX_VALUE, Integer.MAX_VALUE + 1)); + } + + // -- static from(long) + + @Test + public void shouldGenerateLongStream() { + assertThat(Iterator.from(-1L).take(3)).isEqualTo(Iterator.of(-1L, 0L, 1L)); + } + + @Test + public void shouldGenerateTerminatingLongStream() { + //noinspection NumericOverflow + assertThat(Iterator.from(Long.MAX_VALUE).take(2)).isEqualTo(Iterator.of(Long.MAX_VALUE, Long.MAX_VALUE + 1)); + } + + // -- static gen(Supplier) + + @Test + public void shouldGenerateInfiniteStreamBasedOnSupplier() { + assertThat(Iterator.gen(() -> 1).take(13).reduce((i, j) -> i + j)).isEqualTo(13); + } + + // -- static gen(T, Function) + + @Test + public void shouldGenerateInfiniteStreamBasedOnSupplierWithAccessToPreviousValue() { + assertThat(Iterator.gen(2, (i) -> i + 2).take(3).reduce((i, j) -> i + j)).isEqualTo(12); + } + } From 956c6c80d2519ebcca75b4dbda6da6b413623426 Mon Sep 17 00:00:00 2001 From: Ruslan Sennov Date: Wed, 2 Sep 2015 23:43:04 +0300 Subject: [PATCH 2/2] ... --- src/main/java/javaslang/collection/Iterator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/javaslang/collection/Iterator.java b/src/main/java/javaslang/collection/Iterator.java index fcf5808b06..1b1dcfe4f2 100644 --- a/src/main/java/javaslang/collection/Iterator.java +++ b/src/main/java/javaslang/collection/Iterator.java @@ -1462,7 +1462,7 @@ default Iterator takeRight(int n) { @Override public boolean hasNext() { while (that.hasNext()) { - queue = queue.append(that.next()); + queue = queue.enqueue(that.next()); if(queue.length() > n) { queue = queue.dequeue()._2; }