Skip to content

Commit 36ecd53

Browse files
committed
PrependAll now only allocates a single Iterable
1 parent b15fdd0 commit 36ecd53

4 files changed

Lines changed: 79 additions & 6 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
66
## [Unreleased]
77
### Fixed
88
- `CoProductN#embed` no longer eagerly invokes functions
9+
- `PrependAll` now only creates `O(1)` `Iterable`s instead of `O(3n + 1)`
910

1011
### Added
1112
- `Monad` arrives. The following `Applicative`s are now also `Monad`:

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

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

33
import com.jnape.palatable.lambda.functions.Fn1;
44
import com.jnape.palatable.lambda.functions.Fn2;
5-
6-
import static com.jnape.palatable.lambda.functions.builtin.fn1.Head.head;
7-
import static com.jnape.palatable.lambda.functions.builtin.fn1.Tail.tail;
8-
import static com.jnape.palatable.lambda.functions.builtin.fn2.Cons.cons;
9-
import static java.util.Collections.emptyList;
5+
import com.jnape.palatable.lambda.iterators.PrependingIterator;
106

117
/**
128
* Lazily prepend each value with of the <code>Iterable</code> with the supplied separator value. An empty
@@ -24,7 +20,7 @@ private PrependAll() {
2420

2521
@Override
2622
public Iterable<A> apply(A a, Iterable<A> as) {
27-
return () -> head(as).fmap(head -> cons(a, cons(head, prependAll(a, tail(as))))).orElse(emptyList()).iterator();
23+
return () -> new PrependingIterator<>(a, as.iterator());
2824
}
2925

3026
@SuppressWarnings("unchecked")
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.jnape.palatable.lambda.iterators;
2+
3+
import java.util.Iterator;
4+
import java.util.NoSuchElementException;
5+
6+
public final class PrependingIterator<A> extends ImmutableIterator<A> {
7+
8+
private final A antecedent;
9+
private final Iterator<A> iterator;
10+
private boolean prependNext;
11+
12+
public PrependingIterator(A antecedent, Iterator<A> iterator) {
13+
this.antecedent = antecedent;
14+
this.iterator = iterator;
15+
prependNext = true;
16+
}
17+
18+
@Override
19+
public boolean hasNext() {
20+
return iterator.hasNext();
21+
}
22+
23+
@Override
24+
public A next() {
25+
if (!iterator.hasNext())
26+
throw new NoSuchElementException();
27+
28+
return (prependNext = !prependNext) ? iterator.next() : antecedent;
29+
}
30+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.jnape.palatable.lambda.iterators;
2+
3+
import org.junit.Rule;
4+
import org.junit.Test;
5+
import org.junit.rules.ExpectedException;
6+
7+
import java.util.NoSuchElementException;
8+
9+
import static java.util.Arrays.asList;
10+
import static java.util.Collections.emptyIterator;
11+
import static org.junit.Assert.assertEquals;
12+
import static org.junit.Assert.assertFalse;
13+
import static org.junit.Assert.assertTrue;
14+
15+
public class PrependingIteratorTest {
16+
17+
@Rule public ExpectedException thrown = ExpectedException.none();
18+
19+
@Test
20+
public void empty() {
21+
PrependingIterator<Integer> iterator = new PrependingIterator<>(0, emptyIterator());
22+
assertFalse(iterator.hasNext());
23+
24+
thrown.expect(NoSuchElementException.class);
25+
iterator.next();
26+
}
27+
28+
@Test
29+
public void nonEmpty() {
30+
PrependingIterator<Integer> iterator = new PrependingIterator<>(0, asList(1, 2, 3).iterator());
31+
32+
assertTrue(iterator.hasNext());
33+
assertEquals((Integer) 0, iterator.next());
34+
assertTrue(iterator.hasNext());
35+
assertEquals((Integer) 1, iterator.next());
36+
assertTrue(iterator.hasNext());
37+
assertEquals((Integer) 0, iterator.next());
38+
assertTrue(iterator.hasNext());
39+
assertEquals((Integer) 2, iterator.next());
40+
assertTrue(iterator.hasNext());
41+
assertEquals((Integer) 0, iterator.next());
42+
assertTrue(iterator.hasNext());
43+
assertEquals((Integer) 3, iterator.next());
44+
assertFalse(iterator.hasNext());
45+
}
46+
}

0 commit comments

Comments
 (0)