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 }