af6aa5c67e03 — aurelien@trantor.local 12 years ago
use generators, cleanup & simplify a bit
3 files changed, 23 insertions(+), 31 deletions(-)

M __init__.py
M dispatch.py
M test/test_gf.py
M __init__.py +1 -1
@@ 9,6 9,6 @@ def method(*types):
         gf = _METHS.get(name)
         if gf is None:
             gf = _METHS[name] = mm.GF()
-        gf.add_rule(types, meth)
+        gf.register(types, meth)
         return gf
     return _wrap

          
M dispatch.py +21 -29
@@ 5,46 5,38 @@ def proximity(klass, mro):
 
 def lexicographic_mro(signature, matches):
     "dispatch ranking similar to CLOS"
-    mros = [klass.mro() for klass in signature]
-    for (sig,func),i in zip(matches,xrange(1000)):
-        matches[i] = (map(proximity, sig, mros), matches[i])
-    matches.sort(reverse=True)
-    return map(lambda t:t[1], matches)
-
-def signature(*args):
-    return tuple(o.__class__ for o in args)
+    mros = tuple(klass.mro() for klass in signature)
+    return sorted((map(proximity, sig, mros), func)
+                  for sig, func in matches)
 
 class GF(object):
     def __init__(self):
         self._table = []
+        self._cache = {}
 
-    def add_rule(self, sig, func):
-        self._table.append((sig, func))
+    def register(self, sig, func):
+        self._table.append((tuple(sig), func))
         self._cache = {}
 
     def __call__(self, *args):
-        sig = signature(*args)
-        self._pos = 0
-        if sig not in self._cache:
-            self._funcs = self.linearized_table(sig)
-            func = self._funcs.pop()
-            self._cache[sig] = func
-        else:
-            func = self._cache[sig]
+        sig = tuple(x.__class__ for x in args)
+        func = self._cache.get(sig)
+        if func is None:
+            self._funcs = self.compute_mro(sig)
+            try:
+                self._cache[sig] = func = self._funcs.next()
+            except StopIteration:
+                raise TypeError('no defined call signature args (%s)' % args)
         return func(*args)
 
     def next_method(self, *args):
-        func = self._funcs.pop()
+        func = self._funcs.next()
         return func(*args)
 
-    def linearized_table(self, sig):
-        table = [(s,f) for s,f in self._table
-                 if len(s) == len(sig)
-                 and reduce(mul, map(issubclass, sig, s))]
-        if not table:
-            def nomatch(*a):
-                raise TypeError('no defined call signature <%s> for args (%s)' %
-                                (','.join([str(o) for o in sig]), a))
-            return [nomatch]
-        return map(lambda l:l[1], lexicographic_mro(sig, table))
+    def compute_mro(self, callsig):
+        siglen = len(callsig)
+        table = ((sig, func) for sig, func in self._table
+                 if len(sig) == siglen
+                 and reduce(mul, map(issubclass, callsig, sig)))
+        return (x[1] for x in lexicographic_mro(callsig, table))
 

          
M test/test_gf.py +1 -1
@@ 108,7 108,7 @@ class TestGF(unittest.TestCase):
         def foo(b,x):
             return b,x
         b, y = B(), Y()
-        print foo(b, y)
+        foo(b, y)
 
 if __name__ == '__main__':
     unittest.main()