All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dev.marksman.enhancediterables.EnhancedIterables Maven / Gradle / Ivy

There is a newer version: 1.2.0
Show newest version
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;
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy