package fj.data;
import fj.Equal;
import fj.F;
import fj.F0;
import fj.F2;
import fj.Hash;
import fj.P;
import fj.P2;
import fj.Show;
import fj.Unit;
import fj.function.Effect1;
import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.NoSuchElementException;
import static fj.Function.constant;
import static fj.Function.curry;
import static fj.Function.identity;
import static fj.P.p;
import static fj.P.p2;
import static fj.Unit.unit;
import static fj.data.List.iterableList;
import static fj.data.Option.none;
import static fj.data.Option.some;
import static java.lang.Math.min;
import static java.lang.System.arraycopy;
/**
* Provides an interface to arrays.
*
* @version %build.number%
*/
public final class Array<A> implements Iterable<A> {
private final Object[] a;
private Array(final Object[] a) {
this.a = a;
}
/**
* Returns an iterator for this array. This method exists to permit the use in a <code>for</code>-each loop.
*
* @return A iterator for this array.
*/
public Iterator<A> iterator() {
return toCollection().iterator();
}
/**
* Returns the element at the given index if it exists, fails otherwise.
*
* @param index The index at which to get the element to return.
* @return The element at the given index if it exists, fails otherwise.
*/
@SuppressWarnings("unchecked")
public A get(final int index) {
return (A) a[index];
}
@Override
public int hashCode() {
return Hash.arrayHash(Hash.<A>anyHash()).hash(this);
}
/**
* Sets the element at the given index to the given value.
*
* @param index The index at which to set the given value.
* @param a The value to set at the given index.
* @return The unit value.
*/
public Unit set(final int index, final A a) {
this.a[index] = a;
return unit();
}
/**
* Returns the length of this array.
*
* @return The length of this array.
*/
public int length() {
return a.length;
}
public ImmutableProjection<A> immutable() {
return new ImmutableProjection<>(this);
}
/**
* Returns <code>true</code> is this array is empty, <code>false</code> otherwise.
*
* @return <code>true</code> is this array is empty, <code>false</code> otherwise.
*/
public boolean isEmpty() {
return a.length == 0;
}
/**
* Returns <code>false</code> is this array is empty, <code>true</code> otherwise.
*
* @return <code>false</code> is this array is empty, <code>true</code> otherwise.
*/
public boolean isNotEmpty() {
return a.length != 0;
}
/**
* Returns a copy of the underlying primitive array.
*
* @param c A class for the returned array.
* @return A copy of the underlying primitive array.
*/
public A[] array(final Class<A[]> c) {
return copyOf(a, a.length, c);
}
/**
* Returns a copy of the underlying primitive array.
*
* @return A copy of the underlying primitive array;
*/
public Object[] array() {
return copyOf(a, a.length);
}
/**
* To be removed in future release:
* affectation of the result of this method to a non generic array
* will result in runtime error (ClassCastException).
*
* @deprecated As of release 4.6, use {@link #array(Class)}.
*/
@SuppressWarnings("unchecked")
@Deprecated
public A[] toJavaArray() {
return (A[]) array();
}
/**
* Returns an option projection of this array; <code>None</code> if empty, or the first element in
* <code>Some</code>.
*
* @return An option projection of this array.
*/
@SuppressWarnings("unchecked")
public Option<A> toOption() {
return a.length == 0 ? Option.none() : some((A) a[0]);
}
/**
* Returns an either projection of this array; the given argument in <code>Left</code> if empty,
* or the first element in <code>Right</code>.
*
* @param x The value to return in left if this array is empty.
* @return An either projection of this array.
*/
@SuppressWarnings("unchecked")
public <X> Either<X, A> toEither(final F0<X> x) {
return a.length == 0 ? Either.left(x.f()) : Either.right((A) a[0]);
}
/**
* Returns a list projection of this array.
*
* @return A list projection of this array.
*/
@SuppressWarnings("unchecked")
public List<A> toList() {
List<A> x = List.nil();
for (int i = a.length - 1; i >= 0; i--) {
x = x.cons((A) a[i]);
}
return x;
}
/**
* Returns a stream projection of this array.
*
* @return A stream projection of this array.
*/
@SuppressWarnings("unchecked")
public Stream<A> toStream() {
return Stream.unfold(o ->
a.length > o ? some(p((A) a[o], o + 1)) : Option.none(), 0
);
}
@Override
public String toString() {
return Show.arrayShow(Show.<A>anyShow()).showS(this);
}
/**
* Maps the given function across this array.
*
* @param f The function to map across this array.
* @return A new array after the given function has been applied to each element.
*/
@SuppressWarnings("unchecked")
public <B> Array<B> map(final F<A, B> f) {
final Object[] bs = new Object[a.length];
for (int i = 0; i < a.length; i++) {
bs[i] = f.f((A) a[i]);
}
return new Array<>(bs);
}
/**
* Filters elements from this array by returning only elements which produce <code>true</code>
* when the given function is applied to them.
*
* @param f The predicate function to filter on.
* @return A new array whose elements all match the given predicate.
*/
@SuppressWarnings("unchecked")
public Array<A> filter(final F<A, Boolean> f) {
List<A> x = List.nil();
for (int i = a.length - 1; i >= 0; i--) {
if (f.f((A) a[i]))
x = x.cons((A) a[i]);
}
return x.toArray();
}
/**
* Performs a side-effect for each element of this array.
*
* @param f The side-effect to perform for the given element.
* @return The unit value.
*/
@SuppressWarnings("unchecked")
public Unit foreach(final F<A, Unit> f) {
for (final Object x : a) {
f.f((A) x);
}
return unit();
}
/**
* Performs a side-effect for each element of this array.
*
* @param f The side-effect to perform for the given element.
*/
@SuppressWarnings("unchecked")
public void foreachDoEffect(final Effect1<A> f) {
for (final Object x : a) {
f.f((A) x);
}
}
/**
* Performs a right-fold reduction across this array. This function runs in constant stack space.
*
* @param f The function to apply on each element of the array.
* @param b The beginning value to start the application from.
* @return The final result after the right-fold reduction.
*/
@SuppressWarnings("unchecked")
public <B> B foldRight(final F<A, F<B, B>> f, final B b) {
B x = b;
for (int i = a.length - 1; i >= 0; i--)
x = f.f((A) a[i]).f(x);
return x;
}
/**
* Performs a right-fold reduction across this array. This function runs in constant stack space.
*
* @param f The function to apply on each element of the array.
* @param b The beginning value to start the application from.
* @return The final result after the right-fold reduction.
*/
public <B> B foldRight(final F2<A, B, B> f, final B b) {
return foldRight(curry(f), b);
}
/**
* Performs a left-fold reduction across this array. This function runs in constant space.
*
* @param f The function to apply on each element of the array.
* @param b The beginning value to start the application from.
* @return The final result after the left-fold reduction.
*/
@SuppressWarnings("unchecked")
public <B> B foldLeft(final F<B, F<A, B>> f, final B b) {
B x = b;
for (final Object aa : a)
x = f.f(x).f((A) aa);
return x;
}
/**
* Performs a left-fold reduction across this array. This function runs in constant space.
*
* @param f The function to apply on each element of the array.
* @param b The beginning value to start the application from.
* @return The final result after the left-fold reduction.
*/
public <B> B foldLeft(final F2<B, A, B> f, final B b) {
return foldLeft(curry(f), b);
}
/**
* Performs a fold left accummulating and returns an array of the intermediate results.
* This function runs in constant stack space.
*
* @param f The function to apply on each argument pair (initial value/previous result and next array element)
* @param b The beginning value to start the application from.
* @return The array containing all intermediate results of the left-fold reduction.
*/
@SuppressWarnings("unchecked")
public <B> Array<B> scanLeft(final F<B, F<A, B>> f, final B b) {
final Object[] bs = new Object[a.length];
B x = b;
for (int i = 0; i < a.length; i++) {
x = f.f(x).f((A) a[i]);
bs[i] = x;
}
return new Array<>(bs);
}
/**
* Performs a left-fold accummulating and returns an array of the intermediate results.
* This function runs in constant stack space.
*
* @param f The function to apply on each argument pair (initial value/previous result and next array element)
* @param b The beginning value to start the application from.
* @return The array containing all intermediate results of the left-fold reduction.
*/
public <B> Array<B> scanLeft(final F2<B, A, B> f, final B b) {
return scanLeft(curry(f), b);
}
/**
* Performs a left-fold accummulating using first array element as a starting value
* and returns an array of the intermediate results.
* It will fail for empty arrays.
* This function runs in constant stack space.
*
* @param f The function to apply on each argument pair (next array element and first array element/previous result)
* @return The array containing all intermediate results of the left-fold reduction.
*/
@SuppressWarnings("unchecked")
public Array<A> scanLeft1(final F<A, F<A, A>> f) {
final Object[] bs = new Object[a.length];
A x = get(0);
bs[0] = x;
for (int i = 1; i < a.length; i++) {
x = f.f(x).f((A) a[i]);
bs[i] = x;
}
return new Array<>(bs);
}
/**
* Performs a left-fold accummulating using first array element as a starting value
* and returns an array of the intermediate results.
* It will fail for empty arrays.
* This function runs in constant stack space.
*
* @param f The function to apply on each argument pair (next array element and first array element/previous result)
* @return The array containing all intermediate results of the left-fold reduction.
*/
public Array<A> scanLeft1(final F2<A, A, A> f) {
return scanLeft1(curry(f));
}
/**
* Performs a right-fold accummulating and returns an array of the intermediate results.
* This function runs in constant stack space.
*
* @param f The function to apply on each argument pair (previous array element and initial value/previous result)
* @param b The beginning value to start the application from.
* @return The array containing all intermediate results of the right-fold reduction.
*/
@SuppressWarnings("unchecked")
public <B> Array<B> scanRight(final F<A, F<B, B>>f, final B b) {
final Object[] bs = new Object[a.length];
B x = b;
for (int i = a.length - 1; i >= 0; i--) {
x = f.f((A) a[i]).f(x);
bs[i] = x;
}
return new Array<>(bs);
}
/**
* Performs a right-fold accummulating and returns an array of the intermediate results.
* This function runs in constant stack space.
*
* @param f The function to apply on each argument pair (previous array element and initial value/previous result)
* @param b The beginning value to start the application from.
* @return The array containing all intermediate results of the right-fold reduction.
*/
public <B> Array<B> scanRight(final F2<A, B, B> f, final B b) {
return scanRight(curry(f), b);
}
/**
* Performs a right-fold accummulating using last array element as a starting value
* and returns an array of the intermediate results.
* It will fail for empty arrays.
* This function runs in constant stack space.
*
* @param f The function to apply on each argument pair (previous array element and last array element/previous result)
* @return The array containing all intermediate results of the right-fold reduction.
*/
@SuppressWarnings("unchecked")
public Array<A> scanRight1(final F<A, F<A, A>>f) {
final Object[] bs = new Object[a.length];
A x = get(length() - 1);
bs[length() - 1] = x;
for (int i = a.length - 2; i >= 0; i--) {
x = f.f((A) a[i]).f(x);
bs[i] = x;
}
return new Array<>(bs);
}
/**
* Performs a right-fold accummulating using last array element as a starting value
* and returns an array of the intermediate results.
* It will fail for empty arrays.
* This function runs in constant stack space.
*
* @param f The function to apply on each argument pair (previous array element and last array element/previous result)
* @return The array containing all intermediate results of the right-fold reduction.
*/
public Array<A> scanRight1(final F2<A, A, A> f) {
return scanRight1(curry(f));
}
/**
* Binds the given function across each element of this array with a final join.
*
* @param f The function to apply to each element of this array.
* @return A new array after performing the map, then final join.
*/
@SuppressWarnings("unchecked")
public <B> Array<B> bind(final F<A, Array<B>> f) {
List<Array<B>> x = List.nil();
int len = 0;
for (int i = a.length - 1; i >= 0; i--) {
final Array<B> bs = f.f((A) a[i]);
len = len + bs.length();
x = x.cons(bs);
}
final Object[] bs = new Object[len];
x.foreach(new F<Array<B>, Unit>() {
private int i;
public Unit f(final Array<B> x) {
arraycopy(x.a, 0, bs, i, x.a.length);
i = i + x.a.length;
return unit();
}
});
return new Array<>(bs);
}
/**
* Performs a bind across each array element, but ignores the element value each time.
*
* @param bs The array to apply in the final join.
* @return A new array after the final join.
*/
public <B> Array<B> sequence(final Array<B> bs) {
final F<A, Array<B>> c = constant(bs);
return bind(c);
}
/**
* Binds the given function across each element of this array and the given array with a final
* join.
*
* @param sb A given array to bind the given function with.
* @param f The function to apply to each element of this array and the given array.
* @return A new array after performing the map, then final join.
*/
public <B, C> Array<C> bind(final Array<B> sb, final F<A, F<B, C>> f) {
return sb.apply(map(f));
}
/**
* Binds the given function across each element of this array and the given array with a final
* join.
*
* @param sb A given array to bind the given function with.
* @param f The function to apply to each element of this array and the given array.
* @return A new array after performing the map, then final join.
*/
public <B, C> Array<C> bind(final Array<B> sb, final F2<A, B, C> f) {
return bind(sb, curry(f));
}
/**
* Performs function application within an array (applicative functor pattern).
*
* @param lf The array of functions to apply.
* @return A new array after applying the given array of functions through this array.
*/
public <B> Array<B> apply(final Array<F<A, B>> lf) {
return lf.bind(f -> map(f));
}
/**
* Reverse this array in constant stack space.
*
* @return A new array that is the reverse of this one.
*/
public Array<A> reverse() {
final Object[] x = new Object[a.length];
for (int i = 0; i < a.length; i++) {
x[a.length - 1 - i] = a[i];
}
return new Array<>(x);
}
/**
* Appends the given array to this array.
*
* @param aas The array to append to this one.
* @return A new array that has appended the given array.
*/
public Array<A> append(final Array<A> aas) {
final Object[] x = new Object[a.length + aas.a.length];
arraycopy(a, 0, x, 0, a.length);
arraycopy(aas.a, 0, x, a.length, aas.a.length);
return new Array<>(x);
}
/**
* Returns an empty array.
*
* @return An empty array.
*/
public static <A> Array<A> empty() {
return new Array<>(new Object[0]);
}
/**
* Constructs an array from the given elements.
*
* @param as The elements to construct the array with.
* @return A new array of the given elements.
*/
@SafeVarargs
public static <A> Array<A> array(final A...as) {
return arrayArray(as);
}
/**
* Unsafe package-private constructor. The elements of the given array must be assignable to the given type.
*
* @param a An array with elements of the given type.
* @return A wrapped array.
*/
static <A> Array<A> mkArray(final Object[] a) {
return new Array<>(a);
}
/**
* Constructs a singleton array.
*
* @param a The element to put in the array.
* @return An array with the given single element.
*/
public static <A> Array<A> single(final A a) {
return new Array<>(new Object[]{a});
}
/**
* First-class wrapper function for arrays.
*
* @return A function that wraps a given array.
*/
public static <A> F<A[], Array<A>> wrap() {
return Array::array;
}
/**
* First-class map function for Arrays.
*
* @return A function that maps a given function across a given array.
*/
public static <A, B> F<F<A, B>, F<Array<A>, Array<B>>> map() {
return curry((abf, array) -> array.map(abf));
}
/**
* Joins the given array of arrays using a bind operation.
*
* @param o The array of arrays to join.
* @return A new array that is the join of the given arrays.
*/
public static <A> Array<A> join(final Array<Array<A>> o) {
final F<Array<A>, Array<A>> id = identity();
return o.bind(id);
}
/**
* A first-class version of join
*
* @return A function that joins a array of arrays using a bind operation.
*/
public static <A> F<Array<Array<A>>, Array<A>> join() {
return Array::join;
}
/**
* Returns <code>true</code> if the predicate holds for all of the elements of this array,
* <code>false</code> otherwise (<code>true</code> for the empty array).
*
* @param f the predicate function to test on each element of this array.
* @return <code>true</code> if the predicate holds for all of the elements of this array,
* <code>false</code> otherwise.
*/
@SuppressWarnings("unchecked")
public boolean forall(final F<A, Boolean> f) {
for (final Object x : a)
if (!f.f((A) x))
return false;
return true;
}
/**
* Returns <code>true</code> if the predicate holds for at least one of the elements of this
* array, <code>false</code> otherwise (<code>false</code> for the empty array).
*
* @param f the predicate function to test on the elements of this array.
* @return <code>true</code> if the predicate holds for at least one of the elements of this
* array.
*/
@SuppressWarnings("unchecked")
public boolean exists(final F<A, Boolean> f) {
for (final Object x : a)
if (f.f((A) x))
return true;
return false;
}
@Override
public boolean equals(Object o) {
return Equal.equals0(Array.class, this, o, () -> Equal.arrayEqual(Equal.anyEqual()));
}
/**
* Finds the first occurrence of an element that matches the given predicate or no value if no
* elements match.
*
* @param f The predicate function to test on elements of this array.
* @return The first occurrence of an element that matches the given predicate or no value if no
* elements match.
*/
@SuppressWarnings("unchecked")
public Option<A> find(final F<A, Boolean> f) {
for (final Object x : a)
if (f.f((A) x))
return some((A) x);
return none();
}
/**
* Returns an array of integers from the given <code>from</code> value (inclusive) to the given
* <code>to</code> value (exclusive).
*
* @param from The minimum value for the array (inclusive).
* @param to The maximum value for the array (exclusive).
* @return An array of integers from the given <code>from</code> value (inclusive) to the given
* <code>to</code> value (exclusive).
*/
public static Array<Integer> range(final int from, final int to) {
if (from >= to)
return empty();
else {
final Array<Integer> a = new Array<>(new Integer[to - from]);
for (int i = from; i < to; i++)
a.set(i - from, i);
return a;
}
}
/**
* Zips this array with the given array using the given function to produce a new array. If this
* array and the given array have different lengths, then the longer array is normalised so this
* function never fails.
*
* @param bs The array to zip this array with.
* @param f The function to zip this array and the given array with.
* @return A new array with a length the same as the shortest of this array and the given array.
*/
public <B, C> Array<C> zipWith(final Array<B> bs, final F<A, F<B, C>> f) {
final int len = min(a.length, bs.length());
final Array<C> x = new Array<>(new Object[len]);
for (int i = 0; i < len; i++) {
x.set(i, f.f(get(i)).f(bs.get(i)));
}
return x;
}
/**
* Zips this array with the given array using the given function to produce a new array. If this
* array and the given array have different lengths, then the longer array is normalised so this
* function never fails.
*
* @param bs The array to zip this array with.
* @param f The function to zip this array and the given array with.
* @return A new array with a length the same as the shortest of this array and the given array.
*/
public <B, C> Array<C> zipWith(final Array<B> bs, final F2<A, B, C> f) {
return zipWith(bs, curry(f));
}
/**
* Zips this array with the given array to produce an array of pairs. If this array and the given
* array have different lengths, then the longer array is normalised so this function never fails.
*
* @param bs The array to zip this array with.
* @return A new array with a length the same as the shortest of this array and the given array.
*/
public <B> Array<P2<A, B>> zip(final Array<B> bs) {
final F<A, F<B, P2<A, B>>> __2 = p2();
return zipWith(bs, __2);
}
/**
* Zips this array with the index of its element as a pair.
*
* @return A new array with the same length as this array.
*/
public Array<P2<A, Integer>> zipIndex() {
return zipWith(range(0, length()), a -> i -> p(a, i));
}
/**
* Projects an immutable collection of this array.
*
* @return An immutable collection of this array.
*/
public Collection<A> toCollection() {
return asJavaList();
}
/**
* Projects an unmodifiable list view of this array.
*
* @return An unmodifiable list view of this array.
*/
@SuppressWarnings("unchecked")
public java.util.List<A> asJavaList() {
return Collections.unmodifiableList(Arrays.asList((A[]) a));
}
/**
* Returns a java.util.ArrayList projection of this array.
*/
public ArrayList<A> toJavaList() {
return new ArrayList<>(asJavaList());
}
/**
* Takes the given iterable to an array.
*
* @param i The iterable to take to an array.
* @return An array from the given iterable.
*/
public static <A> Array<A> iterableArray(final Iterable<A> i) {
return iterableList(i).toArray();
}
/**
* Creates an Array from the iterator.
*/
public static <A> Array<A> iteratorArray(final Iterator<A> i) {
return iterableArray(() -> i);
}
/**
* Returns a copy of the underlying primitive array.
* Equivalent to array(A...)
*
* @return A copy of the underlying primitive array.
*/
@SafeVarargs
public static <A> Array<A> arrayArray(final A...as) {
return new Array<>(as);
}
/**
* Transforms an array of pairs into an array of first components and an array of second components.
*
* @param xs The array of pairs to transform.
* @return An array of first components and an array of second components.
*/
@SuppressWarnings("unchecked")
public static <A, B> P2<Array<A>, Array<B>> unzip(final Array<P2<A, B>> xs) {
final int len = xs.length();
final Array<A> aa = new Array<>(new Object[len]);
final Array<B> ab = new Array<>(new Object[len]);
for (int i = len - 1; i >= 0; i--) {
final P2<A, B> p = xs.get(i);
aa.set(i, p._1());
ab.set(i, p._2());
}
return p(aa, ab);
}
/**
* Projects an array by providing only operations which do not mutate.
*/
public static final class ImmutableProjection<A> implements Iterable<A> {
private final Array<A> a;
private ImmutableProjection(final Array<A> a) {
this.a = a;
}
/**
* Returns an iterator for this array. This method exists to permit the use in a <code>for</code>-each loop.
*
* @return A iterator for this array.
*/
public Iterator<A> iterator() {
return a.iterator();
}
/**
* Returns the element at the given index if it exists, fails otherwise.
*
* @param index The index at which to get the element to return.
* @return The element at the given index if it exists, fails otherwise.
*/
public A get(final int index) {
return a.get(index);
}
/**
* Returns the length of this array.
*
* @return The length of this array.
*/
public int length() {
return a.length();
}
/**
* Returns <code>true</code> is this array is empty, <code>false</code> otherwise.
*
* @return <code>true</code> is this array is empty, <code>false</code> otherwise.
*/
public boolean isEmpty() {
return a.isEmpty();
}
/**
* Returns <code>false</code> is this array is empty, <code>true</code> otherwise.
*
* @return <code>false</code> is this array is empty, <code>true</code> otherwise.
*/
public boolean isNotEmpty() {
return a.isNotEmpty();
}
/**
* Returns an option projection of this array; <code>None</code> if empty, or the first element
* in <code>Some</code>.
*
* @return An option projection of this array.
*/
public Option<A> toOption() {
return a.toOption();
}
/**
* Returns an either projection of this array; the given argument in <code>Left</code> if empty,
* or the first element in <code>Right</code>.
*
* @param x The value to return in left if this array is empty.
* @return An either projection of this array.
*/
public <X> Either<X, A> toEither(final F0<X> x) {
return a.toEither(x);
}
/**
* Returns a list projection of this array.
*
* @return A list projection of this array.
*/
public List<A> toList() {
return a.toList();
}
/**
* Returns a stream projection of this array.
*
* @return A stream projection of this array.
*/
public Stream<A> toStream() {
return a.toStream();
}
/**
* Maps the given function across this array.
*
* @param f The function to map across this array.
* @return A new array after the given function has been applied to each element.
*/
public <B> Array<B> map(final F<A, B> f) {
return a.map(f);
}
/**
* Filters elements from this array by returning only elements which produce <code>true</code>
* when the given function is applied to them.
*
* @param f The predicate function to filter on.
* @return A new array whose elements all match the given predicate.
*/
public Array<A> filter(final F<A, Boolean> f) {
return a.filter(f);
}
/**
* Performs a side-effect for each element of this array.
*
* @param f The side-effect to perform for the given element.
* @return The unit value.
*/
public Unit foreach(final F<A, Unit> f) {
return a.foreach(f);
}
/**
* Performs a right-fold reduction across this array. This function uses O(length) stack space.
*
* @param f The function to apply on each element of the array.
* @param b The beginning value to start the application from.
* @return The final result after the right-fold reduction.
*/
public <B> B foldRight(final F<A, F<B, B>> f, final B b) {
return a.foldRight(f, b);
}
/**
* Performs a left-fold reduction across this array. This function runs in constant space.
*
* @param f The function to apply on each element of the array.
* @param b The beginning value to start the application from.
* @return The final result after the left-fold reduction.
*/
public <B> B foldLeft(final F<B, F<A, B>> f, final B b) {
return a.foldLeft(f, b);
}
/**
* Binds the given function across each element of this array with a final join.
*
* @param f The function to apply to each element of this array.
* @return A new array after performing the map, then final join.
*/
public <B> Array<B> bind(final F<A, Array<B>> f) {
return a.bind(f);
}
/**
* Performs a bind across each array element, but ignores the element value each time.
*
* @param bs The array to apply in the final join.
* @return A new array after the final join.
*/
public <B> Array<B> sequence(final Array<B> bs) {
return a.sequence(bs);
}
/**
* Performs function application within an array (applicative functor pattern).
*
* @param lf The array of functions to apply.
* @return A new array after applying the given array of functions through this array.
*/
public <B> Array<B> apply(final Array<F<A, B>> lf) {
return a.apply(lf);
}
/**
* Reverse this array in constant stack space.
*
* @return A new array that is the reverse of this one.
*/
public Array<A> reverse() {
return a.reverse();
}
/**
* Appends the given array to this array.
*
* @param aas The array to append to this one.
* @return A new array that has appended the given array.
*/
public Array<A> append(final Array<A> aas) {
return a.append(aas);
}
/**
* Projects an immutable collection of this array.
*
* @return An immutable collection of this array.
*/
public Collection<A> toCollection() {
return a.toCollection();
}
}
@SuppressWarnings({"SuspiciousSystemArraycopy", "unchecked", "ObjectEquality", "RedundantCast"})
public static <T, U> T[] copyOf(final U[] a, final int len, final Class<? extends T[]> newType) {
final T[] copy = (Object)newType == Object[].class
? (T[]) new Object[len]
: (T[]) java.lang.reflect.Array.newInstance(newType.getComponentType(), len);
arraycopy(a, 0, copy, 0,
min(a.length, len));
return copy;
}
@SuppressWarnings("unchecked")
public static <T> T[] copyOf(final T[] a, final int len) {
return (T[]) copyOf(a, len, a.getClass());
}
public static char[] copyOfRange(final char[] a, final int from, final int to) {
final int len = to - from;
if (len < 0)
throw new IllegalArgumentException(from + " > " + to);
final char[] copy = new char[len];
arraycopy(a, from, copy, 0,
min(a.length - from, len));
return copy;
}
}