Mercurial > lasercutter
comparison 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 |
comparison
equal
deleted
inserted
replaced
9:35cf337adfcf | 10:ef7dbbd6452c |
---|---|
1 /** | |
2 * Copyright (c) Rich Hickey. All rights reserved. | |
3 * The use and distribution terms for this software are covered by the | |
4 * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) | |
5 * which can be found in the file epl-v10.html at the root of this distribution. | |
6 * By using this software in any fashion, you are agreeing to be bound by | |
7 * the terms of this license. | |
8 * You must not remove this notice, or any other, from this software. | |
9 **/ | |
10 | |
11 /* rich Sep 13, 2007 */ | |
12 | |
13 package clojure.lang; | |
14 | |
15 import java.util.Map; | |
16 | |
17 public class MultiFn extends AFn{ | |
18 final public IFn dispatchFn; | |
19 final public Object defaultDispatchVal; | |
20 final public IRef hierarchy; | |
21 final String name; | |
22 IPersistentMap methodTable; | |
23 IPersistentMap preferTable; | |
24 IPersistentMap methodCache; | |
25 Object cachedHierarchy; | |
26 | |
27 static final Var assoc = RT.var("clojure.core", "assoc"); | |
28 static final Var dissoc = RT.var("clojure.core", "dissoc"); | |
29 static final Var isa = RT.var("clojure.core", "isa?"); | |
30 static final Var parents = RT.var("clojure.core", "parents"); | |
31 | |
32 public MultiFn(String name, IFn dispatchFn, Object defaultDispatchVal, IRef hierarchy) throws Exception{ | |
33 this.name = name; | |
34 this.dispatchFn = dispatchFn; | |
35 this.defaultDispatchVal = defaultDispatchVal; | |
36 this.methodTable = PersistentHashMap.EMPTY; | |
37 this.methodCache = getMethodTable(); | |
38 this.preferTable = PersistentHashMap.EMPTY; | |
39 this.hierarchy = hierarchy; | |
40 cachedHierarchy = null; | |
41 } | |
42 | |
43 synchronized public MultiFn reset(){ | |
44 methodTable = methodCache = preferTable = PersistentHashMap.EMPTY; | |
45 cachedHierarchy = null; | |
46 return this; | |
47 } | |
48 | |
49 synchronized public MultiFn addMethod(Object dispatchVal, IFn method) throws Exception{ | |
50 methodTable = getMethodTable().assoc(dispatchVal, method); | |
51 resetCache(); | |
52 return this; | |
53 } | |
54 | |
55 synchronized public MultiFn removeMethod(Object dispatchVal) throws Exception{ | |
56 methodTable = getMethodTable().without(dispatchVal); | |
57 resetCache(); | |
58 return this; | |
59 } | |
60 | |
61 synchronized public MultiFn preferMethod(Object dispatchValX, Object dispatchValY) throws Exception{ | |
62 if(prefers(dispatchValY, dispatchValX)) | |
63 throw new IllegalStateException( | |
64 String.format("Preference conflict in multimethod '%s': %s is already preferred to %s", | |
65 name, dispatchValY, dispatchValX)); | |
66 preferTable = getPreferTable().assoc(dispatchValX, RT.conj((IPersistentCollection) RT.get(getPreferTable(), | |
67 dispatchValX, | |
68 PersistentHashSet.EMPTY), | |
69 dispatchValY)); | |
70 resetCache(); | |
71 return this; | |
72 } | |
73 | |
74 private boolean prefers(Object x, Object y) throws Exception{ | |
75 IPersistentSet xprefs = (IPersistentSet) getPreferTable().valAt(x); | |
76 if(xprefs != null && xprefs.contains(y)) | |
77 return true; | |
78 for(ISeq ps = RT.seq(parents.invoke(y)); ps != null; ps = ps.next()) | |
79 { | |
80 if(prefers(x, ps.first())) | |
81 return true; | |
82 } | |
83 for(ISeq ps = RT.seq(parents.invoke(x)); ps != null; ps = ps.next()) | |
84 { | |
85 if(prefers(ps.first(), y)) | |
86 return true; | |
87 } | |
88 return false; | |
89 } | |
90 | |
91 private boolean isA(Object x, Object y) throws Exception{ | |
92 return RT.booleanCast(isa.invoke(hierarchy.deref(), x, y)); | |
93 } | |
94 | |
95 private boolean dominates(Object x, Object y) throws Exception{ | |
96 return prefers(x, y) || isA(x, y); | |
97 } | |
98 | |
99 private IPersistentMap resetCache() throws Exception{ | |
100 methodCache = getMethodTable(); | |
101 cachedHierarchy = hierarchy.deref(); | |
102 return methodCache; | |
103 } | |
104 | |
105 synchronized public IFn getMethod(Object dispatchVal) throws Exception{ | |
106 if(cachedHierarchy != hierarchy.deref()) | |
107 resetCache(); | |
108 IFn targetFn = (IFn) methodCache.valAt(dispatchVal); | |
109 if(targetFn != null) | |
110 return targetFn; | |
111 targetFn = findAndCacheBestMethod(dispatchVal); | |
112 if(targetFn != null) | |
113 return targetFn; | |
114 targetFn = (IFn) getMethodTable().valAt(defaultDispatchVal); | |
115 return targetFn; | |
116 } | |
117 | |
118 private IFn getFn(Object dispatchVal) throws Exception{ | |
119 IFn targetFn = getMethod(dispatchVal); | |
120 if(targetFn == null) | |
121 throw new IllegalArgumentException(String.format("No method in multimethod '%s' for dispatch value: %s", | |
122 name, dispatchVal)); | |
123 return targetFn; | |
124 } | |
125 | |
126 private IFn findAndCacheBestMethod(Object dispatchVal) throws Exception{ | |
127 Map.Entry bestEntry = null; | |
128 for(Object o : getMethodTable()) | |
129 { | |
130 Map.Entry e = (Map.Entry) o; | |
131 if(isA(dispatchVal, e.getKey())) | |
132 { | |
133 if(bestEntry == null || dominates(e.getKey(), bestEntry.getKey())) | |
134 bestEntry = e; | |
135 if(!dominates(bestEntry.getKey(), e.getKey())) | |
136 throw new IllegalArgumentException( | |
137 String.format( | |
138 "Multiple methods in multimethod '%s' match dispatch value: %s -> %s and %s, and neither is preferred", | |
139 name, dispatchVal, e.getKey(), bestEntry.getKey())); | |
140 } | |
141 } | |
142 if(bestEntry == null) | |
143 return null; | |
144 //ensure basis has stayed stable throughout, else redo | |
145 if(cachedHierarchy == hierarchy.deref()) | |
146 { | |
147 //place in cache | |
148 methodCache = methodCache.assoc(dispatchVal, bestEntry.getValue()); | |
149 return (IFn) bestEntry.getValue(); | |
150 } | |
151 else | |
152 { | |
153 resetCache(); | |
154 return findAndCacheBestMethod(dispatchVal); | |
155 } | |
156 } | |
157 | |
158 public Object invoke() throws Exception{ | |
159 return getFn(dispatchFn.invoke()).invoke(); | |
160 } | |
161 | |
162 public Object invoke(Object arg1) throws Exception{ | |
163 return getFn(dispatchFn.invoke(arg1)).invoke(arg1); | |
164 } | |
165 | |
166 public Object invoke(Object arg1, Object arg2) throws Exception{ | |
167 return getFn(dispatchFn.invoke(arg1, arg2)).invoke(arg1, arg2); | |
168 } | |
169 | |
170 public Object invoke(Object arg1, Object arg2, Object arg3) throws Exception{ | |
171 return getFn(dispatchFn.invoke(arg1, arg2, arg3)).invoke(arg1, arg2, arg3); | |
172 } | |
173 | |
174 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4) throws Exception{ | |
175 return getFn(dispatchFn.invoke(arg1, arg2, arg3, arg4)).invoke(arg1, arg2, arg3, arg4); | |
176 } | |
177 | |
178 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) throws Exception{ | |
179 return getFn(dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5)).invoke(arg1, arg2, arg3, arg4, arg5); | |
180 } | |
181 | |
182 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6) throws Exception{ | |
183 return getFn(dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5, arg6)).invoke(arg1, arg2, arg3, arg4, arg5, arg6); | |
184 } | |
185 | |
186 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7) | |
187 throws Exception{ | |
188 return getFn(dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7)) | |
189 .invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7); | |
190 } | |
191 | |
192 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, | |
193 Object arg8) throws Exception{ | |
194 return getFn(dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)). | |
195 invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); | |
196 } | |
197 | |
198 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, | |
199 Object arg8, Object arg9) throws Exception{ | |
200 return getFn(dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)). | |
201 invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); | |
202 } | |
203 | |
204 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, | |
205 Object arg8, Object arg9, Object arg10) throws Exception{ | |
206 return getFn(dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10)). | |
207 invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); | |
208 } | |
209 | |
210 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, | |
211 Object arg8, Object arg9, Object arg10, Object arg11) throws Exception{ | |
212 return getFn(dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11)). | |
213 invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11); | |
214 } | |
215 | |
216 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, | |
217 Object arg8, Object arg9, Object arg10, Object arg11, Object arg12) throws Exception{ | |
218 return getFn(dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12)). | |
219 invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12); | |
220 } | |
221 | |
222 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, | |
223 Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13) throws Exception{ | |
224 return getFn(dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13)). | |
225 invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13); | |
226 } | |
227 | |
228 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, | |
229 Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14) | |
230 throws Exception{ | |
231 return getFn( | |
232 dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14)). | |
233 invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14); | |
234 } | |
235 | |
236 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, | |
237 Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, | |
238 Object arg15) throws Exception{ | |
239 return getFn( | |
240 dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, | |
241 arg15)) | |
242 .invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15); | |
243 } | |
244 | |
245 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, | |
246 Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, | |
247 Object arg15, Object arg16) throws Exception{ | |
248 return getFn( | |
249 dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, | |
250 arg15, arg16)) | |
251 .invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, | |
252 arg15, arg16); | |
253 } | |
254 | |
255 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, | |
256 Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, | |
257 Object arg15, Object arg16, Object arg17) throws Exception{ | |
258 return getFn( | |
259 dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, | |
260 arg15, arg16, arg17)) | |
261 .invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, | |
262 arg15, arg16, arg17); | |
263 } | |
264 | |
265 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, | |
266 Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, | |
267 Object arg15, Object arg16, Object arg17, Object arg18) throws Exception{ | |
268 return getFn( | |
269 dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, | |
270 arg15, arg16, arg17, arg18)). | |
271 invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, | |
272 arg15, arg16, arg17, arg18); | |
273 } | |
274 | |
275 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, | |
276 Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, | |
277 Object arg15, Object arg16, Object arg17, Object arg18, Object arg19) throws Exception{ | |
278 return getFn( | |
279 dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, | |
280 arg15, arg16, arg17, arg18, arg19)). | |
281 invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, | |
282 arg15, arg16, arg17, arg18, arg19); | |
283 } | |
284 | |
285 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, | |
286 Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, | |
287 Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20) | |
288 throws Exception{ | |
289 return getFn( | |
290 dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, | |
291 arg15, arg16, arg17, arg18, arg19, arg20)). | |
292 invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, | |
293 arg15, arg16, arg17, arg18, arg19, arg20); | |
294 } | |
295 | |
296 public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, | |
297 Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, | |
298 Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object... args) | |
299 throws Exception{ | |
300 return getFn( | |
301 dispatchFn.invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, | |
302 arg15, arg16, arg17, arg18, arg19, arg20, args)). | |
303 invoke(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, | |
304 arg15, arg16, arg17, arg18, arg19, arg20, args); | |
305 } | |
306 | |
307 public IPersistentMap getMethodTable() { | |
308 return methodTable; | |
309 } | |
310 | |
311 public IPersistentMap getPreferTable() { | |
312 return preferTable; | |
313 } | |
314 } |