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

dev.marksman.collectionviews.Vector 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 dev.marksman.enhancediterables.FiniteIterable;
import dev.marksman.enhancediterables.ImmutableNonEmptyFiniteIterable;

import java.util.Iterator;
import java.util.List;
import java.util.RandomAccess;

import static com.jnape.palatable.lambda.adt.Maybe.*;
import static dev.marksman.collectionviews.EmptyVectorBuilder.emptyVectorBuilder;

/**
 * A finite, ordered view of a collection.
 * 

* A {@code Vector} guarantees the following: *

    *
  • A {@link Vector#size} method that executes in O(1)*. *
  • A {@link Vector#get} method that retrieves an element by index in O(1)*. *
  • An {@link Vector#isEmpty} method that executes in O(1)*. *
  • Iteration will always terminate. *
  • Protected from mutation by the bearer. *
  • The bearer cannot gain access to a reference to the underlying collection. *
*

* Additionally, the ability to transform the {@code Vector} to new {@code Vector}s, without * affecting or copying the underlying collection, is provided through the following methods: *

    *
  • {@link Vector#fmap} *
  • {@link Vector#take} *
  • {@link Vector#drop} *
  • {@link Vector#slice} *
*

* While {@code Vector} does implement {@link Iterable}, it does not implement {@link java.util.Collection}. * If you need to convert the {@code Vector} to a {@code java.util.Collection}, you will need to make a copy. * Consider using Lambda's {@code toCollection} function to accomplish this. *

* *The claim of O(1) means that the number of elements in the Vector has no bearing on performance. * However, the number of transformations applied to the Vector, such as mapping and slicing, will. * Technically, the complexity is O(k) where k is the number of transformations applied. * * @param the element type */ public interface Vector extends FiniteIterable, RandomAccess { /** * Returns the size of this {@code Vector}. *

* Executes in O(1). * * @return the number of elements in this {@code Vector} */ int size(); /** * Gets an element from this {@code Vector} at an index. *

* Executes in O(1). * * @param index the index of the element to retrieve. * Must be between 0 and size() - 1, otherwise will * throw an {@link IndexOutOfBoundsException} * @return the element at {@code index}. May be null, if the underlying data contains a null at that index. * @throws IndexOutOfBoundsException if index is less than 0 or greater than or equal to {@code size()} */ A unsafeGet(int index); /** * Returns the cartesian product of this {@code Vector} with another {@code Vector}. *

* Does not make copies of any underlying collections. *

* The returned {@link Vector} will have a size of {@code size()} × {@code other.size()}, * but will allocate no extra memory (aside from a few bytes for housekeeping). * * @param other a {@code Vector} of any type * @param the type of the other {@code Vector} * @return a {@code Vector>} */ default Vector> cross(Vector other) { return Vectors.cross(this, other); } /** * Returns a new {@code Vector} that drops the first {@code count} elements of this {@code Vector}. *

* Does not make copies of any underlying collections. *

* Use caution when taking a small slice of a huge {@code Vector} that you no longer need. * The smaller slice will hold onto a reference of the larger one, and will prevent it from being GC'ed. * * @param count the number of elements to drop from this {@code Vector}. * Must be >= 0. * May exceed size of this {@code Vector}, in which case, the result will be an * empty {@code Vector}. * @return a {@code Vector} */ @Override default Vector drop(int count) { return Vectors.drop(count, this); } /** * Returns a new {@code Vector} that drops all except the last {@code count} elements of this {@code Vector}. *

* Does not make copies of any underlying collections. *

* Use caution when taking a small slice of a huge {@code Vector} that you no longer need. * The smaller slice will hold onto a reference of the larger one, and will prevent it from being GC'ed. * * @param count the number of elements to drop from the end of this {@code Vector}. * Must be >= 0. * May exceed size of this {@code Vector}, in which case, the result will be an * empty {@code Vector}. * @return a {@code Vector} */ default Vector dropRight(int count) { return Vectors.dropRight(count, this); } /** * Finds the first element of this {@code Vector} that satisfies a predicate, if any, and returns its index. * * @param predicate a predicate; not null * @return an index wrapped in a {@link Maybe#just} if a matching element is found; * {@link Maybe#nothing} otherwise. */ default Maybe findIndex(Fn1 predicate) { return Vectors.findIndex(predicate, this); } /** * Maps a function over this {@code Vector}. *

* Returns a new {@link Vector} of the same size (but possibly a different type). *

* Does not make any copies of underlying collections. *

* This method is stack-safe, so a {@code Vector} can be mapped as many times as the heap permits. * * @param f a function from {@code A} to {@code B}. * 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 The type of the elements contained in the output Vector. * @return a {@code Vector} of the same size */ @Override default Vector fmap(Fn1 f) { return Vectors.map(f, this); } /** * Gets an element from this {@code Vector} at an index. *

* Executes in O(1). * Will never return null. * * @param index the index of the element to retrieve * @return an element wrapped in a {@link Maybe#just} if the index is in range and the element is not null. * {@link Maybe#nothing} otherwise. */ default Maybe get(int index) { if (index >= 0 && index < size()) { return maybe(unsafeGet(index)); } else { return nothing(); } } /** * Returns an {@code ImmutableVector} that contains all the indices of this {@code Vector}. * * @return an {@code ImmutableVector} */ default ImmutableVector indices() { return ImmutableVectors.indices(this); } /** * Returns a {@code NonEmptyIterable} containing the inits of this {@code Vector}. *

* The first value will be this {@code Vector} and the final one will be an empty {@code Vector}, * with the intervening values the results of successive applications of {@code init}. * * @return a {@code NonEmptyIterable} over all the inits of this {@code Vector} */ @Override default ImmutableNonEmptyFiniteIterable> inits() { return Vectors.inits(this); } /** * Tests whether this {@code Vector} is empty. *

* Executes in O(1). * * @return true if this {@code Vector} is empty, false otherwise. */ @Override default boolean isEmpty() { return size() == 0; } /** * Returns an iterator over this {@code Vector}'s elements. * * @return an Iterator */ @Override default Iterator iterator() { return VectorHelpers.vectorIterator(this); } /** * Creates a {@code Vector} with this {@code Vector}'s elements in reversed order. *

* Does not make copies of any underlying collections. * * @return a {@code Vector} */ @Override default Vector reverse() { return Vectors.reverse(this); } /** * Creates a slice of this {@code Vector}. *

* Does not make copies of any underlying collections. *

* Use caution when taking a small slice of a huge {@code Vector} that you no longer need. * The smaller slice will hold onto a reference of the larger one, and will prevent it from being GC'ed. * To avoid this situation, use {@link Vector#copySliceFrom} instead. * * @param startIndex the index of the element to begin the slice. * Must be >= 0. * May exceed the size of this {@code Vector}, in which case an empty {@code Vector} will be returned. * @param endIndexExclusive the end index (exclusive) of the slice. Must be >= {@code startIndex}. * May exceed the size of this {@code Vector}, in which case the slice will * contain as many elements as available. * @return a {@code Vector} */ default Vector slice(int startIndex, int endIndexExclusive) { return Vectors.slice(startIndex, endIndexExclusive, this); } /** * Splits this {@code Vector} into two at a given position. *

* Does not make copies of any underlying collections. *

* Note that vector.splitAt(n) is equivalent to, but possibly more efficient than * tuple(vector.take(n), vector.drop(n)) * * @param index the position at which to split. * Must be >= 0; * @return a {@code Tuple2} contains of {@code Vector}s, one of which containing the first {@code index} elements, * the second containing the other elements. */ default Tuple2, ? extends Vector> splitAt(int index) { return Vectors.splitAt(index, this); } /** * Returns a {@code NonEmptyIterable} containing the tails of this {@code Vector}. *

* The first value will be this {@code Vector} and the final one will be an empty {@code Vector}, * with the intervening values the results of successive applications of {@code tail}. * * @return a {@code NonEmptyIterable} over all the tails of this {@code Vector} */ @Override default ImmutableNonEmptyFiniteIterable> tails() { return Vectors.tails(this); } /** * Returns a new {@code Vector} containing at most the first {@code count} elements of this {@code Vector}. *

* Does not make copies of any underlying collections. *

* Use caution when taking a small slice of a huge {@link Vector} that you no longer need. * The smaller slice will hold onto a reference of the larger one, and will prevent it from being GC'ed. * To avoid this situation, use {@link Vector#copyFrom(int, Iterable)} instead. * * @param count the maximum number of elements to take from this {@code Vector}. * Must be >= 0. * May exceed size of this {@code Vector}. * @return a {@code Vector} */ @Override default Vector take(int count) { return Vectors.take(count, this); } /** * Returns a new {@code Vector} containing at most the last {@code count} elements of this {@code Vector}. *

* Does not make copies of any underlying collections. *

* Use caution when taking a small slice of a huge {@link Vector} that you no longer need. * The smaller slice will hold onto a reference of the larger one, and will prevent it from being GC'ed. * To avoid this situation, use {@link Vector#copyFrom(int, Iterable)} instead. * * @param count the maximum number of elements to take from this {@code Vector}. * Must be >= 0. * May exceed size of this {@code Vector}. * @return a {@code Vector} */ default Vector takeRight(int count) { return Vectors.takeRight(count, this); } /** * Converts this {@code Vector} to an {@code ImmutableVector}. *

* This method will make a copy of the underlying data structure if necessary to guarantee immutability. *

* If this {@link Vector} is already an {@link ImmutableVector}, no copies are made and this method is a no-op. * * @return an {@code ImmutableVector} of the same type and containing the same elements */ default ImmutableVector toImmutable() { return ImmutableVectors.ensureImmutable(this); } /** * Attempts to convert this {@code Vector} to a {@code NonEmptyVector}. *

* If successful, returns a {@link NonEmptyVector} containing the same elements as this one, wrapped in a {@link Maybe#just}. *

* If this {@code Vector} is empty, returns {@link Maybe#nothing}. *

* Does not make copies of any underlying collections. * * @return a {@code Maybe>} */ @Override default Maybe> toNonEmpty() { return Vectors.maybeNonEmptyWrap(this); } /** * Attempts to convert this {@code Vector} to a {@code NonEmptyVector}. *

* If successful, returns a {@link NonEmptyVector} containing the same elements as this one. * Use this if you are confident that this {@link Vector} is not empty. *

* If this {@code Vector} is empty, throws an {@link IllegalArgumentException}. *

* Does not make copies of any underlying collections. * * @return a {@code NonEmptyVector} * @throws IllegalArgumentException if this {@code Vector} is empty */ default NonEmptyVector toNonEmptyOrThrow() { return Vectors.nonEmptyWrapOrThrow(this); } /** * Zips together this {@code Vector} with another {@code Vector} by applying a zipping function. *

* Applies the function to the successive elements of of each {@code Vector} until one of them runs out of elements. *

* Does not make copies of any underlying collections. * * @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 Vector} * @param The element type of the other {@code Vector} * @param The element type of the result * @return A {@code Vector} */ default Vector zipWith(Fn2 fn, Vector other) { return Vectors.zipWith(fn, this, other); } /** * Zips this {@code Vector} with its indices. *

* Does not make copies of any underlying collections. * * @return a new {@code Vector} containing pairs consisting of all elements of this {@code Vector} paired with their index. * Indices start at 0. */ default Vector> zipWithIndex() { return Vectors.zipWithIndex(this); } /** * Returns an empty {@code ImmutableVector}. * * @param the element type * @return an empty {@code ImmutableVector} */ static ImmutableVector empty() { return Vectors.empty(); } /** * Creates a {@code ImmutableNonEmptyVector} with the given elements. * * @param first the first element * @param more the remaining elements * @param the element type * @return an {@code ImmutableNonEmptyVector} */ @SuppressWarnings("varargs") @SafeVarargs static ImmutableNonEmptyVector of(A first, A... more) { return Vectors.nonEmptyVectorOf(first, more); } /** * Creates a new {@code VectorBuilder}. * * @param the element type * @return an empty {@link VectorBuilder} */ static VectorBuilder builder() { return emptyVectorBuilder(nothing()); } /** * Creates a new {@code VectorBuilder} with an initial capacity hint. * * @param initialCapacity an initial capacity hint. * Must be >= 0. * @param the element type * @return an empty {@link VectorBuilder} */ static VectorBuilder builder(int initialCapacity) { return emptyVectorBuilder(just(initialCapacity)); } /** * Creates an {@code ImmutableVector} that repeats the same element {@code size} times. *

* Uses O(1) memory. *

* See {@link NonEmptyVector#fill} if you require an {@link ImmutableNonEmptyVector} to be returned. * * @param size the number of elements. * Must be >= 0. * @param value the value that will be repeated for all elements of the {@code ImmutableVector} * @param the element type * @return an {@code ImmutableVector} of {@code size} elements, with each element having * the value {@code value} */ static ImmutableVector fill(int size, A value) { return ImmutableVectors.fill(size, value); } /** * Creates an {@code ImmutableVector} where elements are lazily evaluated. *

* Uses O(1) memory. *

* See {@link NonEmptyVector#lazyFill} if you require a {@link ImmutableNonEmptyVector} to be returned. * * @param size the number of elements. * Must be >= 0. * @param valueSupplier a function that accepts an index and returns the computed value for that index. * 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 the element type * @return an {@code ImmutableVector} */ static ImmutableVector lazyFill(int size, Fn1 valueSupplier) { return ImmutableVectors.lazyFill(size, valueSupplier); } /** * Creates an {@code ImmutableVector} containing elements 0..size - 1. * In other words, each element of the returned {@code Vector} will contains its index. *

* Uses O(1) memory. * * @param size the number of elements. * Must be >= 0. * If 0, the returned {@code ImmutableVector} will be empty. * @return an {@code ImmutableVector} */ static ImmutableVector range(int size) { return ImmutableVectors.range(size); } /** * Creates a {@code Vector} that wraps an array. *

* Does not make any copies of the given array. * The created {@link Vector} will hold on to a reference to the array, but will never alter it in any way. *

* Bearers of the created {@code Vector} will be unable to gain access to the underlying array, so it is safe to share. *

* Since no copy is made, be aware that anyone that holds a direct reference to the array can still mutate it. * Use {@link Vector#copyFrom} instead if you want to avoid this situation. * * @param underlying array to wrap; not null * @param the element type * @return a {@code Vector} */ static Vector wrap(A[] underlying) { return Vectors.wrap(underlying); } /** * Creates a {@code Vector} that wraps a {@code java.util.List}. *

* Does not make any copies of the given {@link java.util.List}. * The created {@link Vector} will hold a reference to the given {@code List}, but will not alter it in any way. *

* Bearers of the created {@code Vector} will be unable to gain access to the underlying {@code List}, so it is safe to share. *

* Since no copy is made, be aware that anyone that holds a direct reference to the {@code List} can still mutate it. * Mutating the {@code List} is not advised. * Operations that change the size of the underlying {@code List} will result in unpredictable behavior. * Use {@link Vector#copyFrom} if you want to avoid this situation. * * @param underlying {@code List} to wrap; not null * @param the element type * @return a {@code Vector} */ static Vector wrap(List underlying) { return Vectors.wrap(underlying); } /** * Creates an {@code ImmutableVector} that is copied from any {@code Iterable}. *

* The entire {@link Iterable} will be eagerly iterated. * Be careful not to pass in an infinite {@code Iterable} or this method will not terminate. *

* If necessary to guarantee immutability, this method will make a copy of the data provided. * If {@code source} is an untransformed {@link ImmutableVector}, it will be returned directly. * * @param source an {@code Iterable} that will be iterated eagerly in its entirety; not null * @param the element type * @return an {@code ImmutableVector} */ static ImmutableVector copyFrom(Iterable source) { return ImmutableVectors.copyFrom(source); } /** * Creates an {@code ImmutableVector} that is copied from an array. * * @param source the array to copy from. * Not null. * This method will not alter or hold on to a reference of this array. * @param the element type * @return an {@code ImmutableVector} */ static ImmutableVector copyFrom(A[] source) { return ImmutableVectors.copyFrom(source); } /** * Creates an {@code ImmutableVector} that is copied from any {@code Iterable}, but consuming a maximum number of elements. *

* The {@link Iterable} will be eagerly iterated, but only up to a maximum of {@code maxCount} elements. * If {@code maxCount} elements are not available, then the all of the elements available will be returned. *

* This method will make a copy of the data provided, unless {@code source} is * an untransformed {@link ImmutableVector} and its size is less than or equal to {@code maxCount}, * in which case it will be returned directly. *

* If {@code source} is an {@code ImmutableVector} that is greater than {@code maxCount} in size, * a copy will always be made, therefore making it memory-safe to take a small slice of * a huge {@link Vector} that you no longer need. * * @param maxCount the maximum number of elements to consume from the source. * Must be >= 0. * @param source an {@code Iterable} that will be iterated eagerly for up to {@code maxCount} elements. * Not null. * It is safe for {@code source} to be infinite. * @param the element type * @return an {@code ImmutableVector} that contains at most {@code maxCount} elements */ static ImmutableVector copyFrom(int maxCount, Iterable source) { return ImmutableVectors.copyFrom(maxCount, source); } /** * Returns a new {@code ImmutableVector} that is copied from an array. * * @param maxCount the maximum number of elements to copy from the array. * Must be >= 0. * @param source the array to copy from. * Not null. * This method will not alter or hold on to a reference of this array. * @param the element type * @return an {@code ImmutableVector} */ static ImmutableVector copyFrom(int maxCount, A[] source) { return ImmutableVectors.copyFrom(maxCount, source); } /** * Creates an {@code ImmutableVector} by copying a slice from an {@code Iterable}. *

* The {@link Iterable} will be eagerly iterated, but only for the number of elements needed to fulfill the requested slice. * If not enough elements are not available, then this method yields as many elements that were available. *

* This method will make a copy of the data provided, except in the case {@code startIndex} is 0 * and {@code source} is an {@link ImmutableVector} whose size is less than or equal to {@code count}, * in which case it will be returned directly. *

* It is memory-safe to use this method to take a small slice of a huge {@link Vector} that you no longer need. * * @param startIndex the index of the element to begin the slice. * Must be >= 0. * May exceed the size of the {@link Iterable}. * @param endIndexExclusive the end index (exclusive) of the slice. * Must be >= {@code startIndex}. * May exceed the size of the {@link Iterable}. * @param source an {@code Iterable} that will be iterated eagerly for up to {@code endIndexExclusive} elements. * Not null. * It is safe for {@code source} to be infinite. * @param the element type * @return an {@code ImmutableVector} */ static ImmutableVector copySliceFrom(int startIndex, int endIndexExclusive, Iterable source) { return ImmutableVectors.copySliceFrom(startIndex, endIndexExclusive, source); } }