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