| 16 | import java.util.concurrent.locks.ReentrantReadWriteLock; |
| 17 | |
| 18 | public class MultiFn extends AFn{ |
| 19 | final public IFn dispatchFn; |
| 20 | final public Object defaultDispatchVal; |
| 21 | final public IRef hierarchy; |
| 22 | final String name; |
| 23 | final ReentrantReadWriteLock rw; |
| 24 | volatile IPersistentMap methodTable; |
| 25 | volatile IPersistentMap preferTable; |
| 26 | volatile IPersistentMap methodCache; |
| 27 | volatile Object cachedHierarchy; |
| 28 | |
| 29 | static final Var assoc = RT.var("clojure.core", "assoc"); |
| 30 | static final Var dissoc = RT.var("clojure.core", "dissoc"); |
| 31 | static final Var isa = RT.var("clojure.core", "isa?"); |
| 32 | static final Var parents = RT.var("clojure.core", "parents"); |
| 33 | |
| 34 | public MultiFn(String name, IFn dispatchFn, Object defaultDispatchVal, IRef hierarchy) { |
| 35 | this.rw = new ReentrantReadWriteLock(); |
| 36 | this.name = name; |
| 37 | this.dispatchFn = dispatchFn; |
| 38 | this.defaultDispatchVal = defaultDispatchVal; |
| 39 | this.methodTable = PersistentHashMap.EMPTY; |
| 40 | this.methodCache = getMethodTable(); |
| 41 | this.preferTable = PersistentHashMap.EMPTY; |
| 42 | this.hierarchy = hierarchy; |
| 43 | cachedHierarchy = null; |
| 44 | } |
| 45 | |
| 46 | public MultiFn reset(){ |
| 47 | rw.writeLock().lock(); |
| 48 | try{ |
| 49 | methodTable = methodCache = preferTable = PersistentHashMap.EMPTY; |
| 50 | cachedHierarchy = null; |
| 51 | return this; |
| 52 | } |
| 53 | finally { |
| 54 | rw.writeLock().unlock(); |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | public MultiFn addMethod(Object dispatchVal, IFn method) { |
| 59 | rw.writeLock().lock(); |
| 60 | try{ |
| 61 | methodTable = getMethodTable().assoc(dispatchVal, method); |
| 62 | resetCache(); |
| 63 | return this; |
| 64 | } |
| 65 | finally { |
| 66 | rw.writeLock().unlock(); |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | public MultiFn removeMethod(Object dispatchVal) { |
| 71 | rw.writeLock().lock(); |
| 72 | try |
| 73 | { |
| 74 | methodTable = getMethodTable().without(dispatchVal); |
| 75 | resetCache(); |