96 lines
3.4 KiB
Java
96 lines
3.4 KiB
Java
package tc.oc.commons.core.util;
|
|
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
import java.util.function.Function;
|
|
import javax.inject.Provider;
|
|
|
|
import com.google.common.collect.ImmutableMap;
|
|
import com.google.common.reflect.TypeParameter;
|
|
import com.google.common.reflect.TypeToken;
|
|
import com.google.inject.AbstractModule;
|
|
import tc.oc.commons.core.reflect.Types;
|
|
|
|
public class NumberFactory<T extends Number> {
|
|
|
|
private final Function<String, T> parser;
|
|
private final T negativeInfinity, positiveInfinity;
|
|
|
|
private NumberFactory(T negativeInfinity, T positiveInfinity, Function<String, T> parser) {
|
|
this.negativeInfinity = negativeInfinity;
|
|
this.positiveInfinity = positiveInfinity;
|
|
this.parser = parser;
|
|
}
|
|
|
|
public T parse(String text) throws NumberFormatException {
|
|
if("oo".equals(text)) {
|
|
return infinity(true);
|
|
} else if("-oo".equals(text)) {
|
|
return infinity(false);
|
|
} else {
|
|
return parseFinite(text);
|
|
}
|
|
}
|
|
|
|
public T parseFinite(String text) throws NumberFormatException {
|
|
return parser.apply(text);
|
|
}
|
|
|
|
public T infinity(boolean sign) {
|
|
return sign ? positiveInfinity : negativeInfinity;
|
|
}
|
|
|
|
public boolean isInfinite(T value) {
|
|
return positiveInfinity.equals(value) || negativeInfinity.equals(value);
|
|
}
|
|
|
|
public boolean isFinite(T value) {
|
|
return !isInfinite(value);
|
|
}
|
|
|
|
public static Set<Class<? extends Number>> numberTypes() {
|
|
return byType.keySet();
|
|
}
|
|
|
|
public static <T extends Number> TypeToken<NumberFactory<T>> factoryType(Class<T> numberType) {
|
|
return factoryType(TypeToken.of(numberType));
|
|
}
|
|
|
|
public static <T extends Number> TypeToken<NumberFactory<T>> factoryType(TypeToken<T> numberType) {
|
|
return new TypeToken<NumberFactory<T>>(){}.where(new TypeParameter<T>(){}, numberType);
|
|
}
|
|
|
|
public static <T extends Number> NumberFactory<T> get(Class<T> type) {
|
|
final NumberFactory<T> factory = (NumberFactory<T>) byType.get(type);
|
|
if(factory == null) {
|
|
throw new IllegalArgumentException("No NumberFactory for type " + type.getName());
|
|
}
|
|
return factory;
|
|
}
|
|
|
|
public static <T extends Number> Provider<NumberFactory<T>> provider(Class<T> type) {
|
|
return () -> get(type);
|
|
}
|
|
|
|
private static final Map<Class<? extends Number>, NumberFactory<?>> byType = ImmutableMap
|
|
.<Class<? extends Number>, NumberFactory<?>>builder()
|
|
.put(Byte.class, new NumberFactory<>(Byte.MIN_VALUE, Byte.MAX_VALUE, Byte::valueOf))
|
|
.put(Short.class, new NumberFactory<>(Short.MIN_VALUE, Short.MAX_VALUE, Short::valueOf))
|
|
.put(Integer.class, new NumberFactory<>(Integer.MIN_VALUE, Integer.MAX_VALUE, Integer::valueOf))
|
|
.put(Long.class, new NumberFactory<>(Long.MIN_VALUE, Long.MAX_VALUE, Long::valueOf))
|
|
.put(Float.class, new NumberFactory<>(Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY, Float::valueOf))
|
|
.put(Double.class, new NumberFactory<>(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, Double::valueOf))
|
|
.build();
|
|
|
|
public static class Manifest extends AbstractModule {
|
|
@Override
|
|
protected void configure() {
|
|
numberTypes().forEach(this::configure);
|
|
}
|
|
|
|
<T extends Number> void configure(Class<T> type) {
|
|
bind(Types.toLiteral(NumberFactory.factoryType(type))).toProvider(NumberFactory.provider(type));
|
|
}
|
|
}
|
|
}
|