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.algorithm;
018    
019    import java.io.Serializable;
020    
021    import org.apache.commons.functor.BinaryFunction;
022    import org.apache.commons.functor.UnaryFunction;
023    import org.apache.commons.functor.UnaryProcedure;
024    import org.apache.commons.functor.generator.Generator;
025    
026    /**
027     * Functional left-fold algorithm against the elements of a {@link Generator}.
028     * Uses the seed object (if supplied) as the initial left-side argument to the {@link BinaryFunction},
029     * then uses the result of that evaluation as the next left-side argument, until the {@link Generator}'s
030     * elements have been expended.
031     *
032     * @param <T> the returned evaluation type.
033     * @version $Revision: 1171154 $ $Date: 2011-09-15 17:58:38 +0200 (Thu, 15 Sep 2011) $
034     */
035    public class FoldLeft<T> implements UnaryFunction<Generator<T>, T>, BinaryFunction<Generator<T>, T, T>, Serializable {
036    
037        /**
038         * serialVersionUID declaration.
039         */
040        private static final long serialVersionUID = 2473542974105910450L;
041    
042        /**
043         * Helper procedure.
044         */
045        private static class FoldLeftHelper<T> implements UnaryProcedure<T> {
046            private final BinaryFunction<? super T, ? super T, ? extends T> function;
047            private T seed;
048            private boolean started;
049    
050            /**
051             * Create a seedless FoldLeftHelper.
052             */
053            public FoldLeftHelper(BinaryFunction<? super T, ? super T, ? extends T> function) {
054                this(null, function);
055            }
056    
057            /**
058             * Create a new FoldLeftHelper.
059             * @param seed initial left-side argument
060             */
061            FoldLeftHelper(T seed, BinaryFunction<? super T, ? super T, ? extends T> function) {
062                this.seed = seed;
063                started = seed != null ? true : false;
064                this.function = function;
065            }
066    
067            /**
068             * {@inheritDoc}
069             */
070            public void run(T obj) {
071                if (!started) {
072                    seed = obj;
073                    started = true;
074                } else {
075                    seed = function.evaluate(seed, obj);
076                }
077            }
078    
079            /**
080             * Get current result.
081             * @return Object
082             */
083            T getResult() {
084                return started ? seed : null;
085            }
086    
087        }
088    
089        private final BinaryFunction<? super T, ? super T, ? extends T> function;
090    
091        /**
092         * Create a new FoldLeft.
093         * @param func {@link BinaryFunction} to apply to each (seed, next)
094         */
095        public FoldLeft(BinaryFunction<? super T, ? super T, ? extends T> func) {
096            this.function = func;
097        }
098    
099        /**
100         * {@inheritDoc}
101         * @param obj {@link Generator} to transform
102         */
103        public final T evaluate(Generator<T> obj) {
104            FoldLeftHelper<T> helper = new FoldLeftHelper<T>(function);
105            obj.run(helper);
106            return helper.getResult();
107        }
108    
109        /**
110         * {@inheritDoc}
111         * @param left {@link Generator} to transform
112         * @param right initial left-side seed object
113         */
114        public final T evaluate(Generator<T> left, T right) {
115            FoldLeftHelper<T> helper = new FoldLeftHelper<T>(right, function);
116            left.run(helper);
117            return helper.getResult();
118        }
119    
120        /**
121         * {@inheritDoc}
122         */
123        public boolean equals(Object obj) {
124            if (obj == this) {
125                return true;
126            }
127            if (!(obj instanceof FoldLeft<?>)) {
128                return false;
129            }
130            return ((FoldLeft<?>) obj).function.equals(function);
131        }
132    
133        /**
134         * {@inheritDoc}
135         */
136        public int hashCode() {
137            return "FoldLeft".hashCode() << 2 ^ function.hashCode();
138        }
139    
140    }