1 /* Copyright (c) 2008 Sascha Kohlmann
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU Affero General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Affero General Public License for more details.
12 *
13 * You should have received a copy of the GNU Affero General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16 package net.sf.eos.util;
17
18 import net.sf.eos.Experimental;
19 import net.sf.eos.Function;
20 import net.sf.eos.Predicate;
21 import net.sf.eos.Supplier;
22 import static net.sf.eos.util.Conditions.checkArgumentNotNull;
23
24 /**
25 * Defines some useful compositions for handling with {@link Function Functions},
26 * {@link Predicate Predicates} and {@link Supplier Suppliers}.
27 *
28 * <p>Each {@code composition} follows the rule of a {@code from} or <em>source</em>
29 * entity, propagating its result value to a {@code to} or <em>target</em> entity.</p>
30 *
31 * @author Sascha Kohlmann
32 */
33 @Experimental
34 public class Compositions {
35
36 /**
37 * Returns the composition of two functions. For {@code f: F→I} and
38 * {@code g: I→T}, composition is defined as the function {@code h}
39 * such that {@code h(x) == g(f(x))} for each {@code x}.
40 *
41 * <p>The usage interface is designed as a {@code from} function which
42 * propagates its result to the {@code to} function.</p>
43 *
44 * @param <F> the {@code from} or <em>source</em> type
45 * @param <I> the intermediate type
46 * @param <T> the {@code to} or <em>target</em> type
47 * @param from the {@code from} or <em>source</em> {@code function}
48 * @param to the {@code to} or <em>target</em> {@code function}
49 * @throws IllegalArgumentException if one parameter is {@code null}
50 * @since 0.1.0
51 */
52 public final static <F, I, T> Function<F, T> compose(
53 final Function<? super F, ? extends I> from,
54 final Function<? super I, ? extends T> to) {
55 return new FunctionComposition<F, I, T>(from, to);
56 }
57
58 /**
59 * @see #compose(Function, Function)
60 */
61 private final static class FunctionComposition<F, I, T> implements Function<F, T> {
62
63 private final Function<? super F, ? extends I> from;
64 private final Function<? super I, ? extends T> to;
65
66 public FunctionComposition(final Function<? super F, ? extends I> from,
67 final Function<? super I, ? extends T> to) {
68 this.from = checkArgumentNotNull(from, "from is null");
69 this.to = checkArgumentNotNull(to, "to is null");
70 }
71 public T apply(final F source) {
72 return to.apply(from.apply(source));
73 }
74 }
75
76 /**
77 * Returns a composition of a <em>from</em> {@code Function} and an evaluating
78 * <em>to</em> {@code Predicate}. The {@code predicate} retrieves the value from
79 * the {@code function}.
80 *
81 * <p>The usage interface is designed as a {@code from} function which
82 * propagates its result to the {@code to} predicate.</p>
83 *
84 * @param <F> the {@code from} or <em>source</em> type
85 * @param <T> the {@code to} or <em>target</em> type
86 * @param fromFunction the {@code from} or <em>source</em> {@code function}
87 * @param toPredicate the {@code to} or <em>target</em> {@code predicate}
88 * @return a {@code predicate}
89 * @throws IllegalArgumentException if one parameter is {@code null}
90 * @since 0.7.0
91 */
92 public final static <F, T> Predicate<F> compose(
93 final Function<? super F, ? extends T> fromFunction,
94 final Predicate<T> toPredicate) {
95 return new FunctionPredicateComposition<F, T>(fromFunction, toPredicate);
96 }
97
98 /** @see #compose(Function, Predicate) */
99 private final static class FunctionPredicateComposition<F, T>
100 implements Predicate<F> {
101
102 private final Predicate<? super T> to;
103 private final Function<? super F, ? extends T> from;
104
105 /**
106 * Constructs the composition of the given {@code Function} and
107 * {@code Predicate}.
108 *
109 * @param fromFunction the inner {@link Function}. Must not be {@code null}.
110 * @param toPredicate the outer {@link Predicate}. Must not be {@code null}.
111 */
112 @SuppressWarnings("nls")
113 public FunctionPredicateComposition(
114 final Function<? super F, ? extends T> fromFunction,
115 final Predicate<T> toPredicate) {
116 this.from = checkArgumentNotNull(fromFunction, "fromFunction is null");
117 this.to = checkArgumentNotNull(toPredicate, "toPredicate is null");
118 }
119
120 /** {@inheritDoc} */
121 public boolean evaluate(final F source) {
122 return this.to.evaluate(this.from.apply(source));
123 }
124 }
125
126 /**
127 * Returns a composition of a <em>from</em> {@code Supplier} and an applied
128 * <em>to</em> {@code Function}. The {@code function} retrieves the value from
129 * the {@code supplier}.
130 *
131 * <p>The usage interface is designed as a {@code from} supplier which
132 * propagates its result to the {@code to} function.</p>
133 *
134 * @param <F> the {@code from} or <em>source</em> type
135 * @param <T> the {@code to} or <em>target</em> type
136 * @param fromSupplier the {@code from} or <em>source</em> {@code supplier}
137 * @param toFunction the {@code to} or <em>target</em> {@code function}
138 * @return a {@code supplier} with the value from {@code function}
139 * @throws IllegalArgumentException if one parameter is {@code null}
140 * @since 0.7.0
141 */
142 public final static <F, T> Supplier<T> compose(
143 final Supplier<? extends F> fromSupplier,
144 final Function<F, T> toFunction) {
145 return new SupplierFunctionComposition<F, T>(fromSupplier, toFunction);
146 }
147
148 /** @see #compose(Supplier, Function) */
149 private final static class SupplierFunctionComposition<F, T>
150 implements Supplier<T> {
151
152 private final Supplier<? extends F> from;
153 private final Function<? super F, ? extends T> to;
154
155 /**
156 * Constructs the composition of the given {@code Supplier} and
157 * {@code Function}.
158 *
159 * @param fromSupplier the inner {@link Supplier}. Must not be {@code null}.
160 * @param toFunction the outer {@link Function}. Must not be {@code null}.
161 */
162 @SuppressWarnings("nls")
163 public SupplierFunctionComposition(final Supplier<? extends F> fromSupplier,
164 final Function<F, T> toFunction) {
165 this.from = checkArgumentNotNull(fromSupplier, "fromSupplier is null");
166 this.to = checkArgumentNotNull(toFunction, "toFunction is null");
167 }
168
169 /** {@inheritDoc} */
170 public T get() {
171 return this.to.apply(this.from.get());
172 }
173 }
174
175 /**
176 * Composes a rule. A rule contains a {@code predicate} as decision maker either to call the
177 * {@code trueFunction} or the {@code falseFunction}. The returning function calls the
178 * {@code trueFunction} if {@code predicate} returns {@code true}. Otherwise the
179 * {@code falseFunction} will call.
180 * @param <F> the input type of the {@code predicate} and the {@code functions}
181 * @param <T> the output type of the applyied {@code functions}
182 * @param decider the decision maker
183 * @param trueFunction apply if the decision maker returns {@code true}
184 * @param falseFunction apply if the decision maker returns {@code false}
185 * @return a ruling function
186 * @since 0.8.1
187 */
188 public final static <F, T> Function<F, T> composeRule(
189 final Predicate<? super F> decider,
190 final Function<? super F, ? extends T> trueFunction,
191 final Function<? super F, ? extends T> falseFunction) {
192 return new RuledFunctionComposition<F, T>(decider, trueFunction, falseFunction);
193 }
194
195 /** @see #compose(Predicate, Function, Function) */
196 private static class RuledFunctionComposition<F, T> implements Function<F, T> {
197 /** The <em>trueFunction</em> will aplly if {@link #decisionMaker} returns {@code true}. */
198 private final Function<? super F, ? extends T> trueFunction;
199
200 /** The <em>falseFunction</em> will aplly if {@link #decisionMaker} returns {@code false}. */
201 private final Function<? super F, ? extends T> falseFunction;
202
203 /** Descider either call <em>trueFunction</em> or <em>falseFunction</em>. */
204 private final Predicate<? super F> decisionMaker;
205
206 /**
207 * Constructs the composition of the given {@link Predicate} and {@link Function Functions}.
208 *
209 * @param decisionMaker the predicate which decision is the source for using the
210 * <em>trueFunction</em> or the <em>falseFunction</em>
211 * @param trueFunction the {@link Function} will call if {@code decisionMaker}
212 * returns {@code true}
213 * @param falseFunction the {@link Function} will call if {@code decisionMaker}
214 * returns {@code false}
215 */
216 @SuppressWarnings("nls")
217 public RuledFunctionComposition(
218 @SuppressWarnings("hiding") final Predicate<? super F> decisionMaker,
219 @SuppressWarnings("hiding") final Function<? super F, ? extends T> trueFunction,
220 @SuppressWarnings("hiding") final Function<? super F, ? extends T> falseFunction) {
221 this.decisionMaker = checkArgumentNotNull(decisionMaker, "decisionMaker is null");
222 this.trueFunction = checkArgumentNotNull(trueFunction, "trueFunction is null");
223 this.falseFunction = checkArgumentNotNull(falseFunction, "falseFunction is null");
224 }
225
226 /** {@inheritDoc} */
227 public T apply(final F source) {
228 if (this.decisionMaker.evaluate(source)) {
229 return this.trueFunction.apply(source);
230 }
231 return this.falseFunction.apply(source);
232 }
233 }
234
235 /** Never used. */
236 private Compositions() { }
237 }