package uk.kludje; import java.lang.reflect.Array; /** * An array manipulation type. * Instances of this type are immutable and thread-safe. * * @param <T> the type of the array */ final class ArrayMapper<T> { /** A string array mapper. */ private static final ArrayMapper<String> STRING_ARRAY_MAPPER = new ArrayMapper<>(String.class); private final Class<T> type; private final T[] empty; @SuppressWarnings("unchecked") private ArrayMapper(Class<T> type) { Ensure.that(type != null, "type != null"); this.type = type; this.empty = (T[]) Array.newInstance(type, 0); } /** * @param type the array class * @param <T> the generic type * @return an instance for the given type; some instances may be interned */ @SuppressWarnings("unchecked") public static <T> ArrayMapper<T> arrayMapper(Class<T> type) { if (type == String.class) { return (ArrayMapper<T>) STRING_ARRAY_MAPPER; } return new ArrayMapper<>(type); } /** * Returns an empty array of type {@code T}. * This method will always return the same instance for a given instance of {@link ArrayMapper}. * * @return an array with length zero */ public T[] empty() { return empty; } /** * Returns a new instance with the given element at the end. * * @param oldArray the old array * @param newElement the element to contatenate * @param <E> the element type * @return a new array */ @SuppressWarnings("unchecked") public <E extends T> T[] concat(T[] oldArray, E newElement) { T[] arr = (T[]) Array.newInstance(type, oldArray.length + 1); System.arraycopy(oldArray, 0, arr, 0, oldArray.length); arr[oldArray.length] = newElement; return arr; } }