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

dev.marksman.collectionviews.ImmutableVectors 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.Fn1;
import com.jnape.palatable.lambda.functions.Fn2;
import com.jnape.palatable.lambda.functions.builtin.fn2.Take;
import dev.marksman.enhancediterables.ImmutableNonEmptyFiniteIterable;

import java.util.ArrayList;
import java.util.Arrays;
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.fn1.Id.id;
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.ImmutableCrossJoinVector.immutableCrossJoinVector;
import static dev.marksman.collectionviews.ImmutableReverseVector.immutableReverseVector;
import static dev.marksman.collectionviews.ImmutableVectorZip.immutableVectorZip;
import static dev.marksman.collectionviews.MapperChain.mapperChain;
import static dev.marksman.collectionviews.Validation.*;
import static dev.marksman.collectionviews.Vector.empty;
import static dev.marksman.collectionviews.VectorSlicing.sliceImpl;

final class ImmutableVectors {

    private ImmutableVectors() {

    }

    static  ImmutableVector copyFrom(A[] source) {
        Objects.requireNonNull(source);
        return copyFrom(source.length, source);
    }

    static  ImmutableVector copyFrom(int maxCount, A[] source) {
        validateCopyFrom(maxCount, source);
        int count = Math.min(maxCount, source.length);
        A[] copied = Arrays.copyOf(source, count);
        return wrapAndVouchFor(copied);
    }

    static  ImmutableVector copyFrom(Iterable source) {
        Objects.requireNonNull(source);
        if (source instanceof ImmutableVector && Util.isPrimitive(source)) {
            return (ImmutableVector) source;
        } else if (!source.iterator().hasNext()) {
            return Vectors.empty();
        } else {
            ArrayList copied = toCollection(ArrayList::new, source);
            return wrapAndVouchFor(copied);
        }
    }

    static  ImmutableVector copyFrom(int maxCount, Iterable source) {
        validateCopyFrom(maxCount, source);
        if (maxCount == 0) {
            return Vectors.empty();
        }
        if (source instanceof ImmutableVector && Util.isPrimitive(source)) {
            return ((ImmutableVector) source).take(maxCount);
        } else {
            return copyFrom(Take.take(maxCount, source));
        }
    }

    static  ImmutableVector copySliceFrom(int startIndex, int endIndexExclusive, Iterable source) {
        validateSlice(startIndex, endIndexExclusive, source);
        if (source instanceof ImmutableVector && Util.isPrimitive(source)) {
            return ((ImmutableVector) source).slice(startIndex, endIndexExclusive);
        } else {
            return Vectors.sliceFromIterable(startIndex, endIndexExclusive, source).toImmutable();
        }
    }

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

    static  ImmutableVector drop(int count, ImmutableVector source) {
        return VectorSlicing.dropImpl(ImmutableVectorSlice::immutableVectorSlice, count, source);
    }

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

    static  ImmutableVector dropWhile(Fn1 predicate, ImmutableVector source) {
        Objects.requireNonNull(predicate);
        Objects.requireNonNull(source);
        return drop(Vectors.findPrefixLength(predicate, source), source);
    }

    static  ImmutableVector ensureImmutable(Vector vector) {
        if (vector instanceof ImmutableVector) {
            return (ImmutableVector) vector;
        } else if (vector.isEmpty()) {
            return Vectors.empty();
        } else {
            ArrayList copied = toCollection(ArrayList::new, vector);
            return wrapAndVouchFor(copied);
        }
    }

    static  ImmutableNonEmptyVector ensureImmutable(NonEmptyVector vector) {
        if (vector instanceof ImmutableNonEmptyVector) {
            return (ImmutableNonEmptyVector) vector;
        } else {
            ArrayList copied = toCollection(ArrayList::new, vector);
            return new ImmutableListVector<>(copied);
        }
    }

