Mercurial > lasercutter
diff src/clojure/lang/MultiFn.java @ 10:ef7dbbd6452c
added clojure source goodness
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 21 Aug 2010 06:25:44 -0400 |
parents | |
children |
line wrap: on
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/clojure/lang/MultiFn.java Sat Aug 21 06:25:44 2010 -0400 1.3 @@ -0,0 +1,314 @@ 1.4 +/** 1.5 + * Copyright (c) Rich Hickey. All rights reserved. 1.6 + * The use and distribution terms for this software are covered by the 1.7 + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 1.8 + * which can be found in the file epl-v10.html at the root of this distribution. 1.9 + * By using this software in any fashion, you are agreeing to be bound by 1.10 + * the terms of this license. 1.11 + * You must not remove this notice, or any other, from this software. 1.12 + **/ 1.13 + 1.14 +/* rich Sep 13, 2007 */ 1.15 + 1.16 +package clojure.lang; 1.17 + 1.18 +import java.util.Map; 1.19 + 1.20 +public class MultiFn extends AFn{ 1.21 +final public IFn dispatchFn; 1.22 +final public Object defaultDispatchVal; 1.23 +final public IRef hierarchy; 1.24 +final String name; 1.25 +IPersistentMap methodTable; 1.26 +IPersistentMap preferTable; 1.27 +IPersistentMap methodCache; 1.28 +Object cachedHierarchy; 1.29 + 1.30 +static final Var assoc = RT.var("clojure.core", "assoc"); 1.31 +static final Var dissoc = RT.var("clojure.core", "dissoc"); 1.32 +static final Var isa = RT.var("clojure.core", "isa?"); 1.33 +static final Var parents = RT.var("clojure.core", "parents"); 1.34 + 1.35 +public MultiFn(String name, IFn dispatchFn, Object defaultDispatchVal, IRef hierarchy) throws Exception{ 1.36 + this.name = name; 1.37 + this.dispatchFn = dispatchFn; 1.38 + this.defaultDispatchVal = defaultDispatchVal; 1.39 + this.methodTable = PersistentHashMap.EMPTY; 1.40 + this.methodCache = getMethodTable(); 1.41 + this.preferTable = PersistentHashMap.EMPTY; 1.42 + this.hierarchy = hierarchy; 1.43 + cachedHierarchy = null; 1.44 +} 1.45 + 1.46 +synchronized public MultiFn reset(){ 1.47 + methodTable = methodCache = preferTable = PersistentHashMap.EMPTY; 1.48 + cachedHierarchy = null; 1.49 + return this; 1.50 +} 1.51 + 1.52 +synchronized public MultiFn addMethod(Object dispatchVal, IFn method) throws Exception{ 1.53 + methodTable = getMethodTable().assoc(dispatchVal, method); 1.54 + resetCache(); 1.55 + return this; 1.56 +} 1.57 + 1.58 +synchronized public MultiFn removeMethod(Object dispatchVal) throws Exception{ 1.59 + methodTable = getMethodTable().without(dispatchVal); 1.60 + resetCache(); 1.61 + return this; 1.62 +} 1.63 + 1.64 +synchronized public MultiFn preferMethod(Object dispatchValX, Object dispatchValY) throws Exception{ 1.65 + if(prefers(dispatchValY, dispatchValX)) 1.66 + throw new IllegalStateException( 1.67 + String.format("Preference conflict in multimethod '%s': %s is already preferred to %s", 1.68 + name, dispatchValY, dispatchValX)); 1.69 + preferTable = getPreferTable().assoc(dispatchValX, RT.conj((IPersistentCollection) RT.get(getPreferTable(), 1.70 + dispatchValX, 1.71 + PersistentHashSet.EMPTY), 1.72 + dispatchValY)); 1.73 + resetCache(); 1.74 + return this; 1.75 +} 1.76 + 1.77 +private boolean prefers(Object x, Object y) throws Exception{ 1.78 + IPersistentSet xprefs = (IPersistentSet) getPreferTable().valAt(x); 1.79 + if(xprefs != null && xprefs.contains(y)) 1.80 + return true; 1.81 + for(ISeq ps = RT.seq(parents.invoke(y)); ps != null; ps = ps.next()) 1.82 + { 1.83 + if(prefers(x, ps.first())) 1.84 + return true; 1.85 + } 1.86 + for(ISeq ps = RT.seq(parents.invoke(x)); ps != null; ps = ps.next()) 1.87 + { 1.88 + if(prefers(ps.first(), y)) 1.89 + return true; 1.90 + } 1.91 + return false; 1.92 +} 1.93 + 1.94 +private boolean isA(Object x, Object y) throws Exception{ 1.95 + return RT.booleanCast(isa.invoke(hierarchy.deref(), x, y)); 1.96 +} 1.97 + 1.98 +private boolean dominates(Object x, Object y) throws Exception{ 1.99 + return prefers(x, y) || isA(x, y); 1.100 +} 1.101 + 1.102 +private IPersistentMap resetCache() throws Exception{ 1.103 + methodCache = getMethodTable(); 1.104 + cachedHierarchy = hierarchy.deref(); 1.105 + return methodCache; 1.106 +} 1.107 + 1.108 +synchronized public IFn getMethod(Object dispatchVal) throws Exception{ 1.109 + if(cachedHierarchy != hierarchy.deref()) 1.110 + resetCache(); 1.111 + IFn targetFn = (IFn) methodCache.valAt(dispatchVal); 1.112 + if(targetFn != null) 1.113 + return targetFn; 1.114 + targetFn = findAndCacheBestMethod(dispatchVal); 1.115 + if(targetFn != null) 1.116 + return targetFn; 1.117 + targetFn = (IFn) getMethodTable().valAt(defaultDispatchVal); 1.118 + return targetFn; 1.119 +} 1.120 + 1.121 +private IFn getFn(Object dispatchVal) throws Exception{ 1.122 + IFn targetFn = getMethod(dispatchVal); 1.123 + if(targetFn == null) 1.124 + throw new IllegalArgumentException(String.format("No method in multimethod '%s' for dispatch value: %s", 1.125 + name, dispatchVal)); 1.126 + return targetFn; 1.127 +} 1.128 + 1.129 +private IFn findAndCacheBestMethod(Object dispatchVal) throws Exception{ 1.130 + Map.Entry bestEntry = null; 1.131 + for(Object o : getMethodTable()) 1.132 + { 1.133 + Map.Entry e = (Map.Entry) o; 1.134 + if(isA(dispatchVal, e.getKey())) 1.135 + { 1.136 + if(bestEntry == null || dominates(e.getKey(), bestEntry.getKey())) 1.137 + bestEntry = e; 1.138 + if(!dominates(bestEntry.getKey(), e.getKey())) 1.139 + throw new IllegalArgumentException( 1.140 + String.format( 1.141 + "Multiple methods in multimethod '%s' match dispatch value: %s -> %s and %s, and neither is preferred", 1.142 + name, dispatchVal, e.getKey(), bestEntry.getKey())); 1.143 + } 1.144 + } 1.145 + if(bestEntry == null) 1.146 + return null; 1.147 + //ensure basis has stayed stable throughout, else redo 1.148 + if(cachedHierarchy == hierarchy.deref()) 1.149 + { 1.150 + //place in cache 1.151 + methodCache = methodCache.assoc(dispatchVal, bestEntry.getValue()); 1.152 + return (IFn) bestEntry.getValue(); 1.153 + } 1.154 + else 1.155 + { 1.156 + resetCache(); 1.157 + return findAndCacheBestMethod(dispatchVal); 1.158 + } 1.159 +} 1.160 + 1.161 +public Object invoke() throws Exception{ 1.162 + return getFn(dispatchFn.invoke()).invoke(); 1.163 +} 1.164 + 1.165 +public Object invoke(Object arg1) throws Exception{ 1.166 + return getFn(dispatchFn.invoke(arg1)).invoke(arg1); 1.167 +} 1.168 + 1.169 +public Object invoke(Object arg1, Object arg2) throws Exception{ 1.170 + return getFn(dispatchFn.invoke(arg1, arg2)).invoke(arg1, arg2); 1.171 +} 1.172 + 1.173 +public Object invoke(Object arg1, Object arg2, Object arg3) throws Exception{ 1.174 + return getFn(dispatchFn.invoke(arg1, arg2, arg3)).invoke(arg1, arg2, arg3); 1.175 +} 1.176 + 1.177 +public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4) throws Exception{ 1.178 + return getFn(dispatchFn.invoke(arg1, arg2, arg3, arg4)).invoke(arg1, arg2, arg3, arg4); 1.179 +} 1.180 + 1.181 +public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) throws Exception{ 1.182 + return getFn(dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5)).invoke(arg1, arg2, arg3, arg4, arg5); 1.183 +} 1.184 + 1.185 +public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6) throws Exception{ 1.186 + return getFn(dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5, arg6)).invoke(arg1, arg2, arg3, arg4, arg5, arg6); 1.187 +} 1.188 + 1.189 +public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7) 1.190 + throws Exception{ 1.191 + return getFn(dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7)) 1.192 + .invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7); 1.193 +} 1.194 + 1.195 +public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, 1.196 + Object arg8) throws Exception{ 1.197 + return getFn(dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)). 1.198 + invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); 1.199 +} 1.200 + 1.201 +public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, 1.202 + Object arg8, Object arg9) throws Exception{ 1.203 + return getFn(dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)). 1.204 + invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); 1.205 +} 1.206 + 1.207 +public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, 1.208 + Object arg8, Object arg9, Object arg10) throws Exception{ 1.209 + return getFn(dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10)). 1.210 + invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); 1.211 +} 1.212 + 1.213 +public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, 1.214 + Object arg8, Object arg9, Object arg10, Object arg11) throws Exception{ 1.215 + return getFn(dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11)). 1.216 + invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11); 1.217 +} 1.218 + 1.219 +public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, 1.220 + Object arg8, Object arg9, Object arg10, Object arg11, Object arg12) throws Exception{ 1.221 + return getFn(dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12)). 1.222 + invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12); 1.223 +} 1.224 + 1.225 +public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, 1.226 + Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13) throws Exception{ 1.227 + return getFn(dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13)). 1.228 + invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13); 1.229 +} 1.230 + 1.231 +public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, 1.232 + Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14) 1.233 + throws Exception{ 1.234 + return getFn( 1.235 + dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14)). 1.236 + invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14); 1.237 +} 1.238 + 1.239 +public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, 1.240 + Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, 1.241 + Object arg15) throws Exception{ 1.242 + return getFn( 1.243 + dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, 1.244 + arg15)) 1.245 + .invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15); 1.246 +} 1.247 + 1.248 +public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, 1.249 + Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, 1.250 + Object arg15, Object arg16) throws Exception{ 1.251 + return getFn( 1.252 + dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, 1.253 + arg15, arg16)) 1.254 + .invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, 1.255 + arg15, arg16); 1.256 +} 1.257 + 1.258 +public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, 1.259 + Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, 1.260 + Object arg15, Object arg16, Object arg17) throws Exception{ 1.261 + return getFn( 1.262 + dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, 1.263 + arg15, arg16, arg17)) 1.264 + .invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, 1.265 + arg15, arg16, arg17); 1.266 +} 1.267 + 1.268 +public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, 1.269 + Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, 1.270 + Object arg15, Object arg16, Object arg17, Object arg18) throws Exception{ 1.271 + return getFn( 1.272 + dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, 1.273 + arg15, arg16, arg17, arg18)). 1.274 + invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, 1.275 + arg15, arg16, arg17, arg18); 1.276 +} 1.277 + 1.278 +public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, 1.279 + Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, 1.280 + Object arg15, Object arg16, Object arg17, Object arg18, Object arg19) throws Exception{ 1.281 + return getFn( 1.282 + dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, 1.283 + arg15, arg16, arg17, arg18, arg19)). 1.284 + invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, 1.285 + arg15, arg16, arg17, arg18, arg19); 1.286 +} 1.287 + 1.288 +public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, 1.289 + Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, 1.290 + Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20) 1.291 + throws Exception{ 1.292 + return getFn( 1.293 + dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, 1.294 + arg15, arg16, arg17, arg18, arg19, arg20)). 1.295 + invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, 1.296 + arg15, arg16, arg17, arg18, arg19, arg20); 1.297 +} 1.298 + 1.299 +public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, 1.300 + Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, 1.301 + Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object... args) 1.302 + throws Exception{ 1.303 + return getFn( 1.304 + dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, 1.305 + arg15, arg16, arg17, arg18, arg19, arg20, args)). 1.306 + invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, 1.307 + arg15, arg16, arg17, arg18, arg19, arg20, args); 1.308 +} 1.309 + 1.310 + public IPersistentMap getMethodTable() { 1.311 + return methodTable; 1.312 + } 1.313 + 1.314 + public IPersistentMap getPreferTable() { 1.315 + return preferTable; 1.316 + } 1.317 +}