1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.functor.core.composite;
18
19 import java.io.Serializable;
20
21 import org.apache.commons.functor.UnaryFunction;
22
23 /**
24 * A {@link UnaryFunction UnaryFunction}
25 * representing the composition of
26 * {@link UnaryFunction UnaryFunctions},
27 * "chaining" the output of one to the input
28 * of another. For example,
29 * <pre>new CompositeUnaryFunction(f).of(g)</pre>
30 * {@link #evaluate evaluates} to
31 * <code>f.evaluate(g.evaluate(obj))</code>, and
32 * <pre>new CompositeUnaryFunction(f).of(g).of(h)</pre>
33 * {@link #evaluate evaluates} to
34 * <code>f.evaluate(g.evaluate(h.evaluate(obj)))</code>.
35 * <p>
36 * When the collection is empty, this function is
37 * an identity function.
38 * </p>
39 * <p>
40 * Note that although this class implements
41 * {@link Serializable}, a given instance will
42 * only be truly <code>Serializable</code> if all the
43 * underlying functors are. Attempts to serialize
44 * an instance whose delegates are not all
45 * <code>Serializable</code> will result in an exception.
46 * </p>
47 * @version $Revision: 1171157 $ $Date: 2011-09-15 18:04:31 +0200 (Thu, 15 Sep 2011) $
48 * @author Rodney Waldhoff
49 * @author Matt Benson
50 */
51 public class CompositeUnaryFunction<A, T> implements UnaryFunction<A, T>, Serializable {
52
53 /**
54 * serialVersionUID declaration.
55 */
56 private static final long serialVersionUID = 4945193629275757281L;
57
58 /** Base hash integer used to shift hash */
59 private static final int HASH_SHIFT = 4;
60
61 /**
62 * Encapsulates a double function evaluation.
63 * @param <A> argument type
64 * @param <X> intermediate type
65 * @param <T> return type
66 */
67 private static class Helper<X, A, T> implements UnaryFunction<A, T>, Serializable {
68 /**
69 * serialVersionUID declaration.
70 */
71 private static final long serialVersionUID = 8167255331321876718L;
72 private UnaryFunction<? super X, ? extends T> following;
73 private UnaryFunction<? super A, ? extends X> preceding;
74
75 /**
76 * Create a new Helper.
77 * @param following UnaryFunction<X, Y>
78 * @param preceding UnaryFunction<Y, Z>
79 */
80 public Helper(UnaryFunction<? super X, ? extends T> following,
81 UnaryFunction<? super A, ? extends X> preceding) {
82 this.following = following;
83 this.preceding = preceding;
84 }
85
86 /**
87 * {@inheritDoc}
88 */
89 public T evaluate(A obj) {
90 return following.evaluate(preceding.evaluate(obj));
91 }
92
93 /**
94 * {@inheritDoc}
95 */
96 @Override
97 public boolean equals(Object obj) {
98 return obj == this || obj instanceof Helper<?, ?, ?> && equals((Helper<?, ?, ?>) obj);
99 }
100
101 private boolean equals(Helper<?, ?, ?> helper) {
102 return helper.following.equals(following) && helper.preceding.equals(preceding);
103 }
104
105 /**
106 * {@inheritDoc}
107 */
108 @Override
109 public int hashCode() {
110 int result = "CompositeUnaryFunction$Helper".hashCode();
111 result <<= 2;
112 result |= following.hashCode();
113 result <<= 2;
114 result |= preceding.hashCode();
115 return result;
116 }
117
118 /**
119 * {@inheritDoc}
120 */
121 @Override
122 public String toString() {
123 return following.toString() + " of " + preceding.toString();
124 }
125 }
126
127 private final UnaryFunction<? super A, ? extends T> function;
128
129 /**
130 * Create a new CompositeUnaryFunction.
131 * @param function UnaryFunction to call
132 */
133 public CompositeUnaryFunction(UnaryFunction<? super A, ? extends T> function) {
134 if (function == null) {
135 throw new IllegalArgumentException("function must not be null");
136 }
137 this.function = function;
138 }
139
140 private <X> CompositeUnaryFunction(UnaryFunction<? super X, ? extends T> following,
141 UnaryFunction<? super A, ? extends X> preceding) {
142 this.function = new Helper<X, A, T>(following, preceding);
143 }
144
145 /**
146 * {@inheritDoc}
147 */
148 public final T evaluate(A obj) {
149 return function.evaluate(obj);
150 }
151
152 /**
153 * Fluently obtain a CompositeUnaryFunction that is "this function" applied to the specified preceding function.
154 * @param <P> argument type of the resulting function.
155 * @param preceding UnaryFunction
156 * @return CompositeUnaryFunction<P, T>
157 */
158 public final <P> CompositeUnaryFunction<P, T> of(UnaryFunction<? super P, ? extends A> preceding) {
159 if (preceding == null) {
160 throw new IllegalArgumentException("preceding function was null");
161 }
162 return new CompositeUnaryFunction<P, T>(function, preceding);
163 }
164
165 /**
166 * {@inheritDoc}
167 */
168 public final boolean equals(Object that) {
169 return that == this
170 || (that instanceof CompositeUnaryFunction<?, ?> && equals((CompositeUnaryFunction<?, ?>) that));
171 }
172
173 /**
174 * Learn whether another CompositeUnaryFunction is equal to this.
175 * @param that CompositeUnaryFunction to test
176 * @return boolean
177 */
178 public final boolean equals(CompositeUnaryFunction<?, ?> that) {
179 // by construction, list is never null
180 return null != that && function.equals(that.function);
181 }
182
183 /**
184 * {@inheritDoc}
185 */
186 public int hashCode() {
187 // by construction, list is never null
188 return ("CompositeUnaryFunction".hashCode() << HASH_SHIFT) ^ function.hashCode();
189 }
190
191 /**
192 * {@inheritDoc}
193 */
194 public String toString() {
195 return "CompositeUnaryFunction<" + function + ">";
196 }
197
198 }