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 */
017package org.apache.commons.functor.core.composite;
018
019import org.apache.commons.functor.BinaryFunction;
020import org.apache.commons.functor.Function;
021import org.apache.commons.lang3.Validate;
022
023/**
024 * A BinaryFunction whose result is then run through a Function.
025 *
026 * @param <L> the left argument type.
027 * @param <R> the right argument type.
028 * @param <T> the returned value type.
029 * @version $Revision: 1537602 $ $Date: 2013-10-31 20:53:09 +0100 (Do, 31 Okt 2013) $
030 */
031public class TransformedBinaryFunction<L, R, T> implements BinaryFunction<L, R, T> {
032    /**
033     * Type-remembering helper.
034     *
035     * @param <X> the following function left argument.
036     */
037    private static final class Helper<X, L, R, T> implements BinaryFunction<L, R, T> {
038        /**
039         * The preceding function.
040         */
041        private BinaryFunction<? super L, ? super R, ? extends X> preceding;
042        /**
043         * The following function.
044         */
045        private Function<? super X, ? extends T> following;
046
047        /**
048         * Create a new Helper.
049         * @param preceding BinaryFunction
050         * @param following Function
051         */
052        private Helper(BinaryFunction<? super L, ? super R, ? extends X> preceding,
053                Function<? super X, ? extends T> following) {
054            this.preceding = Validate.notNull(preceding, "BinaryFunction argument was null");
055            this.following = Validate.notNull(following, "Function argument was null");
056        }
057
058        /**
059         * {@inheritDoc}
060         */
061        public T evaluate(L left, R right) {
062            return following.evaluate(preceding.evaluate(left, right));
063        }
064    }
065
066    /**
067     * The adapted helper.
068     */
069    private final Helper<?, L, R, T> helper;
070
071    /**
072     * Create a new TransformedBinaryFunction.
073     * @param <X> the following function left argument.
074     * @param preceding BinaryFunction
075     * @param following Function
076     */
077    public <X> TransformedBinaryFunction(BinaryFunction<? super L, ? super R, ? extends X> preceding,
078            Function<? super X, ? extends T> following) {
079        this.helper = new Helper<X, L, R, T>(preceding, following);
080    }
081
082    /**
083     * {@inheritDoc}
084     */
085    public final T evaluate(L left, R right) {
086        return helper.evaluate(left, right);
087    }
088
089    /**
090     * {@inheritDoc}
091     */
092    @Override
093    public final boolean equals(Object obj) {
094        if (obj == this) {
095            return true;
096        }
097        if (!(obj instanceof TransformedBinaryFunction<?, ?, ?>)) {
098            return false;
099        }
100        TransformedBinaryFunction<?, ?, ?> that = (TransformedBinaryFunction<?, ?, ?>) obj;
101        return this.helper.preceding.equals(that.helper.preceding)
102                && this.helper.following.equals(that.helper.following);
103    }
104
105    /**
106     * {@inheritDoc}
107     */
108    @Override
109    public int hashCode() {
110        int result = "TransformedBinaryFunction".hashCode();
111        result <<= 2;
112        result |= helper.following.hashCode();
113        result <<= 2;
114        result |= helper.preceding.hashCode();
115        return result;
116    }
117
118    /**
119     * {@inheritDoc}
120     */
121    @Override
122    public String toString() {
123        return "TransformedBinaryFunction<" + helper.preceding + "; " + helper.following + ">";
124    }
125}