Skip to content

Commit b29cfee

Browse files
committed
Deforested iterables execute in intended nesting order, where essential
1 parent 90d147d commit b29cfee

File tree

10 files changed

+82
-6
lines changed

10 files changed

+82
-6
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](http://keepachangelog.com/).
55

66
## [Unreleased]
7-
No unreleased changes
7+
### Fixed
8+
- Deforested iterables execute in intended nesting order, where essential
89

910
## [3.0.2] - 2018-05-21
1011
### Added

src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterable.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public FilteringIterable(Function<? super A, Boolean> predicate, Iterable<A> as)
1616
List<Function<? super A, Boolean>> predicates = new ArrayList<>(singletonList(predicate));
1717
while (as instanceof FilteringIterable) {
1818
FilteringIterable<A> nested = (FilteringIterable<A>) as;
19-
predicates.addAll(nested.predicates);
19+
predicates.addAll(0, nested.predicates);
2020
as = nested.as;
2121
}
2222
this.predicates = predicates;

src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterable.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public PredicatedDroppingIterable(Function<? super A, Boolean> predicate, Iterab
1818
while (as instanceof PredicatedDroppingIterable) {
1919
PredicatedDroppingIterable<A> nested = (PredicatedDroppingIterable<A>) as;
2020
as = nested.as;
21-
predicates.addAll(nested.predicates);
21+
predicates.addAll(0, nested.predicates);
2222
}
2323
this.predicates = predicates;
2424
this.as = as;

src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterable.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ public PredicatedTakingIterable(Function<? super A, Boolean> predicate, Iterable
1616
List<Function<? super A, Boolean>> predicates = new ArrayList<>(singletonList(predicate));
1717
while (as instanceof PredicatedTakingIterable) {
1818
PredicatedTakingIterable<A> nested = (PredicatedTakingIterable<A>) as;
19+
predicates.addAll(0, nested.predicates);
1920
as = nested.as;
20-
predicates.addAll(nested.predicates);
2121
}
2222
this.predicates = predicates;
2323
this.as = as;

src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/FlattenTest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import static java.util.Arrays.asList;
1919
import static java.util.Collections.emptyList;
2020
import static java.util.Collections.singleton;
21+
import static java.util.Collections.singletonList;
2122
import static org.junit.Assert.assertThat;
2223
import static testsupport.matchers.IterableMatcher.isEmpty;
2324
import static testsupport.matchers.IterableMatcher.iterates;
@@ -40,4 +41,10 @@ public void flattensSparseIterableOfPopulatedIterables() {
4041
assertThat(flatten(asList(emptyList(), asList(1, 2, 3), emptyList(), emptyList(), singleton(4), asList(5, 6), emptyList())),
4142
iterates(1, 2, 3, 4, 5, 6));
4243
}
44+
45+
@Test
46+
public void flattenMultipleLevelsOfNesting() {
47+
assertThat(flatten(asList(asList(asList(1, 2, 3), asList(4, 5)), singletonList(asList(6, 7)))),
48+
iterates(asList(1, 2, 3), asList(4, 5), asList(6, 7)));
49+
}
4350
}

src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/ReverseTest.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public void iteratesElementsOfAnIterableBackwards() {
3737
}
3838

3939
@Test
40-
@SuppressWarnings("unchecked")
40+
@SuppressWarnings({"unchecked", "ResultOfMethodCallIgnored"})
4141
public void doesNotBeginReversingUntilIterated() {
4242
Iterable<Integer> mockIterable = mock(Iterable.class);
4343
Iterator<Integer> mockIterator = mock(Iterator.class);
@@ -50,4 +50,9 @@ public void doesNotBeginReversingUntilIterated() {
5050
verify(mockIterator).hasNext();
5151
verify(mockIterator, never()).next();
5252
}
53+
54+
@Test
55+
public void doubleReverseIsNoOp() {
56+
assertThat(reverse(reverse(asList(1, 2, 3))), iterates(1, 2, 3));
57+
}
5358
}

src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/DropWhileTest.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@
1111
import testsupport.traits.ImmutableIteration;
1212
import testsupport.traits.Laziness;
1313

14+
import java.util.ArrayList;
15+
import java.util.List;
16+
1417
import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly;
18+
import static com.jnape.palatable.lambda.functions.builtin.fn1.Force.force;
1519
import static com.jnape.palatable.lambda.functions.builtin.fn2.DropWhile.dropWhile;
1620
import static java.util.Arrays.asList;
1721
import static org.junit.Assert.assertThat;
@@ -41,4 +45,19 @@ public void dropsAllElementsIfPredicateNeverFails() {
4145
public void dropsNoElementsIfPredicateImmediatelyFails() {
4246
assertThat(dropWhile(constantly(false), asList(1, 2, 3)), iterates(1, 2, 3));
4347
}
48+
49+
@Test
50+
public void deforestingExecutesPredicatesInOrder() {
51+
List<Integer> innerInvocations = new ArrayList<>();
52+
List<Integer> outerInvocations = new ArrayList<>();
53+
force(dropWhile(y -> {
54+
outerInvocations.add(y);
55+
return true;
56+
}, dropWhile(x -> {
57+
innerInvocations.add(x);
58+
return x > 2;
59+
}, asList(1, 2, 3))));
60+
assertThat(innerInvocations, iterates(1, 2, 3));
61+
assertThat(outerInvocations, iterates(1, 2));
62+
}
4463
}

src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/FilterTest.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@
1111
import testsupport.traits.ImmutableIteration;
1212
import testsupport.traits.Laziness;
1313

14+
import java.util.ArrayList;
15+
import java.util.List;
16+
1417
import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly;
18+
import static com.jnape.palatable.lambda.functions.builtin.fn1.Force.force;
1519
import static com.jnape.palatable.lambda.functions.builtin.fn2.Filter.filter;
1620
import static java.util.Arrays.asList;
1721
import static org.junit.Assert.assertThat;
@@ -21,7 +25,7 @@
2125
public class FilterTest {
2226

2327
@TestTraits({Laziness.class, EmptyIterableSupport.class, FiniteIteration.class, ImmutableIteration.class})
24-
public Fn1<? extends Iterable, ?> createTraitsTestSubject() {
28+
public Fn1<? extends Iterable, ?> testSubject() {
2529
return filter(constantly(true));
2630
}
2731

@@ -33,4 +37,19 @@ public void filtersOutMatchingElements() {
3337
iterates(2, 4, 6)
3438
);
3539
}
40+
41+
@Test
42+
public void deforestingExecutesPredicatesInOrder() {
43+
List<Integer> innerInvocations = new ArrayList<>();
44+
List<Integer> outerInvocations = new ArrayList<>();
45+
force(filter(y -> {
46+
outerInvocations.add(y);
47+
return true;
48+
}, filter(x -> {
49+
innerInvocations.add(x);
50+
return x % 2 == 0;
51+
}, asList(1, 2, 3))));
52+
assertThat(innerInvocations, iterates(1, 2, 3));
53+
assertThat(outerInvocations, iterates(2));
54+
}
3655
}

src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/SnocTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
import static com.jnape.palatable.lambda.functions.builtin.fn2.Snoc.snoc;
1717
import static java.util.Arrays.asList;
18+
import static java.util.Collections.emptyList;
1819
import static org.junit.Assert.assertThat;
1920
import static testsupport.matchers.IterableMatcher.iterates;
2021

@@ -35,4 +36,9 @@ public void appendToEmptyIterable() {
3536
public void appendToNonEmptyIterable() {
3637
assertThat(snoc(4, asList(1, 2, 3)), iterates(1, 2, 3, 4));
3738
}
39+
40+
@Test
41+
public void deforestingOrder() {
42+
assertThat(snoc(3, snoc(2, snoc(1, emptyList()))), iterates(1, 2, 3));
43+
}
3844
}

src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/TakeWhileTest.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@
1111
import testsupport.traits.ImmutableIteration;
1212
import testsupport.traits.Laziness;
1313

14+
import java.util.ArrayList;
15+
import java.util.List;
16+
1417
import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly;
18+
import static com.jnape.palatable.lambda.functions.builtin.fn1.Force.force;
1519
import static com.jnape.palatable.lambda.functions.builtin.fn2.TakeWhile.takeWhile;
1620
import static java.util.Arrays.asList;
1721
import static org.junit.Assert.assertThat;
@@ -46,4 +50,19 @@ public void takesAllElementsIfPredicateNeverFails() {
4650
public void takesNoElementsIfPredicateImmediatelyFails() {
4751
assertThat(takeWhile(constantly(false), asList(1, 2, 3)), isEmpty());
4852
}
53+
54+
@Test
55+
public void deforestingExecutesPredicatesInOrder() {
56+
List<Integer> innerInvocations = new ArrayList<>();
57+
List<Integer> outerInvocations = new ArrayList<>();
58+
force(takeWhile(y -> {
59+
outerInvocations.add(y);
60+
return true;
61+
}, takeWhile(x -> {
62+
innerInvocations.add(x);
63+
return x < 3;
64+
}, asList(1, 2, 3))));
65+
assertThat(innerInvocations, iterates(1, 2, 3));
66+
assertThat(outerInvocations, iterates(1, 2));
67+
}
4968
}

0 commit comments

Comments
 (0)