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

dev.marksman.collectionviews.Vectors Maven / Gradle / Ivy

There is a newer version: 1.2.3
Show newest version
package dev.marksman.collectionviews;

import com.jnape.palatable.lambda.adt.Maybe;
import com.jnape.palatable.lambda.adt.hlist.Tuple2;
import com.jnape.palatable.lambda.functions.Fn0;
import com.jnape.palatable.lambda.functions.Fn1;
import com.jnape.palatable.lambda.functions.Fn2;
import com.jnape.palatable.lambda.functions.builtin.fn2.Drop;
import com.jnape.palatable.lambda.functions.builtin.fn2.Take;
import dev.marksman.enhancediterables.ImmutableNonEmptyFiniteIterable;
import dev.marksman.enhancediterables.NonEmptyIterable;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import static com.jnape.palatable.lambda.adt.Maybe.just;
import static com.jnape.palatable.lambda.adt.Maybe.nothing;
import static com.jnape.palatable.lambda.adt.hlist.HList.tuple;
import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into;
import static com.jnape.palatable.lambda.functions.builtin.fn2.ToCollection.toCollection;
import static com.jnape.palatable.lambda.functions.builtin.fn2.Tupler2.tupler;
import static dev.marksman.collectionviews.CrossJoinVector.crossJoinVector;
import static dev.marksman.collectionviews.ImmutableVectors.nonEmptyRange;
import static dev.marksman.collectionviews.MapperChain.mapperChain;
import static dev.marksman.collectionviews.Validation.*;
import static dev.marksman.collectionviews.VectorZip.vectorZip;

final class Vectors {

    private Vectors() {

    }

    static  Vector> cross(Vector first, Vector second) {
        return second.toNonEmpty()., NonEmptyVector>>zip(first.toNonEmpty()
                .fmap(tupler()))
                .match(__ -> empty(),
                        into(Vectors::nonEmptyCross));
    }

    static  Vector drop(int count, Vector source) {
        return VectorSlicing.dropImpl(VectorSlice::vectorSlice, count, source);
    }

    static  Vector dropRight(int count, Vector source) {
        validateDrop(count, source);
        int size = source.size();
        if (count >= size) {
            return empty();
        } else {
            return take(size - count, source);
        }
    }

    static  ImmutableVector empty() {
        return EmptyVector.emptyVector();
    }

    static  Maybe findIndex(Fn1 predicate, Vector vec) {
        int size = vec.size();
        for (int i = 0; i < size; i++) {
            if (predicate.apply(vec.unsafeGet(i))) {
                return just(i);
            }
        }
        return nothing();
    }

    static  int findPrefixLength(Fn1 predicate, Vector vec) {
        int result = 0;
        for (A current : vec) {
            if (predicate.apply(current)) {
                result += 1;
            } else {
                break;
            }
        }
        return result;
    }

    static  ImmutableNonEmptyFiniteIterable> inits(Vector source) {
        return nonEmptyRange(source.size() + 1).fmap(source::dropRight);
    }

    static  Vector map(Fn1 f, Vector source) {
        return maybeNonEmptyWrap(source)
                .match(__ -> empty(),
                        nonEmpty -> nonEmptyMap(f, nonEmpty));
    }

    static  Maybe> maybeNonEmptyWrap(A[] arr) {
        Objects.requireNonNull(arr);
        if (arr.length == 0) {
            return nothing();
        } else {
            return just(new WrappedArrayVector<>(arr));
        }
    }

    static  Maybe> maybeNonEmptyWrap(List list) {
        Objects.requireNonNull(list);
        if (list.isEmpty()) {
            return nothing();
        } else {
            return just(new WrappedListVector<>(list));
        }
    }

    static  Maybe> maybeNonEmptyWrap(Vector vec) {
        Objects.requireNonNull(vec);
        if (vec instanceof NonEmptyVector) {
            return just((NonEmptyVector) vec);
        } else if (!vec.isEmpty()) {
            return just(new VectorCons<>(vec.unsafeGet(0), vec.drop(1)));
        } else {
            return nothing();
        }
    }

    static  NonEmptyVector> nonEmptyCross(NonEmptyVector first, NonEmptyVector second) {
        return crossJoinVector(first, second);
    }

    static Fn0 nonEmptyError() {
        return () -> new IllegalArgumentException("Cannot construct NonEmptyVector from empty input");
    }

    static  NonEmptyIterable> nonEmptyInits(NonEmptyVector source) {
        return nonEmptyRange(source.size() + 1).fmap(source::dropRight);
    }

    @SuppressWarnings("unchecked")
    static  NonEmptyVector nonEmptyMap(Fn1 f, NonEmptyVector source) {
        return new MappedVector<>(mapperChain((Fn1) f),
                (NonEmptyVector) source);
    }

    static  NonEmptyVector nonEmptyReverse(NonEmptyVector vec) {
        Objects.requireNonNull(vec);
        if (vec.size() < 2) {
            return vec;
        } else {
            return ReverseVector.reverseVector(vec);
        }
    }

    @SuppressWarnings("varargs")
    @SafeVarargs
    static  ImmutableNonEmptyVector nonEmptyVectorOf(A first, A... more) {
        return new ImmutableVectorCons<>(first, ImmutableVectors.wrapAndVouchFor(more));
    }

    static  NonEmptyVector nonEmptyWrapOrThrow(A[] arr) {
        return getNonEmptyOrThrow(maybeNonEmptyWrap(arr));
    }

    static  NonEmptyVector nonEmptyWrapOrThrow(List list) {
        return getNonEmptyOrThrow(maybeNonEmptyWrap(list));
    }

    static  NonEmptyVector nonEmptyWrapOrThrow(Vector vec) {
        return getNonEmptyOrThrow(maybeNonEmptyWrap(vec));
    }

    static  NonEmptyVector nonEmptyZipWith(Fn2 fn, NonEmptyVector first, NonEmptyVector second) {
        Objects.requireNonNull(fn);
        Objects.requireNonNull(first);
        Objects.requireNonNull(second);
        return vectorZip(fn, first, second);
    }

    static  NonEmptyVector> nonEmptyZipWithIndex(NonEmptyVector vec) {
        Objects.requireNonNull(vec);
        return nonEmptyZipWith(tupler(), vec, vec.indices());
    }

    static  Vector reverse(Vector vec) {
        Objects.requireNonNull(vec);
        if (vec.size() < 2) {
            return vec;
        } else {
            return ReverseVector.reverseVector(vec.toNonEmptyOrThrow());
        }
    }

    static  Vector slice(int startIndex, int endIndexExclusive, Vector source) {
        return sliceFromIterable(startIndex, endIndexExclusive, source);
    }

    static  Vector sliceFromIterable(int startIndex, int endIndexExclusive, Iterable source) {
        validateSlice(startIndex, endIndexExclusive, source);
        int requestedSize = endIndexExclusive - startIndex;
        if (requestedSize < 1) {
            return empty();
        }
        if (source instanceof Vector) {
            Vector sourceVector = (Vector) source;
            return VectorSlicing.sliceImpl(VectorSlice::vectorSlice, sourceVector.size(), () -> sourceVector, startIndex, requestedSize);
        } else if (source instanceof List) {
            List sourceList = (List) source;
            return VectorSlicing.sliceImpl(VectorSlice::vectorSlice, sourceList.size(), () -> Vector.wrap(sourceList), startIndex, requestedSize);
        } else {
            ArrayList newList = toCollection(ArrayList::new, Take.take(requestedSize, Drop.drop(startIndex, source)));
            return ImmutableVectors.wrapAndVouchFor(newList);
        }
    }

    static  Tuple2, Vector> splitAt(int index, Vector source) {
        validateTake(index, source);
        return tuple(source.take(index), source.drop(index));
    }

    static  ImmutableNonEmptyFiniteIterable> tails(Vector source) {
        return nonEmptyRange(source.size() + 1).fmap(source::drop);
    }

    static  Vector take(int count, Vector source) {
        validateTake(count, source);
        return sliceFromIterable(0, count, source);
    }

    static  Vector takeRight(int count, Vector source) {
        validateTake(count, source);
        int size = source.size();
        if (count >= size) {
            return source;
        } else {
            return drop(size - count, source);
        }
    }

    static  Vector wrap(A[] arr) {
        Objects.requireNonNull(arr);
        if (arr.length == 0) {
            return empty();
        } else {
            return new WrappedArrayVector<>(arr);
        }
    }

    static  Vector wrap(List list) {
        Objects.requireNonNull(list);
        if (list.isEmpty()) {
            return empty();
        } else {
            return new WrappedListVector<>(list);
        }
    }

    static  Vector zipWith(Fn2 fn, Vector first, Vector second) {
        return second.toNonEmpty()., NonEmptyVector>>zip(first.toNonEmpty()
                .fmap(tupler()))
                .match(__ -> empty(),
                        into((ne1, ne2) -> nonEmptyZipWith(fn, ne1, ne2)));
    }

    static  Vector> zipWithIndex(Vector vec) {
        Objects.requireNonNull(vec);
        return zipWith(tupler(), vec, vec.indices());
    }

    private static  NonEmptyVector getNonEmptyOrThrow(Maybe> maybeResult) {
        return maybeResult.orElseThrow(Vectors.nonEmptyError());
    }

}