package church.lang; import java.lang.reflect.Array; import java.util.function.BiFunction; import java.util.function.IntFunction; import java.util.stream.Stream; import church.util.CollectionsSupport; import church.util.CollectionsSupport.EquivalenceRelation; import church.util.CollectionsSupport.HashingFunction; @SuppressWarnings("unused") public class ArraySupport { /** * A specialised entry point is required here as {@link Array#newInstance(Class, int)} is overloaded. */ @SuppressWarnings("unchecked") public static <T> T[] newArray(Class<T> clarse, int length) { return (T[]) Array.newInstance(clarse, length); } @SuppressWarnings("unchecked") public static <T> T[] createArray0(Class<T> clarse, int length, java.util.function.IntFunction<T> generator) { T[] result = (T[]) Array.newInstance(clarse, length); for (int i = 0; i < result.length; i++) { result[i] = generator.apply(i); } return result; } @SafeVarargs public static <T> T[] array0(T... elements) { return elements; } /* public static <T> T[] emptyArray0(Class<T> clarse) { return (T[]) Array.newInstance(clarse, 0); } */ /** * A specialised entry point is required here as the signature of {@link Stream#toArray(IntFunction)} is: * <pre>{@code * <A> A[] toArray(IntFunction<A[]> generator) * }</pre> * which, when operating on Stream<T>, has two type parameters instead of one. The above signature specifies * that the array will have the same type as the function that created it, but not that the values arriving from * stream must also be of this type -- which they must be to avoid an ArrayStoreException being raised at run-time. * Church's type inference also requires a single type parameter to work correctly here. * <p> * The signature below tightens the specification to align all three type parameters; those of the stream, the array * constructor and the returned array. */ public static <T> T[] toArray(Stream<T> stream, IntFunction<T[]> constructor) { return stream.toArray(constructor); } public static <T> int length0(T[] a) { return a.length; } public static <T> T get0(T[] a, int i) { return a[i]; } @SuppressWarnings("unchecked") private static <T> Class<T> getComponentType(T[] a) { return (Class<T>) a.getClass().getComponentType(); } @SuppressWarnings("unchecked") private static <T> T[] newInstance(Class<T> type, int length) { return (T[]) Array.newInstance(type, length); } public static <T> T[] append0(T[] a, T[] b) { T[] result = newInstance(getComponentType(a), a.length + b.length); java.lang.System.arraycopy(a, 0, result, 0, a.length); java.lang.System.arraycopy(b, 0, result, a.length, b.length); return result; } public static <T> boolean equal0(EquivalenceRelation<T> equivalent, T[] a, T[] b) { if (a == b) { return true; } if (a.length != b.length) { return false; } int length = a.length; for (int i = 0; i < length; i++) { if (!equivalent.equal(a[i], b[i])) { return false; } } return true; } // See Arrays.hashCode(Object[]); public static <T> int hashCode0(HashingFunction<T> hashingFunction, T[] a) { int result = 1; for (T element : a) { result = 31 * result + hashingFunction.hashCode(element); } return result; } public static <T> CollectionsSupport.LeftFold<T[], T> leftFold() { return new CollectionsSupport.LeftFold<T[], T>() { @Override public <R> R reduce(BiFunction<R, T, R> accumulator, R initialValue, T[] array) { R result = initialValue; for (T element : array) { result = accumulator.apply(result, element); } return result; } }; } public static <T> CollectionsSupport.RightFold<T[], T> rightFold() { return new CollectionsSupport.RightFold<T[], T>() { @Override public <R> R reduce(BiFunction<T, R, R> accumulator, R initialValue, T[] array) { R result = initialValue; for (int i = array.length - 1; i >= 0; i--) { T element = array[i]; result = accumulator.apply(element, result); } return result; } }; } }