001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.functor.core.composite;
018    
019    import java.io.Serializable;
020    
021    import org.apache.commons.functor.BinaryFunction;
022    import org.apache.commons.functor.UnaryFunction;
023    
024    /**
025     * A {@link BinaryFunction BinaryFunction} composed of
026     * one binary function, <i>f</i>, and two unary
027     * functions, <i>g</i> and <i>h</i>,
028     * evaluating the ordered parameters <i>x</i>, <i>y</i>
029     * to <code><i>f</i>(<i>g</i>(<i>x</i>),<i>h</i>(<i>y</i>))</code>.
030     * <p>
031     * Note that although this class implements
032     * {@link Serializable}, a given instance will
033     * only be truly <code>Serializable</code> if all the
034     * underlying functors are.  Attempts to serialize
035     * an instance whose delegates are not all
036     * <code>Serializable</code> will result in an exception.
037     * </p>
038     * @version $Revision: 1156337 $ $Date: 2011-08-10 21:44:54 +0200 (Wed, 10 Aug 2011) $
039     * @author Rodney Waldhoff
040     */
041    public class UnaryCompositeBinaryFunction<L, R, T> implements BinaryFunction<L, R, T>, Serializable {
042    
043        /**
044         * serialVersionUID declaration.
045         */
046        private static final long serialVersionUID = 264219357293822629L;
047    
048        private static class Helper<G, H, L, R, T> implements BinaryFunction<L, R, T>, Serializable {
049            /**
050             * serialVersionUID declaration.
051             */
052            private static final long serialVersionUID = 4513309646430305164L;
053            private BinaryFunction<? super G, ? super H, ? extends T> f;
054            private UnaryFunction<? super L, ? extends G> g;
055            private UnaryFunction<? super R, ? extends H> h;
056    
057            /**
058             * Create a new Helper.
059             * @param f BinaryFunction to receive <code>(output(g), output(h))</code>
060             * @param g left UnaryFunction
061             * @param h right UnaryFunction
062             */
063            public Helper(BinaryFunction<? super G, ? super H, ? extends T> f, UnaryFunction<? super L, ? extends G> g,
064                    UnaryFunction<? super R, ? extends H> h) {
065                this.f = f;
066                this.g = g;
067                this.h = h;
068            }
069    
070            /**
071             * {@inheritDoc}
072             */
073            public T evaluate(L left, R right) {
074                return f.evaluate(g.evaluate(left), h.evaluate(right));
075            }
076        }
077    
078        private final Helper<?, ?, L, R, T> helper;
079    
080        // constructor
081        // ------------------------------------------------------------------------
082        /**
083         * Create a new UnaryCompositeBinaryFunction.
084         * @param f BinaryFunction to receive <code>(output(g), output(h))</code>
085         * @param g left UnaryFunction
086         * @param h right UnaryFunction
087         */
088        public <G, H> UnaryCompositeBinaryFunction(BinaryFunction<? super G, ? super H, ? extends T> f,
089                UnaryFunction<? super L, ? extends G> g, UnaryFunction<? super R, ? extends H> h) {
090            if (f == null) {
091                throw new IllegalArgumentException("BinaryFunction must not be null");
092            }
093            if (g == null || h == null) {
094                throw new IllegalArgumentException("Left and right UnaryFunctions may not be null");
095            }
096            this.helper = new Helper<G, H, L, R, T>(f, g, h);
097        }
098    
099        // function interface
100        // ------------------------------------------------------------------------
101        /**
102         * {@inheritDoc}
103         */
104        public T evaluate(L left, R right) {
105            return helper.evaluate(left, right);
106        }
107    
108        /**
109         * {@inheritDoc}
110         */
111        public boolean equals(Object that) {
112            return that == this || (that instanceof UnaryCompositeBinaryFunction<?, ?, ?>
113                                        && equals((UnaryCompositeBinaryFunction<?, ?, ?>) that));
114        }
115    
116        /**
117         * Learn whether a given UnaryCompositeBinaryFunction is equal to this.
118         * @param that UnaryCompositeBinaryFunction to test
119         * @return boolean
120         */
121        public boolean equals(UnaryCompositeBinaryFunction<?, ?, ?> that) {
122            return null != that
123                    && helper.f.equals(that.helper.f)
124                    && helper.g.equals(that.helper.g)
125                    && helper.h.equals(that.helper.h);
126        }
127    
128        /**
129         * {@inheritDoc}
130         */
131        public int hashCode() {
132            int hash = "UnaryCompositeBinaryFunction".hashCode();
133            hash <<= 4;
134            hash ^= helper.f.hashCode();
135            hash <<= 4;
136            hash ^= helper.g.hashCode();
137            hash <<= 4;
138            hash ^= helper.h.hashCode();
139            return hash;
140        }
141    
142        /**
143         * {@inheritDoc}
144         */
145        public String toString() {
146            return "UnaryCompositeBinaryFunction<" + helper.f + ";" + helper.g + ";" + helper.h + ">";
147        }
148    
149    }