--- /dev/null 2015-01-19 11:28:01.396824775 +0100 +++ new/src/java.base/share/classes/java/util/Any.java 2015-02-04 10:44:13.988894732 +0100 @@ -0,0 +1,204 @@ +package javany.util; + +import javany.util.function.Function; + +import java.lang.reflect.Array; +import java.util.HashMap; +import java.util.Map; + +/** + * A helper for common <any T> functionality + */ +public class Any { + + // default value + + public static T defaultValue() { + return new Any().defaultValue; + } + + // null-safe: equals, hashCode & toString + + public static boolean equals(T a, T b) { + return new Any().equalsImpl(a, b); + } + + public static int hashCode(T a) { + return new Any().hashCodeImpl(a); + } + + public static String toString(T a) { + return new Any().toStringImpl(a); + } + + // array construction + + public static T[] newArray(int length, Class type) { + return new Any().newArrayImpl(length, type); + } + + // array copying + + @SuppressWarnings("unchecked") + public static void arraycopy(S[] src, int srcPos, + D[] dest, int destPos, + int length) { + if (Function.class == Function.class) { + // erasure(S) == erasure(D) + System.arraycopy(src, srcPos, dest, destPos, length); + } else { + // assert src != dest; + if (srcPos < 0 || destPos < 0 || length < 0 || + srcPos + length > src.length || destPos + length > dest.length) { + throw new IndexOutOfBoundsException(String.format( + "src.length=%d, srcPos=%d, dest.length=%d, destPos=%d, length=%d", + src.length, srcPos, dest.length, destPos, length + )); + } + Function converter = converter(); + while (length-- > 0) { + dest[destPos++] = converter.apply(src[srcPos++]); + } + } + } + + // identity, widening, boxing and unboxing conversions + + @SuppressWarnings("unchecked") + public static Function converter() { + Function converter = (Function) converters.get(Function.class); + if (converter == null) { + throw new ClassCastException("No converter: " + Function.class.getName()); + } + return converter; + } + + public static T convert(S source) { + return Any.converter().apply(source); + } + + private static final Map, Object> converters = new HashMap<>(); + + @SuppressWarnings("unchecked") + private static void putConverter(Function converter) { + converters.put(Function.class, converter); + } + + static { + // identity conversions + + putConverter(Function.identity()); + putConverter(Function.identity()); + putConverter(Function.identity()); + putConverter(Function.identity()); + putConverter(Function.identity()); + putConverter(Function.identity()); + putConverter(Function.identity()); + putConverter(Function.identity()); + putConverter(Function.identity()); + + // widening conversions + + putConverter((Function) (x) -> (short)x); + putConverter((Function) (x) -> (int)x); + putConverter((Function) (x) -> (long)x); + putConverter((Function) (x) -> (float)x); + putConverter((Function) (x) -> (double)x); + + putConverter((Function) (x) -> (int)x); + putConverter((Function) (x) -> (long)x); + putConverter((Function) (x) -> (float)x); + putConverter((Function) (x) -> (double)x); + + putConverter((Function) (x) -> (int)x); + putConverter((Function) (x) -> (long)x); + putConverter((Function) (x) -> (float)x); + putConverter((Function) (x) -> (double)x); + + putConverter((Function) (x) -> (long)x); + putConverter((Function) (x) -> (float)x); + putConverter((Function) (x) -> (double)x); + + putConverter((Function) (x) -> (double)x); + + // boxing conversions + + putConverter((Function) Boolean::valueOf); + putConverter((Function) Byte::valueOf); + putConverter((Function) Short::valueOf); + putConverter((Function) Character::valueOf); + putConverter((Function) Integer::valueOf); + putConverter((Function) Long::valueOf); + putConverter((Function) Float::valueOf); + putConverter((Function) Double::valueOf); + + // unboxing conversions + + putConverter((Function) Boolean::booleanValue); + putConverter((Function) Byte::byteValue); + putConverter((Function) Short::shortValue); + putConverter((Function) Character::charValue); + putConverter((Function) Integer::intValue); + putConverter((Function) Long::longValue); + putConverter((Function) Float::floatValue); + putConverter((Function) Double::doubleValue); + } + + // private instance implementation + + private Any() {} + + private T defaultValue; + + private boolean equalsImpl(T a, T b) { + __WhereVal(T) { + return equalsNonNullImpl(a, b); + } + __WhereRef(T) { + return a == b || (a != null && equalsNonNullImpl(a, b)); + } + } + + private boolean equalsNonNullImpl(T a, T b) { + return a.equals(b); + } + + private int hashCodeImpl(T a) { + __WhereVal(T) { + return hashCodeNonNullImpl(a); + } + __WhereRef(T) { + return (a == null) ? 0 : hashCodeNonNullImpl(a); + } + } + + private int hashCodeNonNullImpl(T a) { + return a.hashCode(); + } + + private String toStringImpl(T a) { + __WhereVal(T) { + return toStringNonNullImpl(a); + } + __WhereRef(T) { + return (a == null) ? "null" : toStringNonNullImpl(a); + } + } + + private String toStringNonNullImpl(T a) { + return a.toString(); + } + + private T[] newArrayImpl(int length, Class type) { + __WhereVal(T) { + return new T[length]; + } + __WhereRef(T) { + @SuppressWarnings("unchecked") + T[] array = ((Object) type == (Object) Object[].class) + ? (T[]) new Object[length] + : (T[]) Array.newInstance(type.getComponentType(), length); + return array; + } + } +}