add support for DoubleToLong types

This commit is contained in:
Jonathan Shook 2025-02-18 17:56:33 -06:00
parent d400c81fdb
commit 1f45d0b850

View File

@ -35,6 +35,7 @@ public class VirtDataFunctions {
LongUnaryOperator(java.util.function.LongUnaryOperator.class, long.class), LongUnaryOperator(java.util.function.LongUnaryOperator.class, long.class),
IntFunction(java.util.function.IntFunction.class, int.class), IntFunction(java.util.function.IntFunction.class, int.class),
IntUnaryOperator(java.util.function.IntUnaryOperator.class, int.class), IntUnaryOperator(java.util.function.IntUnaryOperator.class, int.class),
DoubleToLongFunction(java.util.function.DoubleToLongFunction.class, long.class),
DoubleToIntFunction(java.util.function.DoubleToIntFunction.class, int.class), DoubleToIntFunction(java.util.function.DoubleToIntFunction.class, int.class),
DoubleFunction(java.util.function.DoubleFunction.class, double.class), DoubleFunction(java.util.function.DoubleFunction.class, double.class),
DoubleUnaryOperator(java.util.function.DoubleUnaryOperator.class, double.class), DoubleUnaryOperator(java.util.function.DoubleUnaryOperator.class, double.class),
@ -60,46 +61,70 @@ public class VirtDataFunctions {
} }
/** /**
* Adapt a functional object into a different type of functional object. Adapt a functional object into a different type of functional object.
* @param func
* @param func The original function object. The original function object.
* @param type The type of function object needed. @param type
* @param output The output type required for the adapted function. The type of function object needed.
* @param truncate Whether to throw an exception on any narrowing conversion. If this is set to false, then basic @param output
* roll-over logic is applied on narrowing conversions. The output type required for the adapted function.
* @param <F> The type of function object needed. @param truncate
* @return An instance of F Whether to throw an exception on any narrowing conversion. If this is set to false, then
basic
roll-over logic is applied on narrowing conversions.
@param <F>
The type of function object needed.
@return An instance of F
*/ */
public static <F> F adapt(Object func, Class<F> type, Class<?> output, boolean truncate) { public static <F> F adapt(Object func, Class<F> type, Class<?> output, boolean truncate) {
FuncType funcType = FuncType.valueOf(type); FuncType funcType = FuncType.valueOf(type);
switch (funcType) { switch (funcType) {
case DoubleToLongFunction:
return truncate ? (F) adaptDoubleToLongFunction(func, output) :
(F) adaptDoubleToLongFunctionStrict(func, output);
case LongUnaryOperator: case LongUnaryOperator:
return truncate ? (F) adaptLongUnaryOperator(func, output) : (F) adaptLongUnaryOperatorStrict(func, output); return truncate ? (F) adaptLongUnaryOperator(func, output) :
(F) adaptLongUnaryOperatorStrict(func, output);
case DoubleUnaryOperator: case DoubleUnaryOperator:
return truncate ? (F) adaptDoubleUnaryOperator(func, output) : (F) adaptDoubleUnaryOperatorStrict(func, output); return truncate ? (F) adaptDoubleUnaryOperator(func, output) :
(F) adaptDoubleUnaryOperatorStrict(func, output);
case IntUnaryOperator: case IntUnaryOperator:
return truncate ? adaptIntUnaryOperator(func, output) : adaptIntUnaryOperatorStrict(func, output); return truncate ? adaptIntUnaryOperator(func, output) :
adaptIntUnaryOperatorStrict(func, output);
case DoubleFunction: case DoubleFunction:
return truncate ? adaptDoubleFunction(func, output) : adaptDoubleFunctionStrict(func, output); return truncate ? adaptDoubleFunction(func, output) :
adaptDoubleFunctionStrict(func, output);
case LongFunction: case LongFunction:
return truncate ? (F) adaptLongFunction(func, output) : (F) adaptLongFunctionStrict(func, output); return truncate ? (F) adaptLongFunction(func, output) :
(F) adaptLongFunctionStrict(func, output);
case LongToDoubleFunction: case LongToDoubleFunction:
return truncate ? (F) adaptLongToDoubleFunction(func, output) : (F) adaptLongToDoubleFunctionStrict(func, output); return truncate ? (F) adaptLongToDoubleFunction(func, output) :
(F) adaptLongToDoubleFunctionStrict(func, output);
case LongToIntFunction: case LongToIntFunction:
return truncate ? (F) adaptLongToIntFunction(func, output) : (F) adaptLongFunctionStrict(func, output); return truncate ? (F) adaptLongToIntFunction(func, output) :
(F) adaptLongFunctionStrict(func, output);
case IntFunction: case IntFunction:
return adaptIntFunction(func, output); return adaptIntFunction(func, output);
case Function: case Function:
return truncate ? (F) adaptFunction(func, output) : adaptFunctionStrict(func, output); return truncate ? (F) adaptFunction(func, output) :
adaptFunctionStrict(func, output);
default: default:
throw new RuntimeException("Unable to convert function type '" + funcType + "' (" + func.getClass().getName() + throw new RuntimeException(
") to " + type.getName() + (truncate ? " WITH " : " WITHOUT ") + "truncation"); "Unable to convert function type '" + funcType + "' (" + func.getClass()
.getName() + ") to " + type.getName() + (truncate ? " WITH " : " WITHOUT ")
+ "truncation");
} }
} }
public static <F extends Object> List<F> adaptList(Object[] funcs, Class<F> type, Class<?> output, boolean truncate) { public static <F extends Object> List<F> adaptList(
Object[] funcs,
Class<F> type,
Class<?> output,
boolean truncate
)
{
List<F> adapted = new ArrayList<>(); List<F> adapted = new ArrayList<>();
for (Object func : funcs) { for (Object func : funcs) {
F f = adapt(func, type, output, truncate); F f = adapt(func, type, output, truncate);
@ -109,7 +134,11 @@ public class VirtDataFunctions {
} }
private static LongToDoubleFunction adaptLongToDoubleFunctionStrict(Object func, Class<?> output) { private static LongToDoubleFunction adaptLongToDoubleFunctionStrict(
Object func,
Class<?> output
)
{
FuncType isaType = FuncType.valueOf(func.getClass()); FuncType isaType = FuncType.valueOf(func.getClass());
switch (isaType) { switch (isaType) {
case LongToDoubleFunction: case LongToDoubleFunction:
@ -119,62 +148,117 @@ public class VirtDataFunctions {
LongToIntFunction f2 = assertTypesAssignable(func, LongToIntFunction.class); LongToIntFunction f2 = assertTypesAssignable(func, LongToIntFunction.class);
return f2::applyAsInt; return f2::applyAsInt;
case LongFunction: case LongFunction:
LongFunction<Double> f3 = assertTypesAssignable(func, LongFunction.class, double.class); LongFunction<Double> f3 =
assertTypesAssignable(func, LongFunction.class, double.class);
return f3::apply; return f3::apply;
case LongUnaryOperator: case LongUnaryOperator:
LongUnaryOperator f4 = assertTypesAssignable(func, LongUnaryOperator.class); LongUnaryOperator f4 = assertTypesAssignable(func, LongUnaryOperator.class);
return f4::applyAsLong; return f4::applyAsLong;
case DoubleFunction: case DoubleFunction:
DoubleFunction<Double> f7 = assertTypesAssignable(func, DoubleFunction.class, double.class); DoubleFunction<Double> f7 =
assertTypesAssignable(func, DoubleFunction.class, double.class);
return f7::apply; return f7::apply;
case DoubleUnaryOperator: case DoubleUnaryOperator:
DoubleUnaryOperator f8 = assertTypesAssignable(func, DoubleUnaryOperator.class); DoubleUnaryOperator f8 = assertTypesAssignable(func, DoubleUnaryOperator.class);
return f8::applyAsDouble; return f8::applyAsDouble;
case Function: case Function:
Function<Double, Double> f9 = assertTypesAssignable(func, Function.class, double.class, double.class); Function<Double, Double> f9 =
assertTypesAssignable(func, Function.class, double.class, double.class);
return l -> f9.apply((double) l).doubleValue(); return l -> f9.apply((double) l).doubleValue();
case IntFunction: case IntFunction:
case IntUnaryOperator: case IntUnaryOperator:
throwNarrowingError(func, isaType.functionClazz); throwNarrowingError(func, isaType.functionClazz);
default: default:
throw new BasicError("I don't know how to convert a " + func.getClass().getName() + " function to a LongToDoubleFunction."); throw new BasicError("I don't know how to convert a " + func.getClass().getName()
+ " function to a LongToDoubleFunction.");
} }
} }
private static DoubleToLongFunction adaptDoubleToLongFunction(Object func, Class<?> output) {
FuncType isaType = FuncType.valueOf(func.getClass());
switch (isaType) {
case LongToDoubleFunction:
LongToDoubleFunction f1 = assertTypesAssignable(func, LongToDoubleFunction.class);
return l -> (long) f1.applyAsDouble((long) l);
case LongToIntFunction:
LongToIntFunction f2 = assertTypesAssignable(func, LongToIntFunction.class);
return l -> f2.applyAsInt((long) l);
case LongFunction:
LongFunction<Long> f3 = assertTypesAssignable(func, LongFunction.class, Long.class);
return l -> f3.apply((long) l);
case LongUnaryOperator:
LongUnaryOperator f4 = assertTypesAssignable(func, LongUnaryOperator.class);
return l -> f4.applyAsLong((long) l);
case IntFunction:
IntFunction<Long> f5 = assertTypesAssignable(func, IntFunction.class, Long.class);
return l -> f5.apply((int) l);
case IntUnaryOperator:
IntUnaryOperator f6 = assertTypesAssignable(func, IntUnaryOperator.class);
return l -> f6.applyAsInt((int) l);
case DoubleToLongFunction:
DoubleToLongFunction f7 = assertTypesAssignable(func, DoubleToLongFunction.class);
return l -> f7.applyAsLong((long) l);
case DoubleToIntFunction:
DoubleToIntFunction f8 = assertTypesAssignable(func, DoubleToIntFunction.class);
return l -> f8.applyAsInt((int) l);
case DoubleFunction:
DoubleFunction<Long> f9 =
assertTypesAssignable(func, DoubleFunction.class, Long.class);
return f9::apply;
case DoubleUnaryOperator:
DoubleUnaryOperator f10 = assertTypesAssignable(func, DoubleUnaryOperator.class);
return l -> (long) f10.applyAsDouble(l);
case Function:
Function<Double, Long> f11 =
assertTypesAssignable(func, Function.class, Double.class, Long.class);
return f11::apply;
default:
throw new BasicError("I don't know how to convert a " + func.getClass().getName()
+ " function to a DoubleToLongFunction.");
}
}
private static LongToDoubleFunction adaptLongToDoubleFunction(Object func, Class<?> output) { private static LongToDoubleFunction adaptLongToDoubleFunction(Object func, Class<?> output) {
FuncType isaType = FuncType.valueOf(func.getClass()); FuncType isaType = FuncType.valueOf(func.getClass());
switch (isaType) { switch (isaType) {
case LongToDoubleFunction: case LongToDoubleFunction:
LongToDoubleFunction f1 = assertTypesAssignable(func, LongToDoubleFunction.class); return assertTypesAssignable(func, LongToDoubleFunction.class);
return null;
case LongToIntFunction: case LongToIntFunction:
LongToIntFunction f2 = assertTypesAssignable(func, LongToIntFunction.class); LongToIntFunction f2 = assertTypesAssignable(func, LongToIntFunction.class);
return null; return f2::applyAsInt;
case LongFunction: case LongFunction:
LongFunction<Double> f3 = assertTypesAssignable(func, LongFunction.class, double.class); LongFunction<Double> f3 =
return null; assertTypesAssignable(func, LongFunction.class, double.class);
return f3::apply;
case LongUnaryOperator: case LongUnaryOperator:
LongUnaryOperator f4 = assertTypesAssignable(func, LongUnaryOperator.class); LongUnaryOperator f4 = assertTypesAssignable(func, LongUnaryOperator.class);
return null; return f4::applyAsLong;
case IntFunction: case IntFunction:
IntFunction<Double> f5 = assertTypesAssignable(func, IntFunction.class, double.class); IntFunction<Double> f5 =
return null; assertTypesAssignable(func, IntFunction.class, double.class);
return l -> f5.apply((int) l);
case IntUnaryOperator: case IntUnaryOperator:
IntUnaryOperator f6 = assertTypesAssignable(func, IntUnaryOperator.class); IntUnaryOperator f6 = assertTypesAssignable(func, IntUnaryOperator.class);
return null; return operand -> f6.applyAsInt((int) operand);
case DoubleFunction: case DoubleFunction:
DoubleFunction<Double> f7 = assertTypesAssignable(func, DoubleFunction.class, double.class); DoubleFunction<Double> f7 =
return null; assertTypesAssignable(func, DoubleFunction.class, double.class);
return f7::apply;
case DoubleUnaryOperator: case DoubleUnaryOperator:
DoubleUnaryOperator f8 = assertTypesAssignable(func, DoubleUnaryOperator.class); DoubleUnaryOperator f8 = assertTypesAssignable(func, DoubleUnaryOperator.class);
return null; return f8::applyAsDouble;
case Function: case Function:
Function<Double, Double> f9 = assertTypesAssignable(func, Function.class, double.class, double.class); Function<Double, Double> f9 =
return null; assertTypesAssignable(func, Function.class, double.class, double.class);
return t -> f9.apply((double) t);
default: default:
throw new BasicError("I don't know how to convert a " + func.getClass().getName() + " function to a LongToDoubleFunction."); throw new BasicError("I don't know how to convert a " + func.getClass().getName()
+ " function to a LongToDoubleFunction.");
} }
} }
@ -188,15 +272,32 @@ public class VirtDataFunctions {
case LongUnaryOperator: case LongUnaryOperator:
LongUnaryOperator f2 = assertTypesAssignable(func, LongUnaryOperator.class); LongUnaryOperator f2 = assertTypesAssignable(func, LongUnaryOperator.class);
return f2::applyAsLong; return f2::applyAsLong;
case LongToDoubleFunction:
LongToDoubleFunction f7 = assertTypesAssignable(func, LongToDoubleFunction.class);
return f7::applyAsDouble;
case LongToIntFunction: case LongToIntFunction:
LongToIntFunction f3 = assertTypesAssignable(func, LongToIntFunction.class); LongToIntFunction f3 = assertTypesAssignable(func, LongToIntFunction.class);
return f3::applyAsInt; return f3::applyAsInt;
case DoubleToLongFunction:
DoubleToLongFunction f4 = assertTypesAssignable(func, DoubleToLongFunction.class);
return f4::applyAsLong;
case DoubleToIntFunction:
DoubleToIntFunction f5 = assertTypesAssignable(func, DoubleToIntFunction.class);
return f5::applyAsInt;
case DoubleFunction:
DoubleFunction<?> f6 = assertTypesAssignable(func, DoubleFunction.class);
return f6::apply;
case Function: case Function:
Function<Long, Long> f7 = assertTypesAssignable(func, Function.class, Long.class); Function<Long, Long> f8 = assertTypesAssignable(func, Function.class, Long.class);
return (long l) -> f7.apply(l); return f8::apply;
case DoubleUnaryOperator:
case IntUnaryOperator:
case IntFunction:
default: default:
throw new RuntimeException("Unable to convert " + func.getClass().getName() + " to a " + throw new RuntimeException(
LongUnaryOperator.class.getName() + " since this would cause a narrowing conversion."); "Unable to convert " + func.getClass().getName() + " to a "
+ LongUnaryOperator.class.getName()
+ " since this would cause a narrowing conversion.");
} }
} }
@ -206,48 +307,60 @@ public class VirtDataFunctions {
switch (isaType) { switch (isaType) {
case LongFunction: case LongFunction:
LongFunction<?> f1 = (LongFunction<?>) func; LongFunction<?> f1 = (LongFunction<?>) func;
Function<Long, ?> rf1 = f1::apply; return (Function<Long, ?>) f1::apply;
return rf1;
case LongUnaryOperator: case LongUnaryOperator:
LongUnaryOperator f2 = (LongUnaryOperator) func; LongUnaryOperator f2 = (LongUnaryOperator) func;
Function<Long, Long> rf2 = f2::applyAsLong; return (Function<Long, Long>) f2::applyAsLong;
return rf2;
case IntFunction: case IntFunction:
IntFunction f3 = (IntFunction) func; IntFunction<?> f3 = (IntFunction<?>) func;
Function<Integer, ?> rf3 = f3::apply; return (Function<Integer, ?>) f3::apply;
return rf3;
case IntUnaryOperator: case IntUnaryOperator:
IntUnaryOperator f4 = (IntUnaryOperator) func; IntUnaryOperator f4 = (IntUnaryOperator) func;
Function<Integer, ?> rf4 = f4::applyAsInt; return (Function<Integer, ?>) f4::applyAsInt;
return rf4;
case DoubleFunction: case DoubleFunction:
DoubleFunction f5 = (DoubleFunction) func; DoubleFunction<?> f5 = (DoubleFunction<?>) func;
Function<Double, ?> rf5 = f5::apply; return (Function<Double, ?>) f5::apply;
return rf5;
case DoubleUnaryOperator: case DoubleUnaryOperator:
DoubleUnaryOperator f6 = (DoubleUnaryOperator) func; DoubleUnaryOperator f6 = (DoubleUnaryOperator) func;
Function<Double, ?> rf6 = f6::applyAsDouble; return (Function<Double, ?>) f6::applyAsDouble;
return rf6; case LongToDoubleFunction:
LongToDoubleFunction f10 = (LongToDoubleFunction) func;
return (Function<Long, Double>) f10;
case LongToIntFunction: case LongToIntFunction:
LongToIntFunction f7 = (LongToIntFunction) func; LongToIntFunction f7 = (LongToIntFunction) func;
Function<Long, Integer> rf7 = f7::applyAsInt; Function<Long, Integer> rf7 = f7::applyAsInt;
case Function: case Function:
return (Function<?, ?>) func; return (Function<?, ?>) func;
case DoubleToLongFunction:
DoubleToLongFunction f8 = (DoubleToLongFunction) func;
return (Function<Double, Long>) f8::applyAsLong;
case DoubleToIntFunction:
DoubleToIntFunction f9 = (DoubleToIntFunction) func;
return (Function<Double, Integer>) f9;
default: default:
throw new RuntimeException("Unable to map function:" + func); throw new RuntimeException("Unable to map function:" + func);
} }
} }
private static <F> F adaptFunctionStrict(Object func, Class<?> output) { private static <F> F adaptFunctionStrict(Object func, Class<?> output) {
throw new RuntimeException("This must be implemented, now that it is used: adaptFunctionsStrict(Object,Class<?>)"); throw new RuntimeException(
"This must be implemented, now that it is used: adaptFunctionsStrict(Object,Class<?>)");
} }
private static <F> F adaptDoubleFunctionStrict(Object func, Class<?> output) { private static <F> F adaptDoubleFunctionStrict(Object func, Class<?> output) {
throw new RuntimeException("This must be implemented, now that it is used: adaptDoubleFunctionStrict(Object,Class<?>) "); throw new RuntimeException(
"This must be implemented, now that it is used: adaptDoubleFunctionStrict(Object,Class<?>) ");
} }
private static LongFunction<?> adaptDoubleToLongFunctionStrict(Object func, Class<?> output) {
throw new RuntimeException(
"This must be implemented, now that it is used: adaptDoubleToLongFunctionStrict(Object,Class<?>)");
}
private static <F> F adaptIntUnaryOperatorStrict(Object func, Class<?> output) { private static <F> F adaptIntUnaryOperatorStrict(Object func, Class<?> output) {
throw new RuntimeException("This must be implemented, now that it is used: adaptIntUnaryOperatorStrict(Object,Class<?>)"); throw new RuntimeException(
"This must be implemented, now that it is used: adaptIntUnaryOperatorStrict(Object,Class<?>)");
} }
private static DoubleUnaryOperator adaptDoubleUnaryOperator(Object func, Class<?> output) { private static DoubleUnaryOperator adaptDoubleUnaryOperator(Object func, Class<?> output) {
@ -255,7 +368,8 @@ public class VirtDataFunctions {
switch (toFuncType) { switch (toFuncType) {
case DoubleFunction: case DoubleFunction:
DoubleFunction<Double> f2 = assertTypesAssignable(func, DoubleFunction.class, double.class); DoubleFunction<Double> f2 =
assertTypesAssignable(func, DoubleFunction.class, double.class);
return f2::apply; return f2::apply;
case LongToDoubleFunction: case LongToDoubleFunction:
LongToDoubleFunction f3 = assertTypesAssignable(func, LongToDoubleFunction.class); LongToDoubleFunction f3 = assertTypesAssignable(func, LongToDoubleFunction.class);
@ -264,13 +378,15 @@ public class VirtDataFunctions {
LongToIntFunction f4 = assertTypesAssignable(func, LongToIntFunction.class); LongToIntFunction f4 = assertTypesAssignable(func, LongToIntFunction.class);
return l -> f4.applyAsInt((long) l % Long.MAX_VALUE); return l -> f4.applyAsInt((long) l % Long.MAX_VALUE);
case LongFunction: case LongFunction:
LongFunction<Double> f5 = assertTypesAssignable(func, LongFunction.class, double.class); LongFunction<Double> f5 =
assertTypesAssignable(func, LongFunction.class, double.class);
return l -> (double) f5.apply((long) l % Long.MAX_VALUE); return l -> (double) f5.apply((long) l % Long.MAX_VALUE);
case LongUnaryOperator: case LongUnaryOperator:
LongUnaryOperator f6 = assertTypesAssignable(func, LongUnaryOperator.class); LongUnaryOperator f6 = assertTypesAssignable(func, LongUnaryOperator.class);
return l -> f6.applyAsLong((long) l % Long.MAX_VALUE); return l -> f6.applyAsLong((long) l % Long.MAX_VALUE);
case IntFunction: case IntFunction:
IntFunction<Double> f7 = assertTypesAssignable(func, IntFunction.class, double.class); IntFunction<Double> f7 =
assertTypesAssignable(func, IntFunction.class, double.class);
return l -> (double) f7.apply((int) l % Integer.MAX_VALUE); return l -> (double) f7.apply((int) l % Integer.MAX_VALUE);
case IntUnaryOperator: case IntUnaryOperator:
IntUnaryOperator f8 = assertTypesAssignable(func, IntUnaryOperator.class); IntUnaryOperator f8 = assertTypesAssignable(func, IntUnaryOperator.class);
@ -282,25 +398,31 @@ public class VirtDataFunctions {
DoubleUnaryOperator fA = assertTypesAssignable(func, DoubleUnaryOperator.class); DoubleUnaryOperator fA = assertTypesAssignable(func, DoubleUnaryOperator.class);
return fA; return fA;
case Function: case Function:
Function<Double, Double> f1 = assertTypesAssignable(func, Function.class, double.class, double.class); Function<Double, Double> f1 =
assertTypesAssignable(func, Function.class, double.class, double.class);
return f1::apply; return f1::apply;
default: default:
throw new IllegalStateException("Unexpected value: " + toFuncType); throw new IllegalStateException("Unexpected value: " + toFuncType);
} }
} }
private static DoubleUnaryOperator adaptDoubleUnaryOperatorStrict(Object func, Class<?> output) { private static DoubleUnaryOperator adaptDoubleUnaryOperatorStrict(Object func, Class<?> output)
{
FuncType toFuncType = FuncType.valueOf(func.getClass()); FuncType toFuncType = FuncType.valueOf(func.getClass());
switch (toFuncType) { switch (toFuncType) {
case Function: case Function:
Function<Double, Double> f1 = assertTypesAssignable(func, Function.class, double.class, double.class); Function<Double, Double> f1 =
assertTypesAssignable(func, Function.class, double.class, double.class);
return f1::apply; return f1::apply;
case DoubleFunction: case DoubleFunction:
DoubleFunction<Double> f2 = assertTypesAssignable(func, DoubleFunction.class, double.class); DoubleFunction<Double> f2 =
assertTypesAssignable(func, DoubleFunction.class, double.class);
return f2::apply; return f2::apply;
default: default:
throw new RuntimeException("Unable to convert " + func.getClass().getName() + " to a " + throw new RuntimeException(
DoubleUnaryOperator.class.getName() + " since this would cause a narrowing conversion."); "Unable to convert " + func.getClass().getName() + " to a "
+ DoubleUnaryOperator.class.getName()
+ " since this would cause a narrowing conversion.");
} }
} }
@ -315,16 +437,20 @@ public class VirtDataFunctions {
LongUnaryOperator o5 = assertTypesAssignable(func, LongUnaryOperator.class); LongUnaryOperator o5 = assertTypesAssignable(func, LongUnaryOperator.class);
return o5; return o5;
case Function: case Function:
Function<Long, Long> o7 = assertTypesAssignable(func, Function.class, long.class, long.class); Function<Long, Long> o7 =
assertTypesAssignable(func, Function.class, long.class, long.class);
return o7::apply; return o7::apply;
default: default:
throw new RuntimeException("Unable to convert " + func.getClass().getName() + " to a " + throw new RuntimeException(
LongUnaryOperator.class.getName() + " since this would cause a narrowing conversion."); "Unable to convert " + func.getClass().getName() + " to a "
+ LongUnaryOperator.class.getName()
+ " since this would cause a narrowing conversion.");
} }
} }
private static <F> F adaptIntFunction(Object func, Class<?> output) { private static <F> F adaptIntFunction(Object func, Class<?> output) {
throw new RuntimeException("This must be implemented, now that it is used: adaptIntFunction(Object,Class<?>)"); throw new RuntimeException(
"This must be implemented, now that it is used: adaptIntFunction(Object,Class<?>)");
} }
protected static LongToIntFunction adaptLongToIntFunction(Object func, Class<?> output) { protected static LongToIntFunction adaptLongToIntFunction(Object func, Class<?> output) {
@ -332,31 +458,36 @@ public class VirtDataFunctions {
switch (isaType) { switch (isaType) {
case LongToDoubleFunction: case LongToDoubleFunction:
LongToDoubleFunction f1 = assertTypesAssignable(func, LongToDoubleFunction.class, double.class); LongToDoubleFunction f1 =
assertTypesAssignable(func, LongToDoubleFunction.class, double.class);
return l -> (int) (f1.applyAsDouble(l) % Integer.MAX_VALUE); return l -> (int) (f1.applyAsDouble(l) % Integer.MAX_VALUE);
case LongToIntFunction: case LongToIntFunction:
LongToIntFunction f2 = assertTypesAssignable(func, LongToIntFunction.class); LongToIntFunction f2 = assertTypesAssignable(func, LongToIntFunction.class);
return f2; return f2;
case LongFunction: case LongFunction:
LongFunction<Double> f3 = assertTypesAssignable(func, LongFunction.class, double.class); LongFunction<Double> f3 =
assertTypesAssignable(func, LongFunction.class, double.class);
return l -> (int) f3.apply((int) l % Integer.MAX_VALUE).longValue(); return l -> (int) f3.apply((int) l % Integer.MAX_VALUE).longValue();
case LongUnaryOperator: case LongUnaryOperator:
LongUnaryOperator f4 = assertTypesAssignable(func, LongUnaryOperator.class); LongUnaryOperator f4 = assertTypesAssignable(func, LongUnaryOperator.class);
return l -> (int) (f4.applyAsLong(l) % Integer.MAX_VALUE); return l -> (int) (f4.applyAsLong(l) % Integer.MAX_VALUE);
case IntFunction: case IntFunction:
IntFunction<Long> f5 = assertTypesAssignable(func, IntFunction.class, double.class); IntFunction<Long> f5 = assertTypesAssignable(func, IntFunction.class, double.class);
return l -> (int) f5.apply((int) l % Integer.MAX_VALUE).longValue() % Integer.MAX_VALUE; return l -> (int) f5.apply((int) l % Integer.MAX_VALUE).longValue()
% Integer.MAX_VALUE;
case IntUnaryOperator: case IntUnaryOperator:
IntUnaryOperator f6 = assertTypesAssignable(func, IntUnaryOperator.class); IntUnaryOperator f6 = assertTypesAssignable(func, IntUnaryOperator.class);
return l -> f6.applyAsInt((int) l % Integer.MAX_VALUE); return l -> f6.applyAsInt((int) l % Integer.MAX_VALUE);
case DoubleFunction: case DoubleFunction:
DoubleFunction<Double> f7 = assertTypesAssignable(func, DoubleFunction.class, double.class); DoubleFunction<Double> f7 =
assertTypesAssignable(func, DoubleFunction.class, double.class);
return l -> (int) f7.apply(l).longValue() & Integer.MAX_VALUE; return l -> (int) f7.apply(l).longValue() & Integer.MAX_VALUE;
case DoubleUnaryOperator: case DoubleUnaryOperator:
DoubleUnaryOperator f8 = assertTypesAssignable(func, DoubleUnaryOperator.class); DoubleUnaryOperator f8 = assertTypesAssignable(func, DoubleUnaryOperator.class);
return l -> (int) f8.applyAsDouble(l) % Integer.MAX_VALUE; return l -> (int) f8.applyAsDouble(l) % Integer.MAX_VALUE;
case Function: case Function:
Function<Double, Double> f9 = assertTypesAssignable(func, Function.class, double.class, double.class); Function<Double, Double> f9 =
assertTypesAssignable(func, Function.class, double.class, double.class);
return l -> (int) f9.apply((double) l).longValue() % Integer.MAX_VALUE; return l -> (int) f9.apply((double) l).longValue() % Integer.MAX_VALUE;
default: default:
throw new IllegalStateException("Unexpected value: " + isaType); throw new IllegalStateException("Unexpected value: " + isaType);
@ -397,29 +528,33 @@ public class VirtDataFunctions {
assertOutputAssignable(f9.applyAsInt(1L), output); assertOutputAssignable(f9.applyAsInt(1L), output);
return (long l) -> f9.applyAsInt(l); return (long l) -> f9.applyAsInt(l);
default: default:
throw new RuntimeException("Unable to convert " + func.getClass().getName() + " to a " + throw new RuntimeException(
LongUnaryOperator.class.getName()); "Unable to convert " + func.getClass().getName() + " to a "
+ LongUnaryOperator.class.getName());
} }
} }
private static void assertOutputAssignable(Object result, Class<?> clazz) { private static void assertOutputAssignable(Object result, Class<?> clazz) {
if (!ClassUtils.isAssignable(result.getClass(), clazz, true)) { if (!ClassUtils.isAssignable(result.getClass(), clazz, true)) {
throw new InvalidParameterException("Unable to assign type of " + result.getClass().getName() throw new InvalidParameterException(
+ " to " + clazz.getName()); "Unable to assign type of " + result.getClass().getName() + " to "
+ clazz.getName());
} }
// if (!clazz.isAssignableFrom(result.getClass())) { // if (!clazz.isAssignableFrom(result.getClass())) {
// throw new InvalidParameterException("Unable to assign type of " + result.getClass().getName() // throw new InvalidParameterException("Unable to assign type of " + result.getClass().getName()
// + " to " + clazz.getName()); // + " to " + clazz.getName());
// } // }
} }
private static <F> F adaptDoubleFunction(Object func, Class<?> output) { private static <F> F adaptDoubleFunction(Object func, Class<?> output) {
throw new RuntimeException("This must be implemented, now that it is used: adaptDoubleFunction(Object,Class<?>)"); throw new RuntimeException(
"This must be implemented, now that it is used: adaptDoubleFunction(Object,Class<?>)");
} }
private static <F> F adaptIntUnaryOperator(Object func, Class<?> output) { private static <F> F adaptIntUnaryOperator(Object func, Class<?> output) {
throw new RuntimeException("This must be implemented, now that it is used: adaptIntUnaryOperator(Object,Class<?>)"); throw new RuntimeException(
"This must be implemented, now that it is used: adaptIntUnaryOperator(Object,Class<?>)");
} }
@ -434,7 +569,8 @@ public class VirtDataFunctions {
LongFunction<Long> o2 = assertTypesAssignable(func, LongFunction.class, long.class); LongFunction<Long> o2 = assertTypesAssignable(func, LongFunction.class, long.class);
return o2::apply; return o2::apply;
case DoubleFunction: case DoubleFunction:
DoubleFunction<Long> o3 = assertTypesAssignable(func, DoubleFunction.class, long.class); DoubleFunction<Long> o3 =
assertTypesAssignable(func, DoubleFunction.class, long.class);
return o3::apply; return o3::apply;
case IntUnaryOperator: case IntUnaryOperator:
IntUnaryOperator o4 = assertTypesAssignable(func, IntUnaryOperator.class); IntUnaryOperator o4 = assertTypesAssignable(func, IntUnaryOperator.class);
@ -446,7 +582,8 @@ public class VirtDataFunctions {
DoubleUnaryOperator o6 = assertTypesAssignable(func, DoubleUnaryOperator.class); DoubleUnaryOperator o6 = assertTypesAssignable(func, DoubleUnaryOperator.class);
return (long l) -> (long) (o6.applyAsDouble(l) % Long.MAX_VALUE); return (long l) -> (long) (o6.applyAsDouble(l) % Long.MAX_VALUE);
case Function: case Function:
Function<Long, Long> o7 = assertTypesAssignable(func, Function.class, long.class, long.class); Function<Long, Long> o7 =
assertTypesAssignable(func, Function.class, long.class, long.class);
return o7::apply; return o7::apply;
case LongToDoubleFunction: case LongToDoubleFunction:
LongToDoubleFunction o8 = assertTypesAssignable(func, LongToDoubleFunction.class); LongToDoubleFunction o8 = assertTypesAssignable(func, LongToDoubleFunction.class);
@ -455,49 +592,60 @@ public class VirtDataFunctions {
LongToIntFunction o9 = assertTypesAssignable(func, LongToIntFunction.class); LongToIntFunction o9 = assertTypesAssignable(func, LongToIntFunction.class);
return o9::applyAsInt; return o9::applyAsInt;
} }
throw new InvalidParameterException("Unable to convert " + func.getClass().getName() + " to a " + throw new InvalidParameterException(
LongUnaryOperator.class.getName()); "Unable to convert " + func.getClass().getName() + " to a "
+ LongUnaryOperator.class.getName());
} }
/** /**
* Given a base object and a wanted type to convert it to, assert that the type of the base object is assignable to Given a base object and a wanted type to convert it to, assert that the type of the base object
* the wanted type. Further, if the wanted type is a generic type, assert that additional classes are assignable to is assignable to
* the generic type parameters. Thus, if you want to assign to a generic type from a non-generic type, you must the wanted type. Further, if the wanted type is a generic type, assert that additional classes
* qualify the types of values that will be used in those generic parameter positions in declaration order. are assignable to
* the generic type parameters. Thus, if you want to assign to a generic type from a non-generic
* <p>This is useful for taking any object and a known type and reifying it as the known type so that it can be type, you must
* then used idiomatically with normal type awareness. This scenario occurs when you are accepting an open type for qualify the types of values that will be used in those generic parameter positions in
* flexibility but then need to narrow the type sufficiently for additional conversion in a type-safe way.</p> declaration order.
*
* @param base The object to be assigned to the wanted type <p>This is useful for taking any object and a known type and reifying it as the known type so
* @param wantType The class type that the base object needs to be assignable to that it can be
* @param clazzes The types of values which will checked against generic type parameters of the wanted type then used idiomatically with normal type awareness. This scenario occurs when you are accepting
* @param <T> Generic parameter T for the wanted type an open type for
* @return The original object casted to the wanted type after verification of parameter assignability flexibility but then need to narrow the type sufficiently for additional conversion in a
type-safe way.</p>
@param base
The object to be assigned to the wanted type
@param wantType
The class type that the base object needs to be assignable to
@param clazzes
The types of values which will checked against generic type parameters of the wanted type
@param <T>
Generic parameter T for the wanted type
@return The original object casted to the wanted type after verification of parameter assignability
*/ */
private static <T> T assertTypesAssignable( private static <T> T assertTypesAssignable(Object base, Class<T> wantType, Class<?>... clazzes)
Object base, {
Class<T> wantType,
Class<?>... clazzes) {
if (!wantType.isAssignableFrom(base.getClass())) { if (!wantType.isAssignableFrom(base.getClass())) {
throw new InvalidParameterException("Unable to assign " + wantType.getName() + " from " + throw new InvalidParameterException(
base.getClass().getName()); "Unable to assign " + wantType.getName() + " from " + base.getClass().getName());
} }
TypeVariable<? extends Class<?>>[] typeParameters = base.getClass().getTypeParameters(); TypeVariable<? extends Class<?>>[] typeParameters = base.getClass().getTypeParameters();
if (typeParameters.length > 0) { if (typeParameters.length > 0) {
if (clazzes.length != typeParameters.length) { if (clazzes.length != typeParameters.length) {
throw new InvalidParameterException( throw new InvalidParameterException(
"type parameter lengths are mismatched:" + clazzes.length + ", " + typeParameters.length "type parameter lengths are mismatched:" + clazzes.length + ", "
); + typeParameters.length);
} }
for (int i = 0; i < clazzes.length; i++) { for (int i = 0; i < clazzes.length; i++) {
Class<?> from = clazzes[i]; Class<?> from = clazzes[i];
TypeVariable<? extends Class<?>> to = typeParameters[i]; TypeVariable<? extends Class<?>> to = typeParameters[i];
boolean assignableFrom = to.getGenericDeclaration().isAssignableFrom(from); boolean assignableFrom = to.getGenericDeclaration().isAssignableFrom(from);
if (!assignableFrom) { if (!assignableFrom) {
throw new InvalidParameterException("Can not assign " + from.getName() + " to " + to.getGenericDeclaration().getName()); throw new InvalidParameterException(
"Can not assign " + from.getName() + " to " + to.getGenericDeclaration()
.getName());
} }
} }
@ -507,14 +655,16 @@ public class VirtDataFunctions {
} }
/** /**
* Throw an error indicating a narrowing conversion was attempted for strict conversion. Throw an error indicating a narrowing conversion was attempted for strict conversion.
* @param func
* @param func The source function to convert from The source function to convert from
* @param targetClass The target class which was requested @param targetClass
The target class which was requested
*/ */
private static void throwNarrowingError(Object func, Class<?> targetClass) { private static void throwNarrowingError(Object func, Class<?> targetClass) {
throw new BasicError("Converting from " + func.getClass().getName() + " to " + targetClass.getName() + throw new BasicError(
" is not allowed when strict conversion is requested."); "Converting from " + func.getClass().getName() + " to " + targetClass.getName()
+ " is not allowed when strict conversion is requested.");
} }