1 package javany.util;
   2 
   3 import javany.util.function.Function;
   4 
   5 import java.lang.reflect.Array;
   6 import java.util.HashMap;
   7 import java.util.Map;
   8 
   9 /**
  10  * A helper for common <any T> functionality
  11  */
  12 public class Any<any T> {
  13 
  14     // default value
  15 
  16     public static <any T> T defaultValue() {
  17         return new Any<T>().defaultValue;
  18     }
  19 
  20     // null-safe: equals, hashCode & toString
  21 
  22     public static <any T> boolean equals(T a, T b) {
  23         return new Any<T>().equalsImpl(a, b);
  24     }
  25 
  26     public static <any T> int hashCode(T a) {
  27         return new Any<T>().hashCodeImpl(a);
  28     }
  29 
  30     public static <any T> String toString(T a) {
  31         return new Any<T>().toStringImpl(a);
  32     }
  33 
  34     // array construction
  35 
  36     public static <any T> T[] newArray(int length, Class<? extends T[]> type) {
  37         return new Any<T>().newArrayImpl(length, type);
  38     }
  39 
  40     // array copying
  41 
  42     @SuppressWarnings("unchecked")
  43     public static <any S, any D> void arraycopy(S[] src,  int  srcPos,
  44                                                 D[] dest, int destPos,
  45                                                 int length) {
  46         if (Function<S, D>.class == Function<S, S>.class) {
  47             // erasure(S) == erasure(D)
  48             System.arraycopy(src, srcPos, dest, destPos, length);
  49         } else {
  50             // assert src != dest;
  51             if (srcPos < 0 || destPos < 0 || length < 0 ||
  52                 srcPos + length > src.length || destPos + length > dest.length) {
  53                 throw new IndexOutOfBoundsException(String.format(
  54                     "src.length=%d, srcPos=%d, dest.length=%d, destPos=%d, length=%d",
  55                     src.length, srcPos, dest.length, destPos, length
  56                 ));
  57             }
  58             Function<S, D> converter = converter();
  59             while (length-- > 0) {
  60                 dest[destPos++] = converter.apply(src[srcPos++]);
  61             }
  62         }
  63     }
  64 
  65     // identity, widening, boxing and unboxing conversions
  66 
  67     @SuppressWarnings("unchecked")
  68     public static <any S, any T> Function<S, T> converter() {
  69         Function<S, T> converter = (Function<S, T>) converters.get(Function<S, T>.class);
  70         if (converter == null) {
  71             throw new ClassCastException("No converter: " + Function<S, T>.class.getName());
  72         }
  73         return converter;
  74     }
  75 
  76     public static <any S, any T> T convert(S source) {
  77         return Any.<S, T>converter().apply(source);
  78     }
  79 
  80     private static final Map<Class<?>, Object> converters = new HashMap<>();
  81 
  82     @SuppressWarnings("unchecked")
  83     private static <any S, any T> void putConverter(Function<S, T> converter) {
  84         converters.put(Function<S, T>.class, converter);
  85     }
  86 
  87     static {
  88         // identity conversions
  89 
  90         putConverter(Function.<boolean>identity());
  91         putConverter(Function.<byte>identity());
  92         putConverter(Function.<short>identity());
  93         putConverter(Function.<char>identity());
  94         putConverter(Function.<int>identity());
  95         putConverter(Function.<long>identity());
  96         putConverter(Function.<float>identity());
  97         putConverter(Function.<double>identity());
  98         putConverter(Function.<Object>identity());
  99 
 100         // widening conversions
 101 
 102         putConverter((Function<byte, short>) (x) -> (short)x);
 103         putConverter((Function<byte, int>) (x) -> (int)x);
 104         putConverter((Function<byte, long>) (x) -> (long)x);
 105         putConverter((Function<byte, float>) (x) -> (float)x);
 106         putConverter((Function<byte, double>) (x) -> (double)x);
 107 
 108         putConverter((Function<short, int>) (x) -> (int)x);
 109         putConverter((Function<short, long>) (x) -> (long)x);
 110         putConverter((Function<short, float>) (x) -> (float)x);
 111         putConverter((Function<short, double>) (x) -> (double)x);
 112 
 113         putConverter((Function<char, int>) (x) -> (int)x);
 114         putConverter((Function<char, long>) (x) -> (long)x);
 115         putConverter((Function<char, float>) (x) -> (float)x);
 116         putConverter((Function<char, double>) (x) -> (double)x);
 117 
 118         putConverter((Function<int, long>) (x) -> (long)x);
 119         putConverter((Function<int, float>) (x) -> (float)x);
 120         putConverter((Function<int, double>) (x) -> (double)x);
 121 
 122         putConverter((Function<float, double>) (x) -> (double)x);
 123 
 124         // boxing conversions
 125 
 126         putConverter((Function<boolean, Boolean>) Boolean::valueOf);
 127         putConverter((Function<byte, Byte>) Byte::valueOf);
 128         putConverter((Function<short, Short>) Short::valueOf);
 129         putConverter((Function<char, Character>) Character::valueOf);
 130         putConverter((Function<int, Integer>) Integer::valueOf);
 131         putConverter((Function<long, Long>) Long::valueOf);
 132         putConverter((Function<float, Float>) Float::valueOf);
 133         putConverter((Function<double, Double>) Double::valueOf);
 134 
 135         // unboxing conversions
 136 
 137         putConverter((Function<Boolean, boolean>) Boolean::booleanValue);
 138         putConverter((Function<Byte, byte>) Byte::byteValue);
 139         putConverter((Function<Short, short>) Short::shortValue);
 140         putConverter((Function<Character, char>) Character::charValue);
 141         putConverter((Function<Integer, int>) Integer::intValue);
 142         putConverter((Function<Long, long>) Long::longValue);
 143         putConverter((Function<Float, float>) Float::floatValue);
 144         putConverter((Function<Double, double>) Double::doubleValue);
 145     }
 146 
 147     // private instance implementation
 148 
 149     private Any() {}
 150 
 151     private T defaultValue;
 152 
 153     private boolean equalsImpl(T a, T b) {
 154         __WhereVal(T) {
 155             return equalsNonNullImpl(a, b);
 156         }
 157         __WhereRef(T) {
 158             return a == b || (a != null && equalsNonNullImpl(a, b));
 159         }
 160     }
 161 
 162     private boolean equalsNonNullImpl(T a, T b) {
 163         return a.equals(b);
 164     }
 165 
 166     private int hashCodeImpl(T a) {
 167         __WhereVal(T) {
 168             return hashCodeNonNullImpl(a);
 169         }
 170         __WhereRef(T) {
 171             return (a == null) ? 0 : hashCodeNonNullImpl(a);
 172         }
 173     }
 174 
 175     private int hashCodeNonNullImpl(T a) {
 176         return a.hashCode();
 177     }
 178 
 179     private String toStringImpl(T a) {
 180         __WhereVal(T) {
 181             return toStringNonNullImpl(a);
 182         }
 183         __WhereRef(T) {
 184             return (a == null) ? "null" : toStringNonNullImpl(a);
 185         }
 186     }
 187 
 188     private String toStringNonNullImpl(T a) {
 189         return a.toString();
 190     }
 191 
 192     private T[] newArrayImpl(int length, Class<? extends T[]> type) {
 193         __WhereVal(T) {
 194             return new T[length];
 195         }
 196         __WhereRef(T) {
 197             @SuppressWarnings("unchecked")
 198             T[] array = ((Object) type == (Object) Object[].class)
 199                 ? (T[]) new Object[length]
 200                 : (T[]) Array.newInstance(type.getComponentType(), length);
 201             return array;
 202         }
 203     }
 204 }