package tc.oc.commons.core.util; import java.lang.reflect.Array; import java.lang.reflect.Method; import java.util.AbstractList; import java.util.Arrays; import java.util.List; import java.util.function.Function; import java.util.function.Predicate; import javax.annotation.Nullable; import tc.oc.commons.core.reflect.Methods; public class ArrayUtils { private ArrayUtils() {} public static final int NOT_FOUND_INDEX = -1; public static <T> T fromEnd(T[] array, int index) { return array[array.length - 1 - index]; } public static <T> int indexOf(T[] array, T value) { if(array == null) return NOT_FOUND_INDEX; if(value == null) { for(int i = 0; i < array.length; i++) { if(array[i] == null) return i; } } else { for(int i = 0; i < array.length; i++) { if(value.equals(array[i])) return i; } } return NOT_FOUND_INDEX; } public static <T> boolean contains(T[] array, T value) { return indexOf(array, value) != NOT_FOUND_INDEX; } /** * Create a new array of given size, with the same component type as the given array */ public static <T> T[] sameType(T[] array, int size) { return (T[]) Array.newInstance(array.getClass().getComponentType(), size); } /** * Similar to {@link Arrays#copyOfRange}, but from can be negative, * which will copy to an offset in the destination array. */ public static <T> T[] copyOfRange(T[] src, int from, int to) { final T[] dest = sameType(src, to - from); System.arraycopy(src, Math.max(0, from), dest, Math.max(0, -from), Math.min(to, src.length)); return dest; } public static <T> T[] append(T[] a, T...b) { if(b.length == 0) return a; if(a.length == 0) return b; T[] result = Arrays.copyOf(a, a.length + b.length); System.arraycopy(b, 0, result, a.length, b.length); return result; } public static <T> T[] prepend(T element, T[] array) { final T[] result = copyOfRange(array, -1, array.length); result[0] = element; return result; } public static <T> void copy(Iterable<? extends T> src, T[] dest, int destPos) { for(T t : src) { if(destPos >= dest.length) break; dest[destPos++] = t; } } public static <T> T first(T[] array, Predicate<T> test, T def) { for(T t : array) { if(test.test(t)) return t; } return def; } public static @Nullable <T> T first(T[] array, Predicate<T> test) { return first(array, test, null); } private static final Method APPLY_METHOD = Methods.method(Function.class, "apply", Object.class); public static <T, U> U[] transform(T[] input, Class<U> outputType, Function<T, U> function) { return transform(input, (U[]) Array.newInstance(outputType, input.length), function); } public static <T, U> U[] transform(T[] input, U[] output, Function<T, U> function) { for(int i = 0; i < input.length; i++) { output[i] = function.apply(input[i]); } return output; } private static final Object[] EMPTY_OBJECT_ARRAY = new Object[]{}; public static Object[] zeroObjects() { return EMPTY_OBJECT_ARRAY; } public static List<Boolean> asList(boolean[] array) { return new AbstractList<Boolean>() { @Override public int size() { return array.length; } @Override public Boolean get(int index) { return array[index]; } }; } public static List<Character> asList(char[] array) { return new AbstractList<Character>() { @Override public int size() { return array.length; } @Override public Character get(int index) { return array[index]; } }; } public static List<Byte> asList(byte[] array) { return new AbstractList<Byte>() { @Override public int size() { return array.length; } @Override public Byte get(int index) { return array[index]; } }; } public static List<Short> asList(short[] array) { return new AbstractList<Short>() { @Override public int size() { return array.length; } @Override public Short get(int index) { return array[index]; } }; } public static List<Integer> asList(int[] array) { return new AbstractList<Integer>() { @Override public int size() { return array.length; } @Override public Integer get(int index) { return array[index]; } }; } public static List<Long> asList(long[] array) { return new AbstractList<Long>() { @Override public int size() { return array.length; } @Override public Long get(int index) { return array[index]; } }; } public static List<Float> asList(float[] array) { return new AbstractList<Float>() { @Override public int size() { return array.length; } @Override public Float get(int index) { return array[index]; } }; } public static List<Double> asList(double[] array) { return new AbstractList<Double>() { @Override public int size() { return array.length; } @Override public Double get(int index) { return array[index]; } }; } public static List<?> asList(Object array) { if(!array.getClass().isArray()) { throw new IllegalArgumentException("Not an array"); } final Class<?> type = array.getClass().getComponentType(); if(!type.isPrimitive()) { return Arrays.asList((Object[]) array); } else if(boolean.class.equals(type)) { return asList((boolean[]) array); } else if(char.class.equals(type)) { return asList((char[]) array); } else if(byte.class.equals(type)) { return asList((byte[]) array); } else if(short.class.equals(type)) { return asList((short[]) array); } else if(int.class.equals(type)) { return asList((int[]) array); } else if(long.class.equals(type)) { return asList((long[]) array); } else if(float.class.equals(type)) { return asList((float[]) array); } else if(double.class.equals(type)) { return asList((double[]) array); } throw new IllegalArgumentException("Weird array type: " + type); } public static <T> List<T> asSubList(int start, int end, T... array) { return new AbstractList() { @Override public int size() { return end - start; } @Override public Object get(int index) { return array[start + index]; } }; } public static <T> List<T> asSubListFrom(int start, T... array) { return asSubList(start, array.length, array); } public static <T> List<T> asSubListTo(int end, T... array) { return asSubList(0, end, array); } }