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.UnaryFunction; 022 023 /** 024 * A {@link UnaryFunction UnaryFunction} 025 * representing the composition of 026 * {@link UnaryFunction UnaryFunctions}, 027 * "chaining" the output of one to the input 028 * of another. For example, 029 * <pre>new CompositeUnaryFunction(f).of(g)</pre> 030 * {@link #evaluate evaluates} to 031 * <code>f.evaluate(g.evaluate(obj))</code>, and 032 * <pre>new CompositeUnaryFunction(f).of(g).of(h)</pre> 033 * {@link #evaluate evaluates} to 034 * <code>f.evaluate(g.evaluate(h.evaluate(obj)))</code>. 035 * <p> 036 * When the collection is empty, this function is 037 * an identity function. 038 * </p> 039 * <p> 040 * Note that although this class implements 041 * {@link Serializable}, a given instance will 042 * only be truly <code>Serializable</code> if all the 043 * underlying functors are. Attempts to serialize 044 * an instance whose delegates are not all 045 * <code>Serializable</code> will result in an exception. 046 * </p> 047 * @version $Revision: 1171157 $ $Date: 2011-09-15 18:04:31 +0200 (Thu, 15 Sep 2011) $ 048 * @author Rodney Waldhoff 049 * @author Matt Benson 050 */ 051 public class CompositeUnaryFunction<A, T> implements UnaryFunction<A, T>, Serializable { 052 053 /** 054 * serialVersionUID declaration. 055 */ 056 private static final long serialVersionUID = 4945193629275757281L; 057 058 /** Base hash integer used to shift hash */ 059 private static final int HASH_SHIFT = 4; 060 061 /** 062 * Encapsulates a double function evaluation. 063 * @param <A> argument type 064 * @param <X> intermediate type 065 * @param <T> return type 066 */ 067 private static class Helper<X, A, T> implements UnaryFunction<A, T>, Serializable { 068 /** 069 * serialVersionUID declaration. 070 */ 071 private static final long serialVersionUID = 8167255331321876718L; 072 private UnaryFunction<? super X, ? extends T> following; 073 private UnaryFunction<? super A, ? extends X> preceding; 074 075 /** 076 * Create a new Helper. 077 * @param following UnaryFunction<X, Y> 078 * @param preceding UnaryFunction<Y, Z> 079 */ 080 public Helper(UnaryFunction<? super X, ? extends T> following, 081 UnaryFunction<? super A, ? extends X> preceding) { 082 this.following = following; 083 this.preceding = preceding; 084 } 085 086 /** 087 * {@inheritDoc} 088 */ 089 public T evaluate(A obj) { 090 return following.evaluate(preceding.evaluate(obj)); 091 } 092 093 /** 094 * {@inheritDoc} 095 */ 096 @Override 097 public boolean equals(Object obj) { 098 return obj == this || obj instanceof Helper<?, ?, ?> && equals((Helper<?, ?, ?>) obj); 099 } 100 101 private boolean equals(Helper<?, ?, ?> helper) { 102 return helper.following.equals(following) && helper.preceding.equals(preceding); 103 } 104 105 /** 106 * {@inheritDoc} 107 */ 108 @Override 109 public int hashCode() { 110 int result = "CompositeUnaryFunction$Helper".hashCode(); 111 result <<= 2; 112 result |= following.hashCode(); 113 result <<= 2; 114 result |= preceding.hashCode(); 115 return result; 116 } 117 118 /** 119 * {@inheritDoc} 120 */ 121 @Override 122 public String toString() { 123 return following.toString() + " of " + preceding.toString(); 124 } 125 } 126 127 private final UnaryFunction<? super A, ? extends T> function; 128 129 /** 130 * Create a new CompositeUnaryFunction. 131 * @param function UnaryFunction to call 132 */ 133 public CompositeUnaryFunction(UnaryFunction<? super A, ? extends T> function) { 134 if (function == null) { 135 throw new IllegalArgumentException("function must not be null"); 136 } 137 this.function = function; 138 } 139 140 private <X> CompositeUnaryFunction(UnaryFunction<? super X, ? extends T> following, 141 UnaryFunction<? super A, ? extends X> preceding) { 142 this.function = new Helper<X, A, T>(following, preceding); 143 } 144 145 /** 146 * {@inheritDoc} 147 */ 148 public final T evaluate(A obj) { 149 return function.evaluate(obj); 150 } 151 152 /** 153 * Fluently obtain a CompositeUnaryFunction that is "this function" applied to the specified preceding function. 154 * @param <P> argument type of the resulting function. 155 * @param preceding UnaryFunction 156 * @return CompositeUnaryFunction<P, T> 157 */ 158 public final <P> CompositeUnaryFunction<P, T> of(UnaryFunction<? super P, ? extends A> preceding) { 159 if (preceding == null) { 160 throw new IllegalArgumentException("preceding function was null"); 161 } 162 return new CompositeUnaryFunction<P, T>(function, preceding); 163 } 164 165 /** 166 * {@inheritDoc} 167 */ 168 public final boolean equals(Object that) { 169 return that == this 170 || (that instanceof CompositeUnaryFunction<?, ?> && equals((CompositeUnaryFunction<?, ?>) that)); 171 } 172 173 /** 174 * Learn whether another CompositeUnaryFunction is equal to this. 175 * @param that CompositeUnaryFunction to test 176 * @return boolean 177 */ 178 public final boolean equals(CompositeUnaryFunction<?, ?> that) { 179 // by construction, list is never null 180 return null != that && function.equals(that.function); 181 } 182 183 /** 184 * {@inheritDoc} 185 */ 186 public int hashCode() { 187 // by construction, list is never null 188 return ("CompositeUnaryFunction".hashCode() << HASH_SHIFT) ^ function.hashCode(); 189 } 190 191 /** 192 * {@inheritDoc} 193 */ 194 public String toString() { 195 return "CompositeUnaryFunction<" + function + ">"; 196 } 197 198 }