Skip to content

Commit db06c19

Browse files
committed
- Snoc deforesting moved to custom Iterable
1 parent 9e1784d commit db06c19

File tree

7 files changed

+57
-49
lines changed

7 files changed

+57
-49
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
1111
- `Identity`, `Compose`, and `Const` functors all have better `toString` implementations
1212
- `Into3-8` now supports functions with parameter variance
1313
- `HListLens#tail` is now covariant in `Tail` parameter
14-
- More functions now automatically deforest nested calls
14+
- More functions now automatically deforest nested calls (`drop`, `snoc`)
1515

1616
### Added
1717
- `BoundedBifunctor`, a `Bifunctor` super type that offers upper bounds for both parameters

src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Snoc.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import com.jnape.palatable.lambda.functions.Fn1;
44
import com.jnape.palatable.lambda.functions.Fn2;
5-
import com.jnape.palatable.lambda.iteration.SnocIterator;
5+
import com.jnape.palatable.lambda.iteration.SnocIterable;
66

77
/**
88
* Opposite of {@link Cons}: lazily append an element to the end of the given {@link Iterable}.
@@ -22,7 +22,7 @@ private Snoc() {
2222

2323
@Override
2424
public Iterable<A> apply(A a, Iterable<A> as) {
25-
return () -> new SnocIterator<>(a, as);
25+
return new SnocIterable<>(a, as);
2626
}
2727

2828
@SuppressWarnings("unchecked")

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import java.util.Iterator;
44

5-
public class DroppingIterable<A> implements Iterable<A> {
5+
public final class DroppingIterable<A> implements Iterable<A> {
66
private final int n;
77
private final Iterable<A> as;
88

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.jnape.palatable.lambda.iteration;
2+
3+
import java.util.Collections;
4+
import java.util.Iterator;
5+
6+
import static com.jnape.palatable.lambda.functions.builtin.fn2.Cons.cons;
7+
import static com.jnape.palatable.lambda.monoid.builtin.Concat.concat;
8+
9+
public final class SnocIterable<A> implements Iterable<A> {
10+
private final Iterable<A> as;
11+
private final Iterable<A> snocs;
12+
13+
public SnocIterable(A a, Iterable<A> as) {
14+
Iterable<A> snocs = cons(a, Collections::emptyIterator);
15+
while (as instanceof SnocIterable) {
16+
SnocIterable<A> nested = ((SnocIterable<A>) as);
17+
as = nested.as;
18+
snocs = concat(nested.snocs, snocs);
19+
}
20+
this.as = as;
21+
this.snocs = snocs;
22+
}
23+
24+
@Override
25+
public Iterator<A> iterator() {
26+
return new SnocIterator<>(as.iterator(), snocs.iterator());
27+
}
28+
}
Lines changed: 7 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,28 @@
11
package com.jnape.palatable.lambda.iteration;
22

3-
import java.util.Collections;
43
import java.util.Iterator;
54
import java.util.NoSuchElementException;
6-
import java.util.function.Supplier;
7-
8-
import static com.jnape.palatable.lambda.functions.builtin.fn2.Cons.cons;
95

106
public final class SnocIterator<A> implements Iterator<A> {
117

12-
private final Supplier<Iterator<A>> initsSupplier;
13-
private final A last;
14-
private Iterator<A> inits;
15-
private Iterator<A> lasts;
8+
private final Iterator<A> as;
9+
private final Iterator<A> snocs;
1610

17-
public SnocIterator(A last, Iterable<A> inits) {
18-
this.last = last;
19-
initsSupplier = inits::iterator;
11+
public SnocIterator(Iterator<A> as, Iterator<A> snocs) {
12+
this.as = as;
13+
this.snocs = snocs;
2014
}
2115

2216
@Override
2317
public boolean hasNext() {
24-
if (inits == null)
25-
queueAndDeforest();
26-
27-
return inits.hasNext() || lasts.hasNext();
18+
return as.hasNext() || snocs.hasNext();
2819
}
2920

3021
@Override
3122
public A next() {
3223
if (!hasNext())
3324
throw new NoSuchElementException();
3425

35-
return inits.hasNext() ? inits.next() : lasts.next();
36-
}
37-
38-
private void queueAndDeforest() {
39-
Iterable<A> lastConses = Collections::emptyIterator;
40-
inits = this;
41-
while (inits instanceof SnocIterator) {
42-
SnocIterator<A> it = (SnocIterator<A>) inits;
43-
lastConses = cons(it.last, lastConses);
44-
inits = it.initsSupplier.get();
45-
}
46-
lasts = lastConses.iterator();
26+
return as.hasNext() ? as.next() : snocs.next();
4727
}
4828
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.jnape.palatable.lambda.iteration;
2+
3+
import com.jnape.palatable.lambda.functions.Fn1;
4+
import com.jnape.palatable.traitor.annotations.TestTraits;
5+
import com.jnape.palatable.traitor.runners.Traits;
6+
import org.junit.runner.RunWith;
7+
import testsupport.traits.NestingStackSafety;
8+
9+
@RunWith(Traits.class)
10+
public class SnocIterableTest {
11+
12+
@TestTraits({NestingStackSafety.class})
13+
public Fn1<Iterable<Object>, Iterable<Object>> testSubject() {
14+
return xs -> new SnocIterable<>(1, xs);
15+
}
16+
}

src/test/java/com/jnape/palatable/lambda/iteration/SnocIteratorTest.java

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,8 @@
33
import org.junit.Before;
44
import org.junit.Test;
55

6-
import java.util.Collections;
7-
8-
import static com.jnape.palatable.lambda.adt.Maybe.just;
9-
import static com.jnape.palatable.lambda.functions.builtin.fn1.Last.last;
10-
import static com.jnape.palatable.lambda.functions.builtin.fn2.Iterate.iterate;
11-
import static com.jnape.palatable.lambda.functions.builtin.fn2.Take.take;
12-
import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft;
136
import static java.util.Arrays.asList;
7+
import static java.util.Collections.singletonList;
148
import static org.junit.Assert.assertEquals;
159
import static org.junit.Assert.assertFalse;
1610
import static org.junit.Assert.assertTrue;
@@ -21,7 +15,7 @@ public class SnocIteratorTest {
2115

2216
@Before
2317
public void setUp() {
24-
iterator = new SnocIterator<>(3, asList(1, 2));
18+
iterator = new SnocIterator<>(asList(1, 2).iterator(), singletonList(3).iterator());
2519
}
2620

2721
@Test
@@ -45,14 +39,4 @@ public void doesNotHaveNextIfLastIterated() {
4539
iterator.next();
4640
assertFalse(iterator.hasNext());
4741
}
48-
49-
@Test
50-
public void stackSafety() {
51-
int stackBlowingNumber = 100000;
52-
Iterable<Integer> ints = foldLeft((xs, x) -> () -> new SnocIterator<>(x, xs),
53-
Collections::emptyIterator,
54-
take(stackBlowingNumber, iterate(x -> x + 1, 1)));
55-
56-
assertEquals(just(stackBlowingNumber), last(ints));
57-
}
5842
}

0 commit comments

Comments
 (0)