    static  ImmutableVector fill(int size, A value) {
        validateFill(size);
        if (size == 0) {
            return Vectors.empty();
        } else {
            return nonEmptyFill(size, value);
        }
    }

    static  ImmutableVector indices(Vector vec) {
        return range(vec.size());
    }

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

    static  ImmutableVector lazyFill(int size, Fn1 valueSupplier) {
        validateFill(size);
        Objects.requireNonNull(valueSupplier);
        if (size == 0) {
            return Vectors.empty();
        } else {
            return nonEmptyLazyFill(size, valueSupplier);
        }
    }

    static  ImmutableVector> magnetizeBy(Fn2 predicate, ImmutableVector source) {
        Objects.requireNonNull(predicate);
        return source.toNonEmpty().match(__ -> Vectors.empty(),
                ne -> nonEmptyMagnetizeBy(predicate, ne));
    }

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

    static  Maybe> maybeNonEmptyConvert(ImmutableVector vec) {
        Objects.requireNonNull(vec);
        if (vec instanceof ImmutableNonEmptyVector) {
            return just((ImmutableNonEmptyVector) vec);
        } else if (!vec.isEmpty()) {
            return just(new ImmutableVectorCons<>(vec.unsafeGet(0), vec.drop(1)));
        } else {
            return nothing();
        }
    }

    @SuppressWarnings("unchecked")
    static  Maybe> maybeNonEmptyCopyFrom(A[] arr) {
        Objects.requireNonNull(arr);
        if (arr.length == 0) {
            return nothing();
        } else {
            return (Maybe>) copyFrom(arr).toNonEmpty();
        }
    }

    @SuppressWarnings("unchecked")
    static  Maybe> maybeNonEmptyCopyFrom(int maxCount, A[] arr) {
        validateCopyFrom(maxCount, arr);
        if (arr.length == 0 || maxCount == 0) {
            return nothing();
        } else {
            return (Maybe>) copyFrom(maxCount, arr).toNonEmpty();
        }
    }

    @SuppressWarnings("unchecked")
    static  Maybe> maybeNonEmptyCopyFrom(Iterable source) {
        Objects.requireNonNull(source);
        if (!source.iterator().hasNext()) {
            return nothing();
        }
        return (Maybe>) copyFrom(source).toNonEmpty();
    }

    @SuppressWarnings("unchecked")
    static  Maybe> maybeNonEmptyCopyFrom(int maxCount, Iterable source) {
        validateCopyFrom(maxCount, source);
        if (maxCount == 0) {
            return nothing();
        }
        if (!source.iterator().hasNext()) {
            return nothing();
        }
        return (Maybe>) copyFrom(maxCount, source).toNonEmpty();
    }

    static  ImmutableNonEmptyVector nonEmptyConvertOrThrow(ImmutableVector source) {
        return getNonEmptyOrThrow(maybeNonEmptyConvert(source));
    }

    static  ImmutableNonEmptyVector nonEmptyCopyFromOrThrow(Iterable source) {
        return getNonEmptyOrThrow(maybeNonEmptyCopyFrom(source));
    }

    static  ImmutableNonEmptyVector nonEmptyCopyFromOrThrow(int maxCount, Iterable source) {
        return getNonEmptyOrThrow(maybeNonEmptyCopyFrom(maxCount, source));
    }

    static  ImmutableNonEmptyVector nonEmptyCopyFromOrThrow(A[] source) {
        return getNonEmptyOrThrow(maybeNonEmptyCopyFrom(source));
    }

    static  ImmutableNonEmptyVector nonEmptyCopyFromOrThrow(int maxCount, A[] source) {
        return getNonEmptyOrThrow(maybeNonEmptyCopyFrom(maxCount, source));
    }

    static  ImmutableNonEmptyVector> nonEmptyCross(ImmutableNonEmptyVector first, ImmutableNonEmptyVector second) {
        return immutableCrossJoinVector(first, second);
    }

