dev.marksman.enhancediterables.EnhancedIterables Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of enhanced-iterables Show documentation
Show all versions of enhanced-iterables Show documentation
Iterables with additional methods
package dev.marksman.enhancediterables;
import com.jnape.palatable.lambda.adt.Maybe;
import com.jnape.palatable.lambda.functions.Fn0;
import com.jnape.palatable.lambda.functions.builtin.fn1.Cycle;
import com.jnape.palatable.lambda.functions.builtin.fn1.Distinct;
import com.jnape.palatable.lambda.functions.builtin.fn1.Size;
import com.jnape.palatable.lambda.functions.builtin.fn1.Uncons;
import com.jnape.palatable.lambda.functions.builtin.fn2.ToCollection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import static com.jnape.palatable.lambda.adt.Maybe.just;
import static com.jnape.palatable.lambda.adt.Maybe.nothing;
import static dev.marksman.enhancediterables.ProtectedIterator.protectedIterator;
import static java.util.Arrays.asList;
import static java.util.Objects.requireNonNull;
final class EnhancedIterables {
private static final ImmutableFiniteIterable> EMPTY = () -> protectedIterator(Collections.emptyIterator());
private EnhancedIterables() {
}
@SuppressWarnings("unchecked")
static ImmutableFiniteIterable emptyEnhancedIterable() {
return (ImmutableFiniteIterable) EMPTY;
}
/**
* Note: Includes an attempt to promote to NonEmptyIterable, so be careful
* not to call this recursively in the non-empty constructors. Call simpleEnhance
* in those cases.
*/
static EnhancedIterable enhance(Iterable underlying) {
requireNonNull(underlying);
if (underlying instanceof EnhancedIterable>) {
return (EnhancedIterable) underlying;
} else if (underlying instanceof Collection>) {
return finiteIterableFromCollection((Collection) underlying);
} else if (underlying.iterator().hasNext()) {
return nonEmptyIterableOrThrow(underlying);
} else {
return () -> protectedIterator(underlying.iterator());
}
}
static FiniteIterable finiteIterable(Iterable underlying) {
requireNonNull(underlying);
if (underlying instanceof FiniteIterable>) {
return (FiniteIterable) underlying;
} else if (underlying instanceof Collection>) {
return new FiniteIterable() {
@Override
public Iterator iterator() {
return protectedIterator(underlying.iterator());
}
@Override
public int size() {
return ((Collection) underlying).size();
}
};
} else {
return () -> protectedIterator(underlying.iterator());
}
}
static ImmutableIterable immutableIterable(Iterable underlying) {
requireNonNull(underlying);
if (underlying instanceof ImmutableIterable>) {
return (ImmutableIterable) underlying;
} else if (underlying instanceof Collection>) {
return immutableFiniteIterableFromCollection((Collection) underlying);
} else if (underlying.iterator().hasNext()) {
return immutableNonEmptyIterableOrThrow(underlying);
} else {
return () -> protectedIterator(underlying.iterator());
}
}
static ImmutableFiniteIterable immutableFiniteIterable(Iterable underlying) {
if (underlying instanceof ImmutableFiniteIterable>) {
return (ImmutableFiniteIterable) underlying;
} else {
return () -> protectedIterator(underlying.iterator());
}
}
static Maybe> maybeFinite(Iterable iterable) {
if (iterable instanceof FiniteIterable>) {
return just((FiniteIterable) iterable);
} else if (iterable instanceof Collection>) {
return just(finiteIterable(iterable));
} else {
return nothing();
}
}
static Maybe> nonEmptyMaybeFinite(A head, Iterable tail) {
if (tail instanceof FiniteIterable>) {
return just(nonEmptyFiniteIterable(head, (FiniteIterable) tail));
} else if (tail instanceof Collection>) {
return just(nonEmptyFiniteIterable(head, finiteIterable(tail)));
} else {
return nothing();
}
}
static Maybe> immutableMaybeFinite(Iterable iterable) {
if (iterable instanceof ImmutableFiniteIterable>) {
return just((ImmutableFiniteIterable) iterable);
} else if (iterable instanceof Collection>) {
return just(immutableFiniteIterable(iterable));
} else {
return nothing();
}
}
static Maybe> immutableNonEmptyMaybeFinite(A head, Iterable tail) {
if (tail instanceof ImmutableFiniteIterable>) {
return just(immutableNonEmptyFiniteIterable(head, (ImmutableFiniteIterable) tail));
} else if (tail instanceof Collection>) {
return just(immutableNonEmptyFiniteIterable(head, immutableFiniteIterable(tail)));
} else {
return nothing();
}
}
static Maybe> maybeNonEmpty(Iterable iterable) {
if (iterable instanceof NonEmptyIterable>) {
return just((NonEmptyIterable) iterable);
} else {
return Uncons.uncons(iterable)
.fmap(headTail -> nonEmptyIterable(headTail._1(), headTail._2()));
}
}
static NonEmptyIterable nonEmptyIterable(A head, Iterable tail) {
EnhancedIterable enhancedTail = simpleEnhance(tail);
return new NonEmptyIterable() {
@Override
public A head() {
return head;
}
@Override
public EnhancedIterable tail() {
return enhancedTail;
}
};
}
static NonEmptyIterable nonEmptyIterableOrThrow(Iterable underlying) {
if (underlying instanceof NonEmptyIterable>) {
return (NonEmptyIterable) underlying;
} else {
if (!underlying.iterator().hasNext()) {
throw nonEmptyError().apply();
}
return new NonEmptyIterable() {
@Override
public A head() {
return iterator().next();
}
@Override
public EnhancedIterable tail() {
return this.drop(1);
}
@Override
public Iterator iterator() {
return protectedIterator(underlying.iterator());
}
};
}
}
static NonEmptyFiniteIterable nonEmptyFiniteIterable(A head, FiniteIterable tail) {
requireNonNull(tail);
return new NonEmptyFiniteIterable() {
@Override
public A head() {
return head;
}
@Override
public FiniteIterable tail() {
return tail;
}
};
}
static NonEmptyFiniteIterable nonEmptyFiniteIterable(A head, Collection tail) {
return nonEmptyFiniteIterable(head, finiteIterable(tail));
}
static NonEmptyFiniteIterable nonEmptyFiniteIterableOrThrow(Iterable underlying) {
if (underlying instanceof Collection>) {
return nonEmptyFiniteIterableFromCollectionOrThrow((Collection) underlying);
} else if (underlying instanceof NonEmptyFiniteIterable>) {
return (NonEmptyFiniteIterable) underlying;
} else {
if (!underlying.iterator().hasNext()) {
throw nonEmptyError().apply();
}
return new NonEmptyFiniteIterable() {
@Override
public A head() {
return iterator().next();
}
@Override
public FiniteIterable tail() {
return this.drop(1);
}
@Override
public Iterator iterator() {
return protectedIterator(underlying.iterator());
}
};
}
}
static ImmutableNonEmptyIterable immutableNonEmptyIterable(A head, ImmutableIterable tail) {
requireNonNull(tail);
return new ImmutableNonEmptyIterable() {
@Override
public A head() {
return head;
}
@Override
public ImmutableIterable tail() {
return tail;
}
};
}
static ImmutableNonEmptyIterable immutableNonEmptyIterableOrThrow(Iterable underlying) {
if (underlying instanceof ImmutableNonEmptyIterable>) {
return (ImmutableNonEmptyIterable) underlying;
} else {
if (!underlying.iterator().hasNext()) {
throw nonEmptyError().apply();
}
return new ImmutableNonEmptyIterable() {
@Override
public A head() {
return iterator().next();
}
@Override
public ImmutableIterable tail() {
return this.drop(1);
}
@Override
public Iterator iterator() {
return protectedIterator(underlying.iterator());
}
};
}
}
static ImmutableNonEmptyFiniteIterable immutableNonEmptyFiniteIterable(A head, ImmutableFiniteIterable tail) {
requireNonNull(tail);
return new ImmutableNonEmptyFiniteIterable() {
@Override
public A head() {
return head;
}
@Override
public ImmutableFiniteIterable tail() {
return tail;
}
};
}
static ImmutableNonEmptyFiniteIterable immutableNonEmptyFiniteIterableOrThrow(Iterable underlying) {
if (underlying instanceof ImmutableNonEmptyFiniteIterable>) {
return (ImmutableNonEmptyFiniteIterable) underlying;
} else {
if (!underlying.iterator().hasNext()) {
throw nonEmptyError().apply();
}
return new ImmutableNonEmptyFiniteIterable() {
@Override
public A head() {
return iterator().next();
}
@Override
public ImmutableFiniteIterable tail() {
return this.drop(1);
}
@Override
public Iterator iterator() {
return protectedIterator(underlying.iterator());
}
};
}
}
@SuppressWarnings("varargs")
@SafeVarargs
static ImmutableNonEmptyFiniteIterable of(A first, A... more) {
if (more.length > 0) {
ImmutableFiniteIterable tail = immutableFiniteIterable(asList(more));
return immutableNonEmptyFiniteIterable(first, tail);
} else {
return singleton(first);
}
}
static ImmutableNonEmptyFiniteIterable singleton(A value) {
return new Singleton<>(value);
}
static ImmutableFiniteIterable copyFrom(FiniteIterable source) {
if (source instanceof ImmutableFiniteIterable>) {
return (ImmutableFiniteIterable) source;
} else {
ArrayList underlying = ToCollection.toCollection(ArrayList::new, source);
if (underlying.isEmpty()) {
return Collections::emptyIterator;
} else {
return immutableNonEmptyFiniteIterableOrThrow(underlying);
}
}
}
static ImmutableFiniteIterable copyFrom(Collection source) {
return copyFrom(finiteIterable(source));
}
static ImmutableFiniteIterable copyFrom(int maxCount, Iterable source) {
if (source instanceof ImmutableIterable>) {
return ((ImmutableIterable) source).take(maxCount);
} else {
return copyFrom(FiniteIterable.finiteIterable(maxCount, source));
}
}
static ImmutableNonEmptyIterable repeat(A element) {
return new ImmutableNonEmptyIterable() {
@Override
public ImmutableIterable tail() {
return this;
}
@Override
public A head() {
return element;
}
@Override
public Iterator iterator() {
return new Iterator() {
@Override
public boolean hasNext() {
return true;
}
@Override
public A next() {
return element;
}
};
}
};
}
static EnhancedIterable cycle(FiniteIterable underlying) {
requireNonNull(underlying);
return underlying.toNonEmpty()
.match(__ -> emptyEnhancedIterable(),
EnhancedIterables::nonEmptyCycle);
}
static ImmutableIterable cycle(ImmutableFiniteIterable underlying) {
requireNonNull(underlying);
return underlying.toNonEmpty()
.match(__ -> emptyEnhancedIterable(),
EnhancedIterables::nonEmptyCycle);
}
static NonEmptyIterable nonEmptyCycle(NonEmptyFiniteIterable underlying) {
requireNonNull(underlying);
return nonEmptyIterableOrThrow(Cycle.cycle(underlying));
}
static ImmutableNonEmptyIterable nonEmptyCycle(ImmutableNonEmptyFiniteIterable underlying) {
requireNonNull(underlying);
return immutableNonEmptyIterableOrThrow(Cycle.cycle(underlying));
}
static FiniteIterable distinct(FiniteIterable underlying) {
requireNonNull(underlying);
return underlying.toNonEmpty()
.match(__ -> emptyEnhancedIterable(),
EnhancedIterables::nonEmptyDistinct);
}
static ImmutableFiniteIterable distinct(ImmutableFiniteIterable underlying) {
requireNonNull(underlying);
return underlying.toNonEmpty()
.match(__ -> emptyEnhancedIterable(),
EnhancedIterables::nonEmptyDistinct);
}
static NonEmptyFiniteIterable nonEmptyDistinct(NonEmptyFiniteIterable underlying) {
requireNonNull(underlying);
return nonEmptyFiniteIterableOrThrow(Distinct.distinct(underlying));
}
static ImmutableNonEmptyFiniteIterable nonEmptyDistinct(ImmutableNonEmptyFiniteIterable underlying) {
requireNonNull(underlying);
return immutableNonEmptyFiniteIterableOrThrow(Distinct.distinct(underlying));
}
static int size(FiniteIterable as) {
requireNonNull(as);
Long longSize = Size.size(as);
if (longSize > Integer.MAX_VALUE) {
return Integer.MAX_VALUE;
} else {
return longSize.intValue();
}
}
/**
* Does not attempt to promote to NonEmpty.
*/
private static EnhancedIterable simpleEnhance(Iterable underlying) {
requireNonNull(underlying);
if (underlying instanceof EnhancedIterable>) {
return (EnhancedIterable) underlying;
} else if (underlying instanceof Collection>) {
return finiteIterable(underlying);
} else {
return () -> protectedIterator(underlying.iterator());
}
}
/**
* Does not attempt to promote to NonEmpty.
*/
private static ImmutableIterable simpleImmutableIterable(Iterable underlying) {
requireNonNull(underlying);
if (underlying instanceof ImmutableIterable>) {
return (ImmutableIterable) underlying;
} else if (underlying instanceof Collection>) {
return immutableFiniteIterable(underlying);
} else {
return () -> protectedIterator(underlying.iterator());
}
}
private static FiniteIterable finiteIterableFromCollection(Collection collection) {
if (collection.isEmpty()) {
return finiteIterable(collection);
} else {
return nonEmptyFiniteIterableFromCollectionOrThrow(collection);
}
}
private static ImmutableIterable immutableFiniteIterableFromCollection(Collection collection) {
if (collection.isEmpty()) {
return immutableFiniteIterable(collection);
} else {
return immutableNonEmptyFiniteIterableOrThrow(collection);
}
}
private static NonEmptyFiniteIterable nonEmptyFiniteIterableFromCollectionOrThrow(Collection underlying) {
if (underlying.isEmpty()) {
throw nonEmptyError().apply();
}
return new NonEmptyFiniteIterable() {
@Override
public A head() {
return iterator().next();
}
@Override
public FiniteIterable tail() {
return this.drop(1);
}
@Override
public Iterator iterator() {
return protectedIterator(underlying.iterator());
}
@Override
public int size() {
return underlying.size();
}
};
}
private static Fn0 nonEmptyError() {
return () -> new IllegalArgumentException("Cannot construct NonEmptyIterable from empty input");
}
private static class Singleton implements ImmutableNonEmptyFiniteIterable {
private final A value;
private Singleton(A value) {
this.value = value;
}
@Override
public ImmutableFiniteIterable tail() {
return EnhancedIterables.emptyEnhancedIterable();
}
@Override
public A head() {
return value;
}
}
}