Skip to content

Commit a09f8cc

Browse files
authored
more robust slideby classifier function handling (#2642)
When the classifier function is pure everything works fine, but with state, `slideBy` might end up in an infinite loop. The reason: `slideBy` calls the classifier two times on the same item. If the second call returns a different value, `slideBy` will not advance anymore and iterate indefinitely on the same item.
1 parent cc4b4b6 commit a09f8cc

File tree

2 files changed

+13
-0
lines changed

2 files changed

+13
-0
lines changed

src/main/java/io/vavr/collection/Iterator.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1909,6 +1909,7 @@ public boolean hasNext() {
19091909
if (next == null && source.hasNext()) {
19101910
final Object key = classifier.apply(source.touch());
19111911
final java.util.List<T> acc = new ArrayList<>();
1912+
acc.add(source.next());
19121913
while (source.hasNext() && key.equals(classifier.apply(source.touch()))) {
19131914
acc.add(source.next());
19141915
}

src/test/java/io/vavr/collection/AbstractTraversableTest.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import java.math.BigDecimal;
2727
import java.math.BigInteger;
2828
import java.util.*;
29+
import java.util.concurrent.atomic.AtomicInteger;
2930
import java.util.function.Function;
3031
import java.util.function.Supplier;
3132
import java.util.stream.Collector;
@@ -1919,6 +1920,17 @@ public void shouldSlideNilByClassifier() {
19191920
assertThat(empty().slideBy(Function.identity())).isEmpty();
19201921
}
19211922

1923+
@Test(timeout=1000)
1924+
public void shouldTerminateSlideByClassifier() {
1925+
AtomicInteger ai = new AtomicInteger(0);
1926+
List<List<String>> expected = List.of(List.of("a", "-"), List.of( "-"), List.of("d") );
1927+
List<List<String>> actual = List.of("a", "-", "-", "d")
1928+
.slideBy(x -> x.equals("-") ? ai.getAndIncrement() : ai.get())
1929+
.toList();
1930+
assertThat(actual).containsAll(expected);
1931+
assertThat(expected).containsAll(actual);
1932+
}
1933+
19221934
@Test
19231935
public void shouldSlideSingularByClassifier() {
19241936
final List<Traversable<Integer>> actual = of(1).slideBy(Function.identity()).toList().map(io.vavr.collection.Vector::ofAll);

0 commit comments

Comments
 (0)