Functions.java
/*
* @copyright defined in LICENSE.txt
*/
package hera.api.function;
import static hera.util.ValidationUtils.assertNotNull;
import hera.api.function.impl.Function0WithIdentity;
import hera.api.function.impl.Function1WithIdentity;
import hera.api.function.impl.Function2WithIdentity;
import hera.api.function.impl.Function3WithIdentity;
import hera.api.function.impl.Function4WithIdentity;
import hera.api.function.impl.Function5WithIdentity;
import hera.exception.HerajException;
import java.util.List;
public final class Functions {
protected static final Class<?>[] functions = {
Function0.class,
Function1.class,
Function2.class,
Function3.class,
Function4.class,
Function5.class,
};
/**
* Invoke target {@code f} with {@code args} and return result.
*
* @param <R> an invocation return type
*
* @param f a function to invoke
* @param args arguments to pass
* @return invocation result
*/
public static <R> R invoke(final Function<R> f, final List<Object> args) {
return buildInvocation(f, args).apply();
}
/**
* Make invocation with {@code f} and {@code args}.
*
* @param <R> an invocation return type
*
* @param f a function to invoke
* @param args arguments to pass
* @return invocation object
*/
@SuppressWarnings("unchecked")
public static <R> Function0<R> buildInvocation(final Function<R> f, final List<Object> args) {
assertNotNull(f);
assertNotNull(args);
if (functions.length < args.size()) {
throw new HerajException("Invalid arguments length for target " + f);
}
final Class<?> possibleTarget = functions[args.size()];
if (!possibleTarget.isInstance(f)) {
throw new HerajException("Invalid arguments length for target " + f);
}
return new Function0<R>() {
@Override
public R apply() {
R ret = null;
if (f instanceof Function0) {
ret = ((Function0<R>) f)
.apply();
} else if (f instanceof Function1) {
ret = ((Function1<Object, R>) f)
.apply(args.get(0));
} else if (f instanceof Function2) {
ret = ((Function2<Object, Object, R>) f)
.apply(args.get(0), args.get(1));
} else if (f instanceof Function3) {
ret = ((Function3<Object, Object, Object, R>) f)
.apply(args.get(0), args.get(1), args.get(2));
} else if (f instanceof Function4) {
ret = ((Function4<Object, Object, Object, Object, R>) f)
.apply(args.get(0), args.get(1), args.get(2), args.get(3));
} else if (f instanceof Function5) {
ret = ((Function5<Object, Object, Object, Object, Object, R>) f)
.apply(args.get(0), args.get(1), args.get(2), args.get(3), args.get(4));
}
return ret;
}
};
}
/**
* Identify a function by name.
*
* @param <R> a function return type
*
* @param f a function to identify
* @param identity an identity
*
* @return a function with identity
*/
public static <R> Function0<R> identify(final Function0<R> f, final String identity) {
return new Function0WithIdentity<R>(f, identity);
}
/**
* Identify a function by name.
*
* @param <T> a function argument type
* @param <R> a function return type
*
* @param f a function to identify
* @param identity an identity
*
* @return a function with identity
*/
public static <T, R> Function1<T, R> identify(final Function1<T, R> f,
final String identity) {
return new Function1WithIdentity<T, R>(f, identity);
}
/**
* Identify a function by name.
*
* @param <T1> a function 1st argument type
* @param <T2> a function 2nd argument type
* @param <R> a function return type
*
* @param f a function to identify
* @param identity an identity
*
* @return a function with identity
*/
public static <T1, T2, R> Function2<T1, T2, R> identify(final Function2<T1, T2, R> f,
final String identity) {
return new Function2WithIdentity<T1, T2, R>(f, identity);
}
/**
* Identify a function by name.
*
* @param <T1> a function 1st argument type
* @param <T2> a function 2nd argument type
* @param <T3> a function 3rd argument type
* @param <R> a function return type
*
* @param f a function to identify
* @param identity an identity
*
* @return a function with identity
*/
public static <T1, T2, T3, R> Function3<T1, T2, T3, R> identify(final Function3<T1, T2, T3, R> f,
final String identity) {
return new Function3WithIdentity<T1, T2, T3, R>(f, identity);
}
/**
* Identify a function by name.
*
* @param <T1> a function 1st argument type
* @param <T2> a function 2nd argument type
* @param <T3> a function 3rd argument type
* @param <T4> a function 4th argument type
* @param <R> a function return type
*
* @param f a function to identify
* @param identity an identity
*
* @return a function with identity
*/
public static <T1, T2, T3, T4, R> Function4<T1, T2, T3, T4, R> identify(
final Function4<T1, T2, T3, T4, R> f, final String identity) {
return new Function4WithIdentity<T1, T2, T3, T4, R>(f, identity);
}
/**
* Identify a function by name.
*
* @param <T1> a function 1st argument type
* @param <T2> a function 2nd argument type
* @param <T3> a function 3rd argument type
* @param <T4> a function 4th argument type
* @param <T5> a function 5th argument type
* @param <R> a function return type
*
* @param f a function to identify
* @param identity an identity
*
* @return a function with identity
*/
public static <T1, T2, T3, T4, T5, R> Function5<T1, T2, T3, T4, T5, R> identify(
final Function5<T1, T2, T3, T4, T5, R> f, final String identity) {
return new Function5WithIdentity<T1, T2, T3, T4, T5, R>(f, identity);
}
/**
* Returns a composed function that first applies {@code first} function to its input, and then
* applies the {@code second} function to the result.
*
* @param <R> the output type of {@code first} and the input type of {@code second}
* @param <V> the type of output of the {@code second} function
*
* @param first the function to invoke first
* @param second the function to invoke second
*
* @return a composed function that first applies {@code first} function and then applies the
* {@code second} function
*
* @throws NullPointerException if before or after is null
*/
public static <R, V> Function0<V> compose(final Function0<R> first,
final Function1<? super R, ? extends V> second) {
if (null == first) {
throw new NullPointerException();
}
if (null == second) {
throw new NullPointerException();
}
return new Function0<V>() {
@Override
public V apply() {
return second.apply(first.apply());
}
};
}
/**
* Returns a composed function that first applies {@code first} function to its input, and then
* applies the {@code second} function to the result.
*
* @param <T> the input type of {@code first}
* @param <R> the output type of {@code first} and the input type of {@code second}
* @param <V> the type of output of the {@code second} function
*
* @param first the function to invoke first
* @param second the function to invoke second
*
* @return a composed function that first applies {@code first} function and then applies the
* {@code second} function
*
* @throws NullPointerException if before or after is null
*/
public static <T, R, V> Function1<T, V> compose(final Function1<? super T, ? extends R> first,
final Function1<? super R, ? extends V> second) {
if (null == first) {
throw new NullPointerException();
}
if (null == second) {
throw new NullPointerException();
}
return new Function1<T, V>() {
@Override
public V apply(final T t) {
return second.apply(first.apply(t));
}
};
}
/**
* Returns a composed function that first applies {@code first} function to its input, and then
* applies the {@code second} function to the result.
*
* @param <T1> the 1st input type of {@code first}
* @param <T2> the 2nd input type of {@code first}
* @param <R> the output type of {@code first} and the input type of {@code second}
* @param <V> the type of output of the {@code second} function
*
* @param first the function to invoke first
* @param second the function to invoke second
*
* @return a composed function that first applies {@code first} function and then applies the
* {@code second} function
*
* @throws NullPointerException if before or after is null
*/
public static <T1, T2, R, V> Function2<T1, T2, V> compose(
final Function2<? super T1, ? super T2, ? extends R> first,
final Function1<? super R, ? extends V> second) {
if (null == first) {
throw new NullPointerException();
}
if (null == second) {
throw new NullPointerException();
}
return new Function2<T1, T2, V>() {
@Override
public V apply(final T1 t1, final T2 t2) {
return second.apply(first.apply(t1, t2));
}
};
}
/**
* Returns a composed function that first applies {@code first} function to its input, and then
* applies the {@code second} function to the result.
*
* @param <T1> the 1st input type of {@code first}
* @param <T2> the 2nd input type of {@code first}
* @param <T3> the 3rd input type of {@code first}
* @param <R> the output type of {@code first} and the input type of {@code second}
* @param <V> the type of output of the {@code second} function
*
* @param first the function to invoke first
* @param second the function to invoke second
*
* @return a composed function that first applies {@code first} function and then applies the
* {@code second} function
*
* @throws NullPointerException if before or after is null
*/
public static <T1, T2, T3, R, V> Function3<T1, T2, T3, V> compose(
final Function3<? super T1, ? super T2, ? super T3, ? extends R> first,
final Function1<? super R, ? extends V> second) {
if (null == first) {
throw new NullPointerException();
}
if (null == second) {
throw new NullPointerException();
}
return new Function3<T1, T2, T3, V>() {
@Override
public V apply(final T1 t1, final T2 t2, final T3 t3) {
return second.apply(first.apply(t1, t2, t3));
}
};
}
/**
* Returns a composed function that first applies {@code first} function to its input, and then
* applies the {@code second} function to the result.
*
* @param <T1> the 1st input type of {@code first}
* @param <T2> the 2nd input type of {@code first}
* @param <T3> the 3rd input type of {@code first}
* @param <T4> the 3rd input type of {@code first}
* @param <R> the output type of {@code first} and the input type of {@code second}
* @param <V> the type of output of the {@code second} function
*
* @param first the function to invoke first
* @param second the function to invoke second
*
* @return a composed function that first applies {@code first} function and then applies the
* {@code second} function
*
* @throws NullPointerException if before or after is null
*/
public static <T1, T2, T3, T4, R, V> Function4<T1, T2, T3, T4, V> compose(
final Function4<? super T1, ? super T2, ? super T3, ? super T4, ? extends R> first,
final Function1<? super R, ? extends V> second) {
if (null == first) {
throw new NullPointerException();
}
if (null == second) {
throw new NullPointerException();
}
return new Function4<T1, T2, T3, T4, V>() {
@Override
public V apply(final T1 t1, final T2 t2, final T3 t3, final T4 t4) {
return second.apply(first.apply(t1, t2, t3, t4));
}
};
}
/**
* Returns a composed function that first applies {@code first} function to its input, and then
* applies the {@code second} function to the result.
*
* @param <T1> the 1st input type of {@code first}
* @param <T2> the 2nd input type of {@code first}
* @param <T3> the 3rd input type of {@code first}
* @param <T4> the 3rd input type of {@code first}
* @param <T5> the 4th input type of {@code first}
* @param <R> the output type of {@code first} and the input type of {@code second}
* @param <V> the type of output of the {@code second} function
*
* @param first the function to invoke first
* @param second the function to invoke second
*
* @return a composed function that first applies {@code first} function and then applies the
* {@code second} function
*
* @throws NullPointerException if before or after is null
*/
public static <T1, T2, T3, T4, T5, R, V> Function5<T1, T2, T3, T4, T5, V> compose(
final Function5<? super T1, ? super T2, ? super T3, ? super T4, ? super T5,
? extends R> first,
final Function1<? super R, ? extends V> second) {
if (null == first) {
throw new NullPointerException();
}
if (null == second) {
throw new NullPointerException();
}
return new Function5<T1, T2, T3, T4, T5, V>() {
@Override
public V apply(final T1 t1, final T2 t2, final T3 t3, final T4 t4, final T5 t5) {
return second.apply(first.apply(t1, t2, t3, t4, t5));
}
};
}
}