dev.marksman.enhancediterables.NonEmptyIterable Maven / Gradle / Ivy
Show all versions of enhanced-iterables Show documentation
package dev.marksman.enhancediterables;
import com.jnape.palatable.lambda.functions.Fn1;
import com.jnape.palatable.lambda.functions.Fn2;
import com.jnape.palatable.lambda.functions.builtin.fn2.Cons;
import com.jnape.palatable.lambda.functions.builtin.fn2.Intersperse;
import com.jnape.palatable.lambda.functions.builtin.fn2.Map;
import com.jnape.palatable.lambda.functions.builtin.fn2.PrependAll;
import com.jnape.palatable.lambda.functions.builtin.fn3.ZipWith;
import com.jnape.palatable.lambda.monoid.builtin.Concat;
import java.util.Iterator;
import static dev.marksman.enhancediterables.EnhancedIterable.enhance;
import static dev.marksman.enhancediterables.EnhancedIterables.nonEmptyFiniteIterableOrThrow;
import static dev.marksman.enhancediterables.EnhancedIterables.nonEmptyIterableOrThrow;
import static java.util.Objects.requireNonNull;
/**
* An {@code EnhancedIterable} that is guaranteed to contain at least one element.
*
* May be infinite or finite.
*
* @param the element type
*/
public interface NonEmptyIterable extends EnhancedIterable {
/**
* Returns the first element.
*
* @return an element of type {@code A}
*/
A head();
/**
* Returns an {@link EnhancedIterable} containing all subsequent elements beyond the first.
*
* @return an {@code EnhancedIterable}. May be empty.
*/
EnhancedIterable tail();
/**
* Lazily concatenates an {@code Iterable} to the end of this {@code NonEmptyIterable},
* yielding a new {@code NonEmptyIterable}.
*
* @param other an {@link Iterable}
* @return a NonEmptyIterable<A>
*/
@Override
default NonEmptyIterable concat(Iterable other) {
requireNonNull(other);
return nonEmptyIterableOrThrow(Concat.concat(this, other));
}
/**
* Returns a new {@code NonEmptyIterable} by applying a function to all elements of this {@code NonEmptyIterable}.
*
* @param f a function from {@code A} to {@code B}.
* This function should be referentially transparent and not perform side-effects.
* It may be called zero or more times for each element.
* @param the type returned by {@code f}
* @return a NonEmptyIterable<B>
*/
@Override
default NonEmptyIterable fmap(Fn1 super A, ? extends B> f) {
requireNonNull(f);
return nonEmptyIterable(f.apply(head()), Map.map(f, tail()));
}
/**
* Always returns false, as a {@code NonEmptyIterable} is never empty.
*
* @return false
*/
@Override
default boolean isEmpty() {
return false;
}
/**
* Returns a new {@code NonEmptyIterable} with the provided separator value injected between each value of this
* {@code NonEmptyIterable}.
*
* If this {@code NonEmptyIterable} contains only one element, it is left untouched.
*
* @param separator the separator value
* @return a NonEmptyIterable<A>
*/
@Override
default NonEmptyIterable intersperse(A separator) {
return nonEmptyIterableOrThrow(Intersperse.intersperse(separator, this));
}
@Override
default Iterator iterator() {
return Cons.cons(head(), tail()).iterator();
}
/**
* Returns a new {@code NonEmptyIterable} with the provided separator value injected before each value of this
* {@code NonEmptyIterable}.
*
* @param separator the separator value
* @return a NonEmptyIterable<A>
*/
@Override
default NonEmptyIterable prependAll(A separator) {
return nonEmptyIterableOrThrow(PrependAll.prependAll(separator, this));
}
default NonEmptyIterable zipWith(Fn2 fn, NonEmptyIterable other) {
requireNonNull(fn);
requireNonNull(other);
return nonEmptyIterable(fn.apply(head(), other.head()),
ZipWith.zipWith(fn, tail(), other.tail()));
}
default NonEmptyFiniteIterable zipWith(Fn2 fn, NonEmptyFiniteIterable other) {
requireNonNull(fn);
requireNonNull(other);
return nonEmptyFiniteIterableOrThrow(ZipWith.zipWith(fn, this, other));
}
/**
* Creates a {@link NonEmptyIterable}.
*
* @param head the first element
* @param tail the remaining elements. May be empty.
* @param the element type
* @return a {@code NonEmptyIterable}
*/
static NonEmptyIterable nonEmptyIterable(A head, Iterable tail) {
EnhancedIterable enhancedTail = enhance(tail);
return new NonEmptyIterable() {
@Override
public A head() {
return head;
}
@Override
public EnhancedIterable tail() {
return enhancedTail;
}
};
}
}