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.BinaryFunction;
22  import org.apache.commons.functor.UnaryFunction;
23  import org.apache.commons.lang3.Validate;
24  
25  /**
26   * A {@link BinaryFunction BinaryFunction} composed of
27   * one binary function, <i>f</i>, and two unary
28   * functions, <i>g</i> and <i>h</i>,
29   * evaluating the ordered parameters <i>x</i>, <i>y</i>
30   * to <code><i>f</i>(<i>g</i>(<i>x</i>),<i>h</i>(<i>y</i>))</code>.
31   * <p>
32   * Note that although this class implements
33   * {@link Serializable}, a given instance will
34   * only be truly <code>Serializable</code> if all the
35   * underlying functors are.  Attempts to serialize
36   * an instance whose delegates are not all
37   * <code>Serializable</code> will result in an exception.
38   * </p>
39   * @param <L> the left argument type.
40   * @param <R> the right argument type.
41   * @param <T> the returned value type.
42   * @version $Revision: 1345136 $ $Date: 2012-06-01 09:47:06 -0300 (Fri, 01 Jun 2012) $
43   */
44  public class UnaryCompositeBinaryFunction<L, R, T> implements BinaryFunction<L, R, T>, Serializable {
45  
46      /**
47       * serialVersionUID declaration.
48       */
49      private static final long serialVersionUID = 264219357293822629L;
50  
51      /** Base hash integer used to shift hash. */
52      private static final int HASH_SHIFT = 4;
53  
54      /**
55       *
56       *
57       * @param <G> the adapted function left argument type.
58       * @param <H> the adapted function right argument type.
59       * @param <L> the left argument type.
60       * @param <R> the right argument type.
61       * @param <T> the returned value type.
62       */
63      private static class Helper<G, H, L, R, T> implements BinaryFunction<L, R, T>, Serializable {
64          /**
65           * serialVersionUID declaration.
66           */
67          private static final long serialVersionUID = 4513309646430305164L;
68          /**
69           * The adapted function to receive <code>(output(g), output(h))</code>.
70           */
71          private BinaryFunction<? super G, ? super H, ? extends T> f;
72          /**
73           * The adapted left function.
74           */
75          private UnaryFunction<? super L, ? extends G> g;
76          /**
77           * The adapted right function.
78           */
79          private UnaryFunction<? super R, ? extends H> h;
80  
81          /**
82           * Create a new Helper.
83           * @param f BinaryFunction to receive <code>(output(g), output(h))</code>
84           * @param g left UnaryFunction
85           * @param h right UnaryFunction
86           */
87          public Helper(BinaryFunction<? super G, ? super H, ? extends T> f, UnaryFunction<? super L, ? extends G> g,
88                  UnaryFunction<? super R, ? extends H> h) {
89              this.f = f;
90              this.g = g;
91              this.h = h;
92          }
93  
94          /**
95           * {@inheritDoc}
96           */
97          public T evaluate(L left, R right) {
98              return f.evaluate(g.evaluate(left), h.evaluate(right));
99          }
100     }
101 
102     /**
103      * The adapted helper.
104      */
105     private final Helper<?, ?, L, R, T> helper;
106 
107     // constructor
108     // ------------------------------------------------------------------------
109     /**
110      * Create a new UnaryCompositeBinaryFunction.
111      *
112      * @param <G> the adapted function left argument type.
113      * @param <H> the adapted function right argument type.
114      * @param f BinaryFunction to receive <code>(output(g), output(h))</code>
115      * @param g left UnaryFunction
116      * @param h right UnaryFunction
117      */
118     public <G, H> UnaryCompositeBinaryFunction(BinaryFunction<? super G, ? super H, ? extends T> f,
119             UnaryFunction<? super L, ? extends G> g, UnaryFunction<? super R, ? extends H> h) {
120         this.helper = new Helper<G, H, L, R, T>(
121                 Validate.notNull(f, "BinaryFunction must not be null"),
122                 Validate.notNull(g, "left UnaryFunction must not be null"),
123                 Validate.notNull(h, "right UnaryFunction must not be null")
124         );
125     }
126 
127     // function interface
128     // ------------------------------------------------------------------------
129     /**
130      * {@inheritDoc}
131      */
132     public T evaluate(L left, R right) {
133         return helper.evaluate(left, right);
134     }
135 
136     /**
137      * {@inheritDoc}
138      */
139     @Override
140     public boolean equals(Object that) {
141         return that == this || (that instanceof UnaryCompositeBinaryFunction<?, ?, ?>
142                                     && equals((UnaryCompositeBinaryFunction<?, ?, ?>) that));
143     }
144 
145     /**
146      * Learn whether a given UnaryCompositeBinaryFunction is equal to this.
147      * @param that UnaryCompositeBinaryFunction to test
148      * @return boolean
149      */
150     public boolean equals(UnaryCompositeBinaryFunction<?, ?, ?> that) {
151         return null != that
152                 && helper.f.equals(that.helper.f)
153                 && helper.g.equals(that.helper.g)
154                 && helper.h.equals(that.helper.h);
155     }
156 
157     /**
158      * {@inheritDoc}
159      */
160     @Override
161     public int hashCode() {
162         int hash = "UnaryCompositeBinaryFunction".hashCode();
163         hash <<= HASH_SHIFT;
164         hash ^= helper.f.hashCode();
165         hash <<= HASH_SHIFT;
166         hash ^= helper.g.hashCode();
167         hash <<= HASH_SHIFT;
168         hash ^= helper.h.hashCode();
169         return hash;
170     }
171 
172     /**
173      * {@inheritDoc}
174      */
175     @Override
176     public String toString() {
177         return "UnaryCompositeBinaryFunction<" + helper.f + ";" + helper.g + ";" + helper.h + ">";
178     }
179 
180 }