| 159 | } |
| 160 | |
| 161 | private IFn findAndCacheBestMethod(Object dispatchVal) { |
| 162 | rw.readLock().lock(); |
| 163 | Object bestValue; |
| 164 | IPersistentMap mt = methodTable; |
| 165 | IPersistentMap pt = preferTable; |
| 166 | Object ch = cachedHierarchy; |
| 167 | try |
| 168 | { |
| 169 | Map.Entry bestEntry = null; |
| 170 | for(Object o : getMethodTable()) |
| 171 | { |
| 172 | Map.Entry e = (Map.Entry) o; |
| 173 | if(isA(ch, dispatchVal, e.getKey())) |
| 174 | { |
| 175 | if(bestEntry == null || dominates(ch, e.getKey(), bestEntry.getKey())) |
| 176 | bestEntry = e; |
| 177 | if(!dominates(ch, bestEntry.getKey(), e.getKey())) |
| 178 | throw new IllegalArgumentException( |
| 179 | String.format( |
| 180 | "Multiple methods in multimethod '%s' match dispatch value: %s -> %s and %s, and neither is preferred", |
| 181 | name, dispatchVal, e.getKey(), bestEntry.getKey())); |
| 182 | } |
| 183 | } |
| 184 | if(bestEntry == null) |
| 185 | { |
| 186 | bestValue = methodTable.valAt(defaultDispatchVal); |
| 187 | if(bestValue == null) |
| 188 | return null; |
| 189 | } |
| 190 | else |
| 191 | bestValue = bestEntry.getValue(); |
| 192 | } |
| 193 | finally |
| 194 | { |
| 195 | rw.readLock().unlock(); |
| 196 | } |
| 197 | |
| 198 | |
| 199 | //ensure basis has stayed stable throughout, else redo |
| 200 | rw.writeLock().lock(); |
| 201 | try |
| 202 | { |
| 203 | if( mt == methodTable && |
| 204 | pt == preferTable && |
| 205 | ch == cachedHierarchy && |
| 206 | cachedHierarchy == hierarchy.deref()) |
| 207 | { |
| 208 | //place in cache |
| 209 | methodCache = methodCache.assoc(dispatchVal, bestValue); |
| 210 | return (IFn) bestValue; |
| 211 | } |
| 212 | else |
| 213 | { |
| 214 | resetCache(); |
| 215 | return findAndCacheBestMethod(dispatchVal); |
| 216 | } |
| 217 | } |
| 218 | finally |