dev.marksman.kraftwerk.ValueSupply Maven / Gradle / Ivy
Show all versions of kraftwerk Show documentation
package dev.marksman.kraftwerk;
import com.jnape.palatable.lambda.functions.Fn1;
import dev.marksman.enhancediterables.ImmutableIterable;
import dev.marksman.enhancediterables.ImmutableNonEmptyIterable;
import java.util.Iterator;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
/**
* An infinite sequence of values of type {@code A}.
*
* A {@code ValueSupply} does not have internal state, so it can be iterated multiple times, and for each time will return
* the same sequence.
*
* Each element of a {@code ValueSupply} is lazily computed, therefore, a {@code ValueSupply} only requires a small, constant
* amount of memory.
*
* @param the element type
*/
public final class ValueSupply implements ImmutableNonEmptyIterable {
private final Fn1> gen;
private final A firstValue;
private final Seed state;
private ValueSupply(Fn1> gen, Seed initialState) {
this.gen = gen;
Result extends Seed, A> r1 = gen.apply(initialState);
this.firstValue = r1.getValue();
this.state = r1.getNextState();
}
static ValueSupply valueSupply(Fn1> gen, Seed initialState) {
return new ValueSupply<>(gen, initialState);
}
@Override
public A head() {
return firstValue;
}
@Override
public ImmutableIterable tail() {
return () -> new TailIterator<>(gen, state);
}
@Override
public ValueSupply drop(int count) {
if (count <= 0) {
return this;
} else {
Seed current = state;
for (int i = 0; i < count; i++) {
current = gen.apply(current).getNextState();
}
return new ValueSupply<>(gen, current);
}
}
/**
* Creates a {@link Stream} from this {@code ValueSupply}.
*
* @return a {@code Stream}
*/
public Stream stream() {
return StreamSupport.stream(spliterator(), false);
}
private static class TailIterator implements Iterator {
private final Fn1> gen;
private Seed state;
private TailIterator(Fn1> gen, Seed state) {
this.gen = gen;
this.state = state;
}
@Override
public boolean hasNext() {
return true;
}
@Override
public A next() {
Result extends Seed, A> run;
synchronized (this) {
run = this.gen.apply(state);
state = run.getNextState();
}
return run.getValue();
}
}
}