package org.corfudb.util;
import com.google.common.collect.ImmutableMap;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.BinaryOperator;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import java.util.function.DoubleBinaryOperator;
import java.util.function.DoubleConsumer;
import java.util.function.DoubleFunction;
import java.util.function.DoublePredicate;
import java.util.function.DoubleSupplier;
import java.util.function.DoubleToIntFunction;
import java.util.function.DoubleToLongFunction;
import java.util.function.DoubleUnaryOperator;
import java.util.function.Function;
import java.util.function.IntBinaryOperator;
import java.util.function.IntConsumer;
import java.util.function.IntFunction;
import java.util.function.IntPredicate;
import java.util.function.IntSupplier;
import java.util.function.IntToDoubleFunction;
import java.util.function.IntToLongFunction;
import java.util.function.IntUnaryOperator;
import java.util.function.LongBinaryOperator;
import java.util.function.LongConsumer;
import java.util.function.LongFunction;
import java.util.function.LongPredicate;
import java.util.function.LongSupplier;
import java.util.function.LongToDoubleFunction;
import java.util.function.LongToIntFunction;
import java.util.function.LongUnaryOperator;
import java.util.function.ObjDoubleConsumer;
import java.util.function.ObjIntConsumer;
import java.util.function.ObjLongConsumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.function.ToDoubleBiFunction;
import java.util.function.ToDoubleFunction;
import java.util.function.ToIntBiFunction;
import java.util.function.ToIntFunction;
import java.util.function.ToLongBiFunction;
import java.util.function.ToLongFunction;
import java.util.function.UnaryOperator;
/**
* Created by mwei on 3/24/16.
*/
public class LambdaUtils {
private static final Map<Class<Object>, LambdaResolver<Object>> dispatchMap = generateDispatchMap();
@SuppressWarnings("unchecked")
private static Map<Class<Object>, LambdaResolver<Object>> generateDispatchMap() {
ImmutableMap.Builder<Class<Object>, LambdaResolver<Object>> builder =
ImmutableMap.<Class<Object>, LambdaResolver<Object>>builder();
typedPut(builder, BiConsumer.class, (f, a) -> {
f.accept(a[0], a[1]);
return null;
});
typedPut(builder, BiFunction.class, (f, a) -> f.apply(a[0], a[1]));
typedPut(builder, BinaryOperator.class, (f, a) -> f.apply(a[0], a[1]));
typedPut(builder, BiPredicate.class, (f, a) -> f.test(a[0], a[1]));
typedPut(builder, BooleanSupplier.class, (f, a) -> f.getAsBoolean());
typedPut(builder, Consumer.class, (f, a) -> {
f.accept(a[0]);
return null;
});
typedPut(builder, DoubleBinaryOperator.class, (f, a) -> f.applyAsDouble((double) a[0], (double) a[1]));
typedPut(builder, DoubleConsumer.class, (f, a) -> {
f.accept((double) a[0]);
return null;
});
typedPut(builder, DoubleFunction.class, (f, a) -> f.apply((double) a[0]));
typedPut(builder, DoublePredicate.class, (f, a) -> f.test((double) a[0]));
typedPut(builder, DoubleSupplier.class, (f, a) -> f.getAsDouble());
typedPut(builder, DoubleToIntFunction.class, (f, a) -> f.applyAsInt((double) a[0]));
typedPut(builder, DoubleToLongFunction.class, (f, a) -> f.applyAsLong((double) a[0]));
typedPut(builder, DoubleUnaryOperator.class, (f, a) -> f.applyAsDouble((double) a[0]));
typedPut(builder, Function.class, (f, a) -> f.apply(a[0]));
typedPut(builder, IntBinaryOperator.class, (f, a) -> f.applyAsInt((int) a[0], (int) a[1]));
typedPut(builder, IntConsumer.class, (f, a) -> {
f.accept((int) a[0]);
return null;
});
typedPut(builder, IntFunction.class, (f, a) -> f.apply((int) a[0]));
typedPut(builder, IntPredicate.class, (f, a) -> f.test((int) a[0]));
typedPut(builder, IntSupplier.class, (f, a) -> f.getAsInt());
typedPut(builder, IntToDoubleFunction.class, (f, a) -> f.applyAsDouble((int) a[0]));
typedPut(builder, IntToLongFunction.class, (f, a) -> f.applyAsLong((int) a[0]));
typedPut(builder, IntUnaryOperator.class, (f, a) -> f.applyAsInt((int) a[0]));
typedPut(builder, LongBinaryOperator.class, (f, a) -> f.applyAsLong((long) a[0], (long) a[1]));
typedPut(builder, LongConsumer.class, (f, a) -> {
f.accept((long) a[0]);
return null;
});
typedPut(builder, LongFunction.class, (f, a) -> f.apply((long) a[0]));
typedPut(builder, LongPredicate.class, (f, a) -> f.test((long) a[0]));
typedPut(builder, LongSupplier.class, (f, a) -> f.getAsLong());
typedPut(builder, LongToDoubleFunction.class, (f, a) -> f.applyAsDouble((long) a[0]));
typedPut(builder, LongToIntFunction.class, (f, a) -> f.applyAsInt((long) a[0]));
typedPut(builder, LongUnaryOperator.class, (f, a) -> f.applyAsLong((long) a[0]));
typedPut(builder, ObjDoubleConsumer.class, (f, a) -> {
f.accept(a[0], (double) a[1]);
return null;
});
typedPut(builder, ObjIntConsumer.class, (f, a) -> {
f.accept(a[0], (int) a[1]);
return null;
});
typedPut(builder, ObjLongConsumer.class, (f, a) -> {
f.accept(a[0], (long) a[1]);
return null;
});
typedPut(builder, Predicate.class, (f, a) -> f.test(a[0]));
typedPut(builder, Supplier.class, (f, a) -> f.get());
typedPut(builder, ToDoubleBiFunction.class, (f, a) -> f.applyAsDouble(a[0], a[1]));
typedPut(builder, ToDoubleFunction.class, (f, a) -> f.applyAsDouble(a[0]));
typedPut(builder, ToIntBiFunction.class, (f, a) -> f.applyAsInt(a[0], a[1]));
typedPut(builder, ToIntFunction.class, (f, a) -> f.applyAsInt(a[0]));
typedPut(builder, ToLongBiFunction.class, (f, a) -> f.applyAsLong(a[0], a[1]));
typedPut(builder, ToLongFunction.class, (f, a) -> f.applyAsLong(a[0]));
typedPut(builder, UnaryOperator.class, (f, a) -> f.apply(a[0]));
return builder.build();
}
@SuppressWarnings("unchecked")
private static <T, U> ImmutableMap.Builder<Class<T>, LambdaResolver<T>> typedPut(
ImmutableMap.Builder<Class<T>, LambdaResolver<T>> builder,
Class<U> cls,
LambdaResolver<U> fn) {
return builder.put((Class<T>) cls, (LambdaResolver<T>) fn);
}
/**
* This function executes an unknown lambda from Java's broken (IMO) functional interface.
*/
public static Object executeUnknownLambda(Object unknownLambda, Object... arguments) {
return dispatchMap.entrySet().stream()
.filter(e -> e.getKey().isInstance(unknownLambda))
.findFirst().get().getValue().resolve(unknownLambda, arguments);
}
@FunctionalInterface
interface LambdaResolver<T> {
Object resolve(T resolver, Object[] args);
}
}