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.algorithm;
018
019import org.apache.commons.functor.BinaryFunction;
020import org.apache.commons.functor.Function;
021import org.apache.commons.functor.Procedure;
022import org.apache.commons.functor.generator.Generator;
023
024/**
025 * Functional left-fold algorithm against the elements of a {@link Generator}.
026 * Uses the seed object (if supplied) as the initial left-side argument to the {@link BinaryFunction},
027 * then uses the result of that evaluation as the next left-side argument, until the {@link Generator}'s
028 * elements have been expended.
029 *
030 * @param <T> the returned evaluation type.
031 * @version $Revision: 1537906 $ $Date: 2013-11-01 12:47:33 +0100 (Fr, 01 Nov 2013) $
032 */
033public class FoldLeft<T> implements Function<Generator<T>, T>, BinaryFunction<Generator<T>, T, T> {
034
035    /**
036     * Helper procedure.
037     *
038     * @param <T> the returned evaluation type.
039     */
040    private static class FoldLeftHelper<T> implements Procedure<T> {
041        /**
042         * The wrapped function.
043         */
044        private final BinaryFunction<? super T, ? super T, ? extends T> function;
045        /**
046         * The seed object.
047         */
048        private T seed;
049        /**
050         * Flag to check the helper started or not.
051         */
052        private boolean started;
053
054        /**
055         * Create a seedless FoldLeftHelper.
056         *
057         * @param function The wrapped function
058         */
059        public FoldLeftHelper(BinaryFunction<? super T, ? super T, ? extends T> function) {
060            this(null, function);
061        }
062
063        /**
064         * Create a new FoldLeftHelper.
065         *
066         * @param seed initial left-side argument
067         * @param function The wrapped function
068         */
069        FoldLeftHelper(T seed, BinaryFunction<? super T, ? super T, ? extends T> function) {
070            this.seed = seed;
071            started = seed != null ? true : false;
072            this.function = function;
073        }
074
075        /**
076         * {@inheritDoc}
077         */
078        public void run(T obj) {
079            if (!started) {
080                seed = obj;
081                started = true;
082            } else {
083                seed = function.evaluate(seed, obj);
084            }
085        }
086
087        /**
088         * Get current result.
089         * @return Object
090         */
091        T getResult() {
092            return started ? seed : null;
093        }
094
095    }
096
097    /**
098     * {@link BinaryFunction} to apply to each (seed, next).
099     */
100    private final BinaryFunction<? super T, ? super T, ? extends T> function;
101
102    /**
103     * Create a new FoldLeft.
104     * @param func {@link BinaryFunction} to apply to each (seed, next)
105     */
106    public FoldLeft(BinaryFunction<? super T, ? super T, ? extends T> func) {
107        this.function = func;
108    }
109
110    /**
111     * {@inheritDoc}
112     * @param obj {@link Generator} to transform
113     */
114    public final T evaluate(Generator<T> obj) {
115        FoldLeftHelper<T> helper = new FoldLeftHelper<T>(function);
116        obj.run(helper);
117        return helper.getResult();
118    }
119
120    /**
121     * {@inheritDoc}
122     * @param left {@link Generator} to transform
123     * @param right initial left-side seed object
124     */
125    public final T evaluate(Generator<T> left, T right) {
126        FoldLeftHelper<T> helper = new FoldLeftHelper<T>(right, function);
127        left.run(helper);
128        return helper.getResult();
129    }
130
131    /**
132     * {@inheritDoc}
133     */
134    @Override
135    public boolean equals(Object obj) {
136        if (obj == this) {
137            return true;
138        }
139        if (!(obj instanceof FoldLeft<?>)) {
140            return false;
141        }
142        return ((FoldLeft<?>) obj).function.equals(function);
143    }
144
145    /**
146     * {@inheritDoc}
147     */
148    @Override
149    public int hashCode() {
150        return "FoldLeft".hashCode() << 2 ^ function.hashCode();
151    }
152
153    /**
154     * {@inheritDoc}
155     */
156    @Override
157    public String toString() {
158        return "FoldLeft<" + function + ">";
159    }
160
161}