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}