    static  ImmutableNonEmptyVector nonEmptyFill(int size, A value) {
        validateNonEmptyFill(size);
        return new RepeatingVector<>(size, value);
    }

    static  ImmutableNonEmptyVector nonEmptyIndices(NonEmptyVector vec) {
        return nonEmptyRange(vec.size());
    }

    static  ImmutableNonEmptyVector nonEmptyLazyFill(int size, Fn1 valueSupplier) {
        validateNonEmptyFill(size);
        return new LazyVector<>(size, 0, valueSupplier);
    }

    static  ImmutableNonEmptyVector> nonEmptyMagnetizeBy(Fn2 predicate, ImmutableNonEmptyVector source) {
        Objects.requireNonNull(predicate);
        int size = source.size();
        VectorBuilder> builder = Vector.builder();
        int index = 0;
        while (index < size) {
            Tuple2, Integer> next = magnetizeAt(predicate, index, source);
            builder = builder.add(next._1());
            index = next._2();
        }
        return builder.build().toNonEmptyOrThrow();
    }

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


    static ImmutableNonEmptyVector nonEmptyRange(int size) {
        if (size < 0) {
            throw new IllegalArgumentException("size must be >= 1");
        }
        return nonEmptyLazyFill(size, id());
    }

    static  ImmutableNonEmptyVector nonEmptyReverse(ImmutableNonEmptyVector vec) {
        if (vec.size() < 2) {
            return vec;
        } else {
            return immutableReverseVector(vec);
        }
    }

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

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

    static  ImmutableVector reverse(ImmutableVector vec) {
        if (vec.size() < 2) {
            return vec;
        } else {
            return immutableReverseVector(vec.toNonEmptyOrThrow());
        }
    }

    static ImmutableVector range(int size) {
        if (size < 0) {
            throw new IllegalArgumentException("size must be >= 0");
        }
        return lazyFill(size, id());
    }

    static  ImmutableVector slice(int startIndex, int endIndexExclusive, ImmutableVector source) {
        validateSlice(startIndex, endIndexExclusive, source);
        int requestedSize = endIndexExclusive - startIndex;
        if (requestedSize < 1) {
            return Vectors.empty();
        } else {
            return sliceImpl(ImmutableVectorSlice::immutableVectorSlice, source.size(), () -> source,
                    startIndex, requestedSize);
        }
    }

    static  Tuple2, ImmutableVector> span
            (Fn1 predicate, ImmutableVector source) {
        Objects.requireNonNull(predicate);
        Objects.requireNonNull(source);
        return splitAt(Vectors.findPrefixLength(predicate, source), source);
    }

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

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

    static  ImmutableVector take(int count, ImmutableVector source) {
        validateTake(count, source);
        return slice(0, count, source);
    }

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

    static  ImmutableVector takeWhile(Fn1 predicate, ImmutableVector source) {
        Objects.requireNonNull(predicate);
        Objects.requireNonNull(source);
        return take(Vectors.findPrefixLength(predicate, source), source);
    }

    static  ImmutableVector wrapAndVouchFor(A[] arr) {
        Objects.requireNonNull(arr);
        if (arr.length == 0) {
            return Vectors.empty();
        } else {
            return new ImmutableArrayVector<>(arr);
        }
    }

    static  ImmutableVector wrapAndVouchFor(List list) {
        Objects.requireNonNull(list);
        if (list.isEmpty()) {
            return Vectors.empty();
        } else {
            return new ImmutableListVector<>(list);
        }
    }

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

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

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

    private static  Tuple2, Integer> magnetizeAt(Fn2 predicate, int index, ImmutableVector source) {
        int maxIndex = source.size() - 1;
        int firstIndex = index;
        while (index < maxIndex && predicate.apply(source.unsafeGet(index), source.unsafeGet(index + 1))) {
            index += 1;
        }
        int nextIndex = index + 1;
        return tuple(slice(firstIndex, nextIndex, source).toNonEmptyOrThrow(), nextIndex);
    }

}