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

dev.marksman.enhancediterables.ImmutableNonEmptyFiniteIterable 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.adt.hlist.Tuple2;
import com.jnape.palatable.lambda.functions.Fn1;
import com.jnape.palatable.lambda.functions.Fn2;
import com.jnape.palatable.lambda.functions.builtin.fn1.Init;
import com.jnape.palatable.lambda.functions.builtin.fn1.Reverse;
import com.jnape.palatable.lambda.functions.builtin.fn2.*;
import com.jnape.palatable.lambda.functions.builtin.fn3.ZipWith;
import com.jnape.palatable.lambda.monoid.builtin.Concat;

import static com.jnape.palatable.lambda.adt.Maybe.just;
import static dev.marksman.enhancediterables.EnhancedIterables.immutableFiniteIterable;
import static dev.marksman.enhancediterables.EnhancedIterables.immutableNonEmptyFiniteIterableOrThrow;
import static java.util.Objects.requireNonNull;

/**
 * An {@code EnhancedIterable} that is finite, safe from mutation, and guaranteed to contain at least one element.
 *
 * @param  the element type
 */
public interface ImmutableNonEmptyFiniteIterable extends ImmutableFiniteIterable, ImmutableNonEmptyIterable,
        NonEmptyFiniteIterable {

    /**
     * Returns an {@code ImmutableFiniteIterable} containing all subsequent elements of this one beyond the first.
     *
     * @return an {@code ImmutableFiniteIterable}
     */
    @Override
    ImmutableFiniteIterable tail();

    /**
     * Lazily concatenates another {@code ImmutableFiniteIterable} to the end of this {@code ImmutableNonEmptyFiniteIterable},
     * yielding a new {@code ImmutableIterable}.
     *
     * @param other the other {@link ImmutableIterable}
     * @return an {@code ImmutableIterable}
     */
    @Override
    default ImmutableNonEmptyFiniteIterable concat(ImmutableFiniteIterable other) {
        requireNonNull(other);
        return immutableNonEmptyFiniteIterableOrThrow(Concat.concat(this, other));
    }

    /**
     * Returns the lazily computed cartesian product of this {@code ImmutableNonEmptyFiniteIterable} with another {@code ImmutableNonEmptyFiniteIterable}.
     *
     * @param other an {@code ImmutableNonEmptyFiniteIterable} of any type
     * @param    the type of the other {@code ImmutableNonEmptyFiniteIterable}
     * @return a {@code ImmutableNonEmptyFiniteIterable>}
     */
    default  ImmutableNonEmptyFiniteIterable> cross(ImmutableNonEmptyFiniteIterable other) {
        requireNonNull(other);
        return immutableNonEmptyFiniteIterableOrThrow(CartesianProduct.cartesianProduct(this, other));
    }

    /**
     * Returns an infinite {@code ImmutableNonEmptyIterable} that repeatedly cycles this {@code ImmutableNonEmptyFiniteIterable}'s elements,
     * in order.
     *
     * @return an {@code ImmutableNonEmptyIterable}
     */
    default ImmutableNonEmptyIterable cycle() {
        return EnhancedIterables.nonEmptyCycle(this);
    }

    /**
     * Returns a {@code ImmutableNonEmptyFiniteIterable} of the distinct values from this {@link ImmutableNonEmptyFiniteIterable}.
     *
     * @return a {@code ImmutableNonEmptyFiniteIterable}
     */
    default ImmutableNonEmptyFiniteIterable distinct() {
        return EnhancedIterables.nonEmptyDistinct(this);
    }

    /**
     * Returns a new {@code ImmutableNonEmptyFiniteIterable} by applying a function to all elements of this {@code ImmutableNonEmptyFiniteIterable}.
     *
     * @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 an {@code ImmutableNonEmptyFiniteIterable}
     */
    @Override
    default  ImmutableNonEmptyFiniteIterable fmap(Fn1 f) {
        requireNonNull(f);
        return immutableNonEmptyFiniteIterableOrThrow(Map.map(f, this));
    }

    /**
     * Returns an {@code ImmutableFiniteIterable} containing all of elements of this one, except for the last element.
     *
     * @return an {@code ImmutableFiniteIterable}
     */
    @Override
    default ImmutableFiniteIterable init() {
        return immutableFiniteIterable(Init.init(this));
    }

    /**
     * Returns a new {@code ImmutableNonEmptyFiniteIterable} with the provided separator value injected between each value of this
     * {@code ImmutableNonEmptyFiniteIterable}.
     * 

* If this {@code ImmutableNonEmptyFiniteIterable} contains only one element, it is left untouched. * * @param separator the separator value * @return an {@code ImmutableNonEmptyFiniteIterable} */ @Override default ImmutableNonEmptyFiniteIterable intersperse(A separator) { return immutableNonEmptyFiniteIterableOrThrow(Intersperse.intersperse(separator, this)); } /** * Returns an {@code Iterable} of contiguous groups of elements in this {@code ImmutableNonEmptyFiniteIterable} that match a * predicate pairwise. * * @param predicate the predicate function. * This function should be referentially transparent and not perform side-effects. * It may be called zero or more times for each element. * @return an {@code ImmutableNonEmptyFiniteIterable>} containing the contiguous groups */ @Override default ImmutableNonEmptyFiniteIterable> magnetizeBy(Fn2 predicate) { requireNonNull(predicate); return immutableNonEmptyFiniteIterableOrThrow(MagnetizeBy.magnetizeBy(predicate, this)) .fmap(EnhancedIterables::immutableNonEmptyFiniteIterableOrThrow); } /** * Lazily prepends an element to the front of this {@code ImmutableNonEmptyFiniteIterable}, yielding a new {@code ImmutableNonEmptyFiniteIterable}. * * @param element the element to prepend * @return a {@code ImmutableNonEmptyFiniteIterable} */ @Override default ImmutableNonEmptyFiniteIterable prepend(A element) { return immutableNonEmptyFiniteIterable(element, this); } /** * Returns a new {@code ImmutableNonEmptyFiniteIterable} with the provided separator value injected before each value of this * {@code ImmutableNonEmptyFiniteIterable}. * * @param separator the separator value * @return an {@code ImmutableNonEmptyFiniteIterable} */ @Override default ImmutableNonEmptyFiniteIterable prependAll(A separator) { return immutableNonEmptyFiniteIterableOrThrow(PrependAll.prependAll(separator, this)); } /** * Returns a reversed representation of this {@code ImmutableNonEmptyFiniteIterable}. *

* Note that reversing is deferred until the returned {@code Iterable} is iterated. * * @return an {@code ImmutableNonEmptyFiniteIterable} */ @Override default ImmutableNonEmptyFiniteIterable reverse() { return immutableNonEmptyFiniteIterableOrThrow(Reverse.reverse(this)); } /** * Always succeeds because {@code ImmutableNonEmptyFiniteIterable}s are always finite. * * @return this {@code ImmutableNonEmptyFiniteIterable} wrapped in a `just` */ @Override default Maybe> toFinite() { return just(this); } /** * Always succeeds because {@code ImmutableNonEmptyFiniteIterable}s are always non-empty. * * @return this {@code ImmutableNonEmptyFiniteIterable} wrapped in a `just` */ @Override default Maybe> toNonEmpty() { return just(this); } /** * Zips together this {@code ImmutableNonEmptyFiniteIterable} with another {@code ImmutableNonEmptyIterable} by applying a zipping function. *

* Applies the function to the successive elements of each {@code Iterable} until one of them runs out of elements. * * @param fn the zipping function. * Not null. * This function should be referentially transparent and not perform side-effects. * It may be called zero or more times for each element. * @param other the other {@code Iterable} * @param the element type of the other {@code Iterable} * @param the element type of the result * @return an {@code ImmutableNonEmptyFiniteIterable} */ default ImmutableNonEmptyFiniteIterable zipWith(Fn2 fn, ImmutableNonEmptyIterable other) { requireNonNull(fn); requireNonNull(other); return immutableNonEmptyFiniteIterableOrThrow(ZipWith.zipWith(fn, this, other)); } /** * Creates an {@code ImmutableNonEmptyFiniteIterable}. * * @param head the first element * @param tail the remaining elements. May be empty. * @param the element type * @return a {@code ImmutableNonEmptyFiniteIterable} */ static ImmutableNonEmptyFiniteIterable immutableNonEmptyFiniteIterable(A head, ImmutableFiniteIterable tail) { return EnhancedIterables.immutableNonEmptyFiniteIterable(head, tail); } /** * Creates an {@code ImmutableNonEmptyFiniteIterable} containing the given elements. * * @param first the first element * @param more the remaining elements * @param the element type * @return an {@code ImmutableNonEmptyFiniteIterable} */ @SuppressWarnings("varargs") @SafeVarargs static ImmutableNonEmptyFiniteIterable of(A first, A... more) { if (more.length > 0) { return EnhancedIterables.of(first, more); } else { return EnhancedIterables.singleton(first); } } }