blob: 29274bdddedf04e41974589945bed906c650ec85 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011 itemis AG (http://www.itemis.eu) and others.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.xtext.xbase.lib;
import org.eclipse.xtext.xbase.lib.Functions.Function0;
import org.eclipse.xtext.xbase.lib.Functions.Function1;
import org.eclipse.xtext.xbase.lib.Functions.Function2;
import org.eclipse.xtext.xbase.lib.Functions.Function3;
import org.eclipse.xtext.xbase.lib.Functions.Function4;
import org.eclipse.xtext.xbase.lib.Functions.Function5;
import org.eclipse.xtext.xbase.lib.Functions.Function6;
import org.eclipse.xtext.xbase.lib.Procedures.Procedure0;
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
import com.google.common.annotations.GwtCompatible;
/**
* This is an extension library for {@link Functions functions}, e.g. closures.
*
* @author Sven Efftinge - Initial contribution and API
* @see Functions
*/
@GwtCompatible public class FunctionExtensions {
/**
* Curries a function that takes one argument.
*
* @param function
* the original function. May not be <code>null</code>.
* @param argument
* the fixed argument.
* @return a function that takes no arguments. Never <code>null</code>.
*/
@Pure
public static <P1, RESULT> Function0<RESULT> curry(final Function1<? super P1, ? extends RESULT> function, final P1 argument) {
if (function == null)
throw new NullPointerException("function");
return new Function0<RESULT>() {
@Override
public RESULT apply() {
return function.apply(argument);
}
};
}
/**
* Curries a function that takes two arguments.
*
* @param function
* the original function. May not be <code>null</code>.
* @param argument
* the fixed first argument of {@code function}.
* @return a function that takes one argument. Never <code>null</code>.
*/
@Pure
public static <P1, P2, RESULT> Function1<P2, RESULT> curry(final Function2<? super P1, ? super P2, ? extends RESULT> function,
final P1 argument) {
if (function == null)
throw new NullPointerException("function");
return new Function1<P2, RESULT>() {
@Override
public RESULT apply(P2 p) {
return function.apply(argument, p);
}
};
}
/**
* Curries a function that takes three arguments.
*
* @param function
* the original function. May not be <code>null</code>.
* @param argument
* the fixed first argument of {@code function}.
* @return a function that takes two arguments. Never <code>null</code>.
*/
@Pure
public static <P1, P2, P3, RESULT> Function2<P2, P3, RESULT> curry(final Function3<? super P1, ? super P2, ? super P3, ? extends RESULT> function,
final P1 argument) {
if (function == null)
throw new NullPointerException("function");
return new Function2<P2, P3, RESULT>() {
@Override
public RESULT apply(P2 p2, P3 p3) {
return function.apply(argument, p2, p3);
}
};
}
/**
* Curries a function that takes four arguments.
*
* @param function
* the original function. May not be <code>null</code>.
* @param argument
* the fixed first argument of {@code function}.
* @return a function that takes three arguments. Never <code>null</code>.
*/
@Pure
public static <P1, P2, P3, P4, RESULT> Function3<P2, P3, P4, RESULT> curry(
final Function4<? super P1, ? super P2, ? super P3, ? super P4, ? extends RESULT> function, final P1 argument) {
if (function == null)
throw new NullPointerException("function");
return new Function3<P2, P3, P4, RESULT>() {
@Override
public RESULT apply(P2 p2, P3 p3, P4 p4) {
return function.apply(argument, p2, p3, p4);
}
};
}
/**
* Curries a function that takes five arguments.
*
* @param function
* the original function. May not be <code>null</code>.
* @param argument
* the fixed first argument of {@code function}.
* @return a function that takes four arguments. Never <code>null</code>.
*/
@Pure
public static <P1, P2, P3, P4, P5, RESULT> Function4<P2, P3, P4, P5, RESULT> curry(
final Function5<? super P1, ? super P2, ? super P3, ? super P4, ? super P5, ? extends RESULT> function, final P1 argument) {
if (function == null)
throw new NullPointerException("function");
return new Function4<P2, P3, P4, P5, RESULT>() {
@Override
public RESULT apply(P2 p2, P3 p3, P4 p4, P5 p5) {
return function.apply(argument, p2, p3, p4, p5);
}
};
}
/**
* Curries a function that takes six arguments.
*
* @param function
* the original function. May not be <code>null</code>.
* @param argument
* the fixed first argument of {@code function}.
* @return a function that takes five arguments. Never <code>null</code>.
*/
@Pure
public static <P1, P2, P3, P4, P5, P6, RESULT> Function5<P2, P3, P4, P5, P6, RESULT> curry(
final Function6<? super P1, ? super P2, ? super P3, ? super P4, ? super P5, ? super P6, ? extends RESULT> function, final P1 argument) {
if (function == null)
throw new NullPointerException("function");
return new Function5<P2, P3, P4, P5, P6, RESULT>() {
@Override
public RESULT apply(P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) {
return function.apply(argument, p2, p3, p4, p5, p6);
}
};
}
/**
* Returns a composed function that first applies the {@code before}
* function to its input, and then applies the {@code after} function to the result.
* If evaluation of either function throws an exception, it is relayed to
* the caller of the composed function.
*
* @param <V> the type of input to the {@code before} function, and to the
* composed function
* @param <T> the type of output of the {@code before} function, and input to the
* {@code after} function
* @param <R> the type of output to the {@code after} function, and to the
* composed function
* @param after the function to apply after the before function is applied
* @param before the function to apply before the after function is applied
* @return a composed function that first applies the {@code before}
* function and then applies the {@code after} function
* @throws NullPointerException if {@code before} or {@code after} is <code>null</code>
*
* @see #andThen(Functions.Function1, Functions.Function1)
* @since 2.9
*/
public static <V,T,R> Function1<V, R> compose(final Function1<? super T, ? extends R> after, final Function1<? super V, ? extends T> before) {
if (after == null)
throw new NullPointerException("after");
if (before == null)
throw new NullPointerException("before");
return new Function1<V,R>() {
@Override
public R apply(V v) {
return after.apply(before.apply(v));
}
};
}
/**
* Returns a composed function that first applies the {@code before}
* function to its input, and then applies the {@code after} function to the result.
* If evaluation of either function throws an exception, it is relayed to
* the caller of the composed function.
*
* @param <V> the type of input to the {@code before} function, and to the composed function
* @param <T> the type of output of the {@code before} function, and input to the {@code after} function
* @param <R> the type of output to the {@code after} function, and to the composed function
* @param before the function to apply before the after function is applied
* @param after the function to apply after the before function is applied
* @return a composed function that first applies the {@code before}
* function and then applies the {@code after} function
* @throws NullPointerException if {@code before} or {@code after} is <code>null</code>
*
* @see #compose(Functions.Function1, Functions.Function1)
* @since 2.9
*/
public static <V,T,R> Function1<V, R> andThen(final Function1<? super V, ? extends T> before, final Function1<? super T, ? extends R> after) {
return compose(after, before);
}
/**
* Returns a composed function that first applies the {@code before}
* function to its input, and then applies the {@code after} function to the result.
* If evaluation of either function throws an exception, it is relayed to
* the caller of the composed function.
*
* @param <V1> the type of the first parameter to the {@code before} function, and to the composed function
* @param <V2> the type of the second parameter to the {@code before} function, and to the composed function
* @param <T> the type of output of the {@code before} function, and input to the {@code after} function
* @param <R> the type of output to the {@code after} function, and to the composed function
* @param before the function to apply before the {@code after} function is applied
* @param after the function to apply after the {@code before} function is applied
* @return a composed function that first applies the {@code before}
* function and then applies the {@code after} function
* @throws NullPointerException if {@code before} or {@code after} is null
*
* @see #compose(Functions.Function1, Functions.Function1)
* @since 2.9
*/
public static <V1,V2,T,R> Function2<V1, V2, R> andThen(final Function2<? super V1,? super V2, ? extends T> before, final Function1<? super T, ? extends R> after) {
if (after == null)
throw new NullPointerException("after");
if (before == null)
throw new NullPointerException("before");
return new Function2<V1, V2, R>() {
@Override
public R apply(V1 v1, V2 v2) {
return after.apply(before.apply(v1, v2));
}
};
}
/**
* Returns a composed {@code Procedure1} that performs, in sequence, the {@code before}
* operation followed by the {@code after} operation. If performing either
* operation throws an exception, it is relayed to the caller of the
* composed operation. If performing the {@code before} operation throws an exception,
* the {@code after} operation will not be performed.
*
* @param <T> the type of input for the {@code before} operation
* @param before the operation to perform first
* @param after the operation to perform afterwards
* @return a composed {@code Procedure1} that performs in sequence the {@code before}
* operation followed by the {@code after} operation
* @throws NullPointerException if {@code before} or {@code after} is null
* @since 2.9
*/
public static <T> Procedure1<T> andThen(final Procedure1<? super T> before, final Procedure1<? super T> after) {
if (after == null)
throw new NullPointerException("after");
if (before == null)
throw new NullPointerException("before");
return new Procedures.Procedure1<T>() {
@Override
public void apply(T p) {
before.apply(p);
after.apply(p);
}
};
}
/**
* Returns a composed {@code Procedure1} that performs, in sequence, the {@code before}
* operation followed by the {@code after} operation. If performing either
* operation throws an exception, it is relayed to the caller of the
* composed operation. If performing the {@code before} operation throws an exception,
* the {@code after} operation will not be performed.
*
* @param before the operation to perform first
* @param after the operation to perform afterwards
* @return a composed {@code Procedure1} that performs in sequence the {@code before}
* operation followed by the {@code after} operation
* @throws NullPointerException if {@code before} or {@code after} is null
* @since 2.9
*/
public static Procedure0 andThen(final Procedure0 before, final Procedure0 after) {
if (after == null)
throw new NullPointerException("after");
if (before == null)
throw new NullPointerException("before");
return new Procedures.Procedure0() {
@Override
public void apply() {
before.apply();
after.apply();
}
};
}
}