[Checkins] SVN: Zope3/trunk/src/zope/interface/ Implemented the cached adapter lookup code in C. This provided about

Jim Fulton jim at zope.com
Mon May 1 09:55:45 EDT 2006


Log message for revision 67796:
  Implemented the cached adapter lookup code in C.  This provided about
  a 10% speedup for the requests I tested.
  

Changed:
  U   Zope3/trunk/src/zope/interface/_zope_interface_coptimizations.c
  U   Zope3/trunk/src/zope/interface/adapter.py

-=-
Modified: Zope3/trunk/src/zope/interface/_zope_interface_coptimizations.c
===================================================================
--- Zope3/trunk/src/zope/interface/_zope_interface_coptimizations.c	2006-05-01 13:55:42 UTC (rev 67795)
+++ Zope3/trunk/src/zope/interface/_zope_interface_coptimizations.c	2006-05-01 13:55:44 UTC (rev 67796)
@@ -24,6 +24,10 @@
 static PyObject *str__class__, *str__providedBy__;
 static PyObject *empty, *fallback, *str_implied, *str_cls, *str_implements;
 static PyObject *str__conform__, *str_call_conform, *adapter_hooks;
+static PyObject *str_uncached_lookup, *str_uncached_lookupAll;
+static PyObject *str_uncached_subscriptions;
+static PyObject *str_registry, *strro, *str_generation, *strchanged;
+
 static PyTypeObject *Implements;
 
 static int imported_declarations = 0;
@@ -184,7 +188,10 @@
      because we may have a proxy, so we'll just try to get the
      only attribute.
   */
-  if (PyObject_HasAttr(result, strextends))
+  if (PyObject_TypeCheck(result, &SpecType)
+      || 
+      PyObject_HasAttr(result, strextends)
+      )
     return result;
     
   /*
@@ -510,7 +517,7 @@
 };
 
 /* ==================================================================== */
-/* ========== Begin: __call__ and __adapt__ descriptors =============== */
+/* ========== Begin: __call__ and __adapt__ =========================== */
 
 /*
     def __adapt__(self, obj):
@@ -696,8 +703,854 @@
         /* tp_methods        */ ib_methods,
 };
 
-/* ========== End: __call__ and __adapt__ descriptors =============== */
+/* =================== End: __call__ and __adapt__ ==================== */
+/* ==================================================================== */
 
+/* ==================================================================== */
+/* ========================== Begin: Lookup Bases ===================== */
+
+typedef struct {
+  PyObject_HEAD
+  PyObject *_cache;
+  PyObject *_mcache;
+  PyObject *_scache;
+} lookup;
+
+typedef struct {
+  PyObject_HEAD
+  PyObject *_cache;
+  PyObject *_mcache;
+  PyObject *_scache;
+  PyObject *_verify_ro;
+  PyObject *_verify_generations;
+} verify;
+
+static int
+lookup_traverse(lookup *self, visitproc visit, void *arg)
+{
+  int vret;
+
+  if (self->_cache) {
+    vret = visit(self->_cache, arg);
+    if (vret != 0)
+      return vret;
+  }
+
+  if (self->_mcache) {
+    vret = visit(self->_mcache, arg);
+    if (vret != 0)
+      return vret;
+  }
+
+  if (self->_scache) {
+    vret = visit(self->_scache, arg);
+    if (vret != 0)
+      return vret;
+  }
+  
+  return 0;
+}
+
+static int
+lookup_clear(lookup *self)
+{
+  Py_CLEAR(self->_cache);
+  Py_CLEAR(self->_mcache);
+  Py_CLEAR(self->_scache);
+  return 0;
+}
+
+static void
+lookup_dealloc(lookup *self)
+{
+  lookup_clear(self);
+  self->ob_type->tp_free((PyObject*)self);
+}
+
+/*
+    def changed(self, ignored=None):
+        self._cache.clear()
+        self._mcache.clear()
+        self._scache.clear()
+*/
+static PyObject *
+lookup_changed(lookup *self, PyObject *ignored)
+{
+  lookup_clear(self);
+  Py_INCREF(Py_None);
+  return Py_None;
+}
+
+#define ASSURE_DICT(N) if (N == NULL) { N = PyDict_New(); \
+                                        if (N == NULL) return NULL; \
+                                       }
+
+/*  
+    def _getcache(self, provided, name):
+        cache = self._cache.get(provided)
+        if cache is None:
+            cache = {}
+            self._cache[provided] = cache
+        if name:
+            c = cache.get(name)
+            if c is None:
+                c = {}
+                cache[name] = c
+            cache = c
+        return cache
+*/
+static PyObject *
+_subcache(PyObject *cache, PyObject *key)
+{
+  PyObject *subcache;
+
+  subcache = PyDict_GetItem(cache, key);
+  if (subcache == NULL)
+    {
+      int status;
+ 
+      subcache = PyDict_New();
+      if (subcache == NULL)
+        return NULL;
+      status = PyDict_SetItem(cache, key, subcache);
+      Py_DECREF(subcache);
+      if (status < 0)
+        return NULL;
+    }
+
+  return subcache;
+}
+static PyObject *
+_getcache(lookup *self, PyObject *provided, PyObject *name)
+{
+  PyObject *cache;
+
+  ASSURE_DICT(self->_cache);
+  cache = _subcache(self->_cache, provided);
+  if (cache == NULL)
+    return NULL;
+
+  if (name != NULL && PyObject_IsTrue(name))
+    cache = _subcache(cache, name);
+
+  return cache;
+}
+
+
+/*  
+    def lookup(self, required, provided, name=u'', default=None):
+        cache = self._getcache(provided, name)
+        if len(required) == 1:
+            result = cache.get(required[0], _not_in_mapping)
+        else:
+            result = cache.get(tuple(required), _not_in_mapping)
+
+        if result is _not_in_mapping:
+            result = self._uncached_lookup(required, provided, name)
+            if len(required) == 1:
+                cache[required[0]] = result
+            else:
+                cache[tuple(required)] = result
+
+        if result is None:
+            return default
+
+        return result
+*/
+static PyObject *
+tuplefy(PyObject *v)
+{
+  if (! PyTuple_Check(v))
+    {
+      v = PyObject_CallFunctionObjArgs(OBJECT(&PyTuple_Type), v, NULL);
+      if (v == NULL)
+        return NULL;
+    }
+  else
+    Py_INCREF(v);
+  
+  return v;
+}
+static PyObject *
+_lookup(lookup *self, 
+        PyObject *required, PyObject *provided, PyObject *name, 
+        PyObject *default_)
+{
+  PyObject *result, *key, *cache;
+
+  cache = _getcache(self, provided, name);
+  if (cache == NULL)
+    return NULL;
+
+  required = tuplefy(required);
+  if (required == NULL)
+    return NULL;
+
+  if (PyTuple_GET_SIZE(required) == 1)
+    key = PyTuple_GET_ITEM(required, 0);
+  else
+    key = required;
+
+  result = PyDict_GetItem(cache, key);
+  if (result == NULL)
+    {
+      int status;
+
+      result = PyObject_CallMethodObjArgs(OBJECT(self), str_uncached_lookup,
+                                          required, provided, name, NULL);
+      if (result == NULL)
+        {
+          Py_DECREF(required);
+          return NULL;
+        }
+      status = PyDict_SetItem(cache, key, result);
+      Py_DECREF(required);
+      if (status < 0)
+        {
+          Py_DECREF(result);
+          return NULL;
+        }
+    }
+  else
+    {
+      Py_INCREF(result);
+      Py_DECREF(required);
+    }
+
+  if (result == Py_None && default_ != NULL)
+    {
+      Py_DECREF(Py_None);
+      Py_INCREF(default_);
+      return default_;
+    }
+
+  return result;
+}
+static PyObject *
+lookup_lookup(lookup *self, PyObject *args, PyObject *kwds)
+{
+  static char *kwlist[] = {"required", "provided", "name", "default", NULL};
+  PyObject *required, *provided, *name=NULL, *default_=NULL;
+
+  if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
+                                    &required, &provided, &name, &default_))
+    return NULL; 
+
+  return _lookup(self, required, provided, name, default_);
+}
+
+
+/*  
+    def lookup1(self, required, provided, name=u'', default=None):
+        cache = self._getcache(provided, name)
+        result = cache.get(required, _not_in_mapping)
+        if result is _not_in_mapping:
+            return self.lookup((required, ), provided, name, default)
+
+        if result is None:
+            return default
+
+        return result
+*/
+static PyObject *
+_lookup1(lookup *self, 
+        PyObject *required, PyObject *provided, PyObject *name, 
+        PyObject *default_)
+{
+  PyObject *result, *cache;
+
+  cache = _getcache(self, provided, name);
+  if (cache == NULL)
+    return NULL;
+
+  result = PyDict_GetItem(cache, required);
+  if (result == NULL)
+    {
+      PyObject *tup;
+
+      tup = PyTuple_New(1);
+      if (tup == NULL)
+        return NULL;
+      Py_INCREF(required);
+      PyTuple_SET_ITEM(tup, 0, required);
+      result = _lookup(self, tup, provided, name, default_);
+      Py_DECREF(tup);
+    }
+  else
+    Py_INCREF(result);
+
+  return result;
+}
+static PyObject *
+lookup_lookup1(lookup *self, PyObject *args, PyObject *kwds)
+{
+  static char *kwlist[] = {"required", "provided", "name", "default", NULL};
+  PyObject *required, *provided, *name=NULL, *default_=NULL;
+
+  if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
+                                    &required, &provided, &name, &default_))
+    return NULL; 
+
+  return _lookup1(self, required, provided, name, default_);
+}
+
+/*  
+    def adapter_hook(self, provided, object, name=u'', default=None):
+        required = providedBy(object)
+        cache = self._getcache(provided, name)
+        factory = cache.get(required, _not_in_mapping)
+        if factory is _not_in_mapping:
+            factory = self.lookup((required, ), provided, name)
+
+        if factory is not None:
+            result = factory(object)
+            if result is not None:
+                return result
+
+        return default
+*/
+static PyObject *
+_adapter_hook(lookup *self, 
+              PyObject *provided, PyObject *object,  PyObject *name, 
+              PyObject *default_)
+{
+  PyObject *required, *factory, *result;
+
+  required = providedBy(NULL, object);
+  if (required == NULL)
+    return NULL;
+  
+  factory = _lookup1(self, required, provided, name, Py_None);
+  Py_DECREF(required);
+  if (factory == NULL)
+    return NULL;
+  
+  if (factory != Py_None)
+    {
+      result = PyObject_CallFunctionObjArgs(factory, object, NULL);
+      Py_DECREF(factory);
+      if (result == NULL || result != Py_None)
+        return result;
+    }
+  else
+    result = factory; /* None */
+
+  if (default_ == NULL || default_ == result) /* No default specified, */
+    return result;   /* Return None.  result is owned None */
+
+  Py_DECREF(result);
+  Py_INCREF(default_);
+
+  return default_;
+}
+static PyObject *
+lookup_adapter_hook(lookup *self, PyObject *args, PyObject *kwds)
+{
+  static char *kwlist[] = {"provided", "object", "name", "default", NULL};
+  PyObject *object, *provided, *name=NULL, *default_=NULL;
+
+  if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
+                                    &provided, &object, &name, &default_))
+    return NULL; 
+
+  return _adapter_hook(self, provided, object, name, default_);
+}
+
+static PyObject *
+lookup_queryAdapter(lookup *self, PyObject *args, PyObject *kwds)
+{
+  static char *kwlist[] = {"object", "provided", "name", "default", NULL};
+  PyObject *object, *provided, *name=NULL, *default_=NULL;
+
+  if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
+                                    &object, &provided, &name, &default_))
+    return NULL; 
+
+  return _adapter_hook(self, provided, object, name, default_);
+}
+
+/*  
+    def lookupAll(self, required, provided):
+        cache = self._mcache.get(provided)
+        if cache is None:
+            cache = {}
+            self._mcache[provided] = cache
+
+        required = tuple(required)
+        result = cache.get(required, _not_in_mapping)
+        if result is _not_in_mapping:
+            result = self._uncached_lookupAll(required, provided)
+            cache[required] = result
+
+        return result
+*/
+static PyObject *
+_lookupAll(lookup *self, PyObject *required, PyObject *provided)
+{
+  PyObject *cache, *result;
+
+  ASSURE_DICT(self->_mcache);
+  cache = _subcache(self->_mcache, provided);
+  if (cache == NULL)
+    return NULL;
+
+  required = tuplefy(required);
+  if (required == NULL)
+    return NULL;
+
+  result = PyDict_GetItem(cache, required);
+  if (result == NULL)
+    {
+      int status;
+
+      result = PyObject_CallMethodObjArgs(OBJECT(self), str_uncached_lookupAll,
+                                          required, provided, NULL);
+      if (result == NULL)
+        {
+          Py_DECREF(required);
+          return NULL;
+        }
+      status = PyDict_SetItem(cache, required, result);
+      Py_DECREF(required);
+      if (status < 0)
+        {
+          Py_DECREF(result);
+          return NULL;
+        }
+    }
+  else
+    {
+      Py_INCREF(result);
+      Py_DECREF(required);
+    }
+
+  return result;  
+}
+static PyObject *
+lookup_lookupAll(lookup *self, PyObject *args, PyObject *kwds)
+{
+  static char *kwlist[] = {"required", "provided", NULL};
+  PyObject *required, *provided;
+
+  if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist,
+                                    &required, &provided))
+    return NULL; 
+
+  return _lookupAll(self, required, provided);
+}
+
+/*  
+    def subscriptions(self, required, provided):
+        cache = self._scache.get(provided)
+        if cache is None:
+            cache = {}
+            self._scache[provided] = cache
+
+        required = tuple(required)
+        result = cache.get(required, _not_in_mapping)
+        if result is _not_in_mapping:
+            result = self._uncached_subscriptions(required, provided)
+            cache[required] = result
+
+        return result
+*/
+static PyObject *
+_subscriptions(lookup *self, PyObject *required, PyObject *provided)
+{
+  PyObject *cache, *result;
+
+  ASSURE_DICT(self->_scache);
+  cache = _subcache(self->_scache, provided);
+  if (cache == NULL)
+    return NULL;
+
+  required = tuplefy(required);
+  if (required == NULL)
+    return NULL;
+
+  result = PyDict_GetItem(cache, required);
+  if (result == NULL)
+    {
+      int status;
+
+      result = PyObject_CallMethodObjArgs(
+                                 OBJECT(self), str_uncached_subscriptions,
+                                 required, provided, NULL);
+      if (result == NULL)
+        {
+          Py_DECREF(required);
+          return NULL;
+        }
+      status = PyDict_SetItem(cache, required, result);
+      Py_DECREF(required);
+      if (status < 0)
+        {
+          Py_DECREF(result);
+          return NULL;
+        }
+    }
+  else
+    {
+      Py_INCREF(result);
+      Py_DECREF(required);
+    }
+
+  return result;  
+}
+static PyObject *
+lookup_subscriptions(lookup *self, PyObject *args, PyObject *kwds)
+{
+  static char *kwlist[] = {"required", "provided", NULL};
+  PyObject *required, *provided;
+
+  if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist,
+                                    &required, &provided))
+    return NULL; 
+
+  return _subscriptions(self, required, provided);
+}
+
+static struct PyMethodDef lookup_methods[] = {
+  {"changed",	    (PyCFunction)lookup_changed,       METH_O,        ""},
+  {"lookup",	    (PyCFunction)lookup_lookup,	       METH_KEYWORDS, ""},
+  {"lookup1",	    (PyCFunction)lookup_lookup1,       METH_KEYWORDS, ""},
+  {"queryAdapter",  (PyCFunction)lookup_queryAdapter,  METH_KEYWORDS, ""},
+  {"adapter_hook",  (PyCFunction)lookup_adapter_hook,  METH_KEYWORDS, ""},
+  {"lookupAll",	    (PyCFunction)lookup_lookupAll,     METH_KEYWORDS, ""},
+  {"subscriptions", (PyCFunction)lookup_subscriptions, METH_KEYWORDS, ""},
+  {NULL,	    NULL}		/* sentinel */
+};
+
+static PyTypeObject LookupBase = {
+	PyObject_HEAD_INIT(NULL)
+	/* ob_size           */ 0,
+	/* tp_name           */ "_zope_interface_coptimizations."
+                                "LookupBase",
+	/* tp_basicsize      */ sizeof(lookup),
+	/* tp_itemsize       */ 0,
+	/* tp_dealloc        */ (destructor)&lookup_dealloc,
+	/* tp_print          */ (printfunc)0,
+	/* tp_getattr        */ (getattrfunc)0,
+	/* tp_setattr        */ (setattrfunc)0,
+	/* tp_compare        */ (cmpfunc)0,
+	/* tp_repr           */ (reprfunc)0,
+	/* tp_as_number      */ 0,
+	/* tp_as_sequence    */ 0,
+	/* tp_as_mapping     */ 0,
+	/* tp_hash           */ (hashfunc)0,
+	/* tp_call           */ (ternaryfunc)0,
+	/* tp_str            */ (reprfunc)0,
+        /* tp_getattro       */ (getattrofunc)0,
+        /* tp_setattro       */ (setattrofunc)0,
+        /* tp_as_buffer      */ 0,
+        /* tp_flags          */ Py_TPFLAGS_DEFAULT
+				| Py_TPFLAGS_BASETYPE 
+                          	| Py_TPFLAGS_HAVE_GC,
+	/* tp_doc            */ "",
+        /* tp_traverse       */ (traverseproc)lookup_traverse,
+        /* tp_clear          */ (inquiry)lookup_clear,
+        /* tp_richcompare    */ (richcmpfunc)0,
+        /* tp_weaklistoffset */ (long)0,
+        /* tp_iter           */ (getiterfunc)0,
+        /* tp_iternext       */ (iternextfunc)0,
+        /* tp_methods        */ lookup_methods,
+};
+
+static int
+verifying_traverse(verify *self, visitproc visit, void *arg)
+{
+  int vret;
+
+  vret = lookup_traverse((lookup *)self, visit, arg);
+  if (vret != 0)
+    return vret;
+
+  if (self->_verify_ro) {
+    vret = visit(self->_verify_ro, arg);
+    if (vret != 0)
+      return vret;
+  }
+  if (self->_verify_generations) {
+    vret = visit(self->_verify_generations, arg);
+    if (vret != 0)
+      return vret;
+  }
+  
+  return 0;
+}
+
+static int
+verifying_clear(verify *self)
+{
+  lookup_clear((lookup *)self);
+  Py_CLEAR(self->_verify_generations);
+  Py_CLEAR(self->_verify_ro);
+  return 0;
+}
+
+
+static void
+verifying_dealloc(verify *self)
+{
+  verifying_clear(self);
+  self->ob_type->tp_free((PyObject*)self);
+}
+
+/*  
+    def changed(self, originally_changed):
+        super(VerifyingBasePy, self).changed(originally_changed)
+        self._verify_ro = self._registry.ro[1:]
+        self._verify_generations = [r._generation for r in self._verify_ro]
+*/
+static PyObject *
+_generations_tuple(PyObject *ro)
+{
+  int i, l;
+  PyObject *generations;
+  
+  l = PyTuple_GET_SIZE(ro);
+  generations = PyTuple_New(l);
+  for (i=0; i < l; i++)
+    {
+      PyObject *generation;
+      
+      generation = PyObject_GetAttr(PyTuple_GET_ITEM(ro, i), str_generation);
+      if (generation == NULL)
+        {
+          Py_DECREF(generations);
+          return NULL;
+        }
+      PyTuple_SET_ITEM(generations, i, generation);
+    }
+
+  return generations;
+}
+static PyObject *
+verifying_changed(verify *self, PyObject *ignored)
+{
+  PyObject *t, *ro;
+
+  verifying_clear(self);
+
+  t = PyObject_GetAttr(OBJECT(self), str_registry);
+  if (t == NULL)
+    return NULL;
+  ro = PyObject_GetAttr(t, strro);
+  Py_DECREF(t);
+  if (ro == NULL)
+    return NULL;
+
+  t = PyObject_CallFunctionObjArgs(OBJECT(&PyTuple_Type), ro, NULL);
+  Py_DECREF(ro);
+  if (t == NULL)
+    return NULL;
+
+  ro = PyTuple_GetSlice(t, 1, PyTuple_GET_SIZE(t));
+  Py_DECREF(t);
+  if (ro == NULL)
+    return NULL;
+  
+  self->_verify_generations = _generations_tuple(ro);
+  if (self->_verify_generations == NULL)
+    {
+      Py_DECREF(ro);
+      return NULL;
+    }
+
+  self->_verify_ro = ro;
+
+  Py_INCREF(Py_None);
+  return Py_None;
+}
+
+/*  
+    def _verify(self):
+        if ([r._generation for r in self._verify_ro]
+            != self._verify_generations):
+            self.changed(None)
+*/
+static int
+_verify(verify *self)
+{
+  PyObject *changed_result;
+
+  if (self->_verify_ro != NULL && self->_verify_generations != NULL)
+    {
+      PyObject *generations;
+      int changed;
+
+      generations = _generations_tuple(self->_verify_ro);
+      if (generations == NULL)
+        return -1;
+
+      changed = PyObject_Compare(self->_verify_generations, generations);
+      Py_DECREF(generations);
+      if (PyErr_Occurred())
+        return -1;
+      
+      if (changed == 0)
+        return 0;
+    }
+
+  changed_result = PyObject_CallMethodObjArgs(OBJECT(self), strchanged, 
+                                              Py_None, NULL);
+  if (changed_result == NULL)
+    return -1;
+
+  Py_DECREF(changed_result);
+  return 0;
+}
+
+static PyObject *
+verifying_lookup(verify *self, PyObject *args, PyObject *kwds)
+{
+  static char *kwlist[] = {"required", "provided", "name", "default", NULL};
+  PyObject *required, *provided, *name=NULL, *default_=NULL;
+
+  if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
+                                    &required, &provided, &name, &default_))
+    return NULL; 
+
+  if (_verify(self) < 0)
+    return NULL;
+
+  return _lookup((lookup *)self, required, provided, name, default_);
+}
+
+static PyObject *
+verifying_lookup1(verify *self, PyObject *args, PyObject *kwds)
+{
+  static char *kwlist[] = {"required", "provided", "name", "default", NULL};
+  PyObject *required, *provided, *name=NULL, *default_=NULL;
+
+  if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
+                                    &required, &provided, &name, &default_))
+    return NULL; 
+
+  if (_verify(self) < 0)
+    return NULL;
+
+  return _lookup1((lookup *)self, required, provided, name, default_);
+}
+
+static PyObject *
+verifying_adapter_hook(verify *self, PyObject *args, PyObject *kwds)
+{
+  static char *kwlist[] = {"provided", "object", "name", "default", NULL};
+  PyObject *object, *provided, *name=NULL, *default_=NULL;
+
+  if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
+                                    &provided, &object, &name, &default_))
+    return NULL; 
+
+  if (_verify(self) < 0)
+    return NULL;
+
+  return _adapter_hook((lookup *)self, provided, object, name, default_);
+}
+
+static PyObject *
+verifying_queryAdapter(verify *self, PyObject *args, PyObject *kwds)
+{
+  static char *kwlist[] = {"object", "provided", "name", "default", NULL};
+  PyObject *object, *provided, *name=NULL, *default_=NULL;
+
+  if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist,
+                                    &object, &provided, &name, &default_))
+    return NULL; 
+
+  if (_verify(self) < 0)
+    return NULL;
+
+  return _adapter_hook((lookup *)self, provided, object, name, default_);
+}
+
+static PyObject *
+verifying_lookupAll(verify *self, PyObject *args, PyObject *kwds)
+{
+  static char *kwlist[] = {"required", "provided", NULL};
+  PyObject *required, *provided;
+
+  if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist,
+                                    &required, &provided))
+    return NULL; 
+
+  if (_verify(self) < 0)
+    return NULL;
+
+  return _lookupAll((lookup *)self, required, provided);
+}
+
+static PyObject *
+verifying_subscriptions(verify *self, PyObject *args, PyObject *kwds)
+{
+  static char *kwlist[] = {"required", "provided", NULL};
+  PyObject *required, *provided;
+
+  if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist,
+                                    &required, &provided))
+    return NULL; 
+
+  if (_verify(self) < 0)
+    return NULL;
+
+  return _subscriptions((lookup *)self, required, provided);
+}
+
+static struct PyMethodDef verifying_methods[] = {
+  {"changed",	   (PyCFunction)verifying_changed,	  METH_O,        ""},
+  {"lookup",	   (PyCFunction)verifying_lookup,	  METH_KEYWORDS, ""},
+  {"lookup1",	   (PyCFunction)verifying_lookup1,	  METH_KEYWORDS, ""},
+  {"queryAdapter",  (PyCFunction)verifying_queryAdapter,  METH_KEYWORDS, ""},
+  {"adapter_hook",  (PyCFunction)verifying_adapter_hook,  METH_KEYWORDS, ""},
+  {"lookupAll",	   (PyCFunction)verifying_lookupAll,	  METH_KEYWORDS, ""},
+  {"subscriptions", (PyCFunction)verifying_subscriptions, METH_KEYWORDS, ""},
+  {NULL,	    NULL}		/* sentinel */
+};
+
+static PyTypeObject VerifyingBase = {
+	PyObject_HEAD_INIT(NULL)
+	/* ob_size           */ 0,
+	/* tp_name           */ "_zope_interface_coptimizations."
+                                "VerifyingBase",
+	/* tp_basicsize      */ sizeof(verify),
+	/* tp_itemsize       */ 0,
+	/* tp_dealloc        */ (destructor)&verifying_dealloc,
+	/* tp_print          */ (printfunc)0,
+	/* tp_getattr        */ (getattrfunc)0,
+	/* tp_setattr        */ (setattrfunc)0,
+	/* tp_compare        */ (cmpfunc)0,
+	/* tp_repr           */ (reprfunc)0,
+	/* tp_as_number      */ 0,
+	/* tp_as_sequence    */ 0,
+	/* tp_as_mapping     */ 0,
+	/* tp_hash           */ (hashfunc)0,
+	/* tp_call           */ (ternaryfunc)0,
+	/* tp_str            */ (reprfunc)0,
+        /* tp_getattro       */ (getattrofunc)0,
+        /* tp_setattro       */ (setattrofunc)0,
+        /* tp_as_buffer      */ 0,
+        /* tp_flags          */ Py_TPFLAGS_DEFAULT
+				| Py_TPFLAGS_BASETYPE 
+                          	| Py_TPFLAGS_HAVE_GC,
+	/* tp_doc            */ "",
+        /* tp_traverse       */ (traverseproc)verifying_traverse,
+        /* tp_clear          */ (inquiry)verifying_clear,
+        /* tp_richcompare    */ (richcmpfunc)0,
+        /* tp_weaklistoffset */ (long)0,
+        /* tp_iter           */ (getiterfunc)0,
+        /* tp_iternext       */ (iternextfunc)0,
+        /* tp_methods        */ verifying_methods,
+        /* tp_members        */ 0,
+        /* tp_getset         */ 0,
+        /* tp_base           */ &LookupBase,
+};
+
+/* ========================== End: Lookup Bases ======================= */
+/* ==================================================================== */
+
+
+
 static struct PyMethodDef m_methods[] = {
   {"implementedBy", (PyCFunction)implementedBy, METH_O,
    "Interfaces implemented by a class or factory.\n"
@@ -732,6 +1585,13 @@
   DEFINE_STRING(_cls);
   DEFINE_STRING(__conform__);
   DEFINE_STRING(_call_conform);
+  DEFINE_STRING(_uncached_lookup);
+  DEFINE_STRING(_uncached_lookupAll);
+  DEFINE_STRING(_uncached_subscriptions);
+  DEFINE_STRING(_registry);
+  DEFINE_STRING(_generation);
+  DEFINE_STRING(ro);
+  DEFINE_STRING(changed);
 #undef DEFINE_STRING
   adapter_hooks = PyList_New(0);
   if (adapter_hooks == NULL)
@@ -752,6 +1612,14 @@
   if (PyType_Ready(&InterfaceBase) < 0)
     return;
 
+  LookupBase.tp_new = PyBaseObject_Type.tp_new;
+  if (PyType_Ready(&LookupBase) < 0)
+    return;
+
+  VerifyingBase.tp_new = PyBaseObject_Type.tp_new;
+  if (PyType_Ready(&VerifyingBase) < 0)
+    return;
+
   
   /* Create the module and add the functions */
   m = Py_InitModule3("_zope_interface_coptimizations", m_methods,
@@ -761,15 +1629,19 @@
     return;
   
   /* Add types: */
-  if (PyModule_AddObject(m, "SpecificationBase", (PyObject *)&SpecType) < 0)
+  if (PyModule_AddObject(m, "SpecificationBase", OBJECT(&SpecType)) < 0)
     return;
   if (PyModule_AddObject(m, "ObjectSpecificationDescriptor", 
                          (PyObject *)&OSDType) < 0)
     return;
-  if (PyModule_AddObject(m, "ClassProvidesBase", (PyObject *)&CPBType) < 0)
+  if (PyModule_AddObject(m, "ClassProvidesBase", OBJECT(&CPBType)) < 0)
     return;
-  if (PyModule_AddObject(m, "InterfaceBase", (PyObject *)&InterfaceBase) < 0)
+  if (PyModule_AddObject(m, "InterfaceBase", OBJECT(&InterfaceBase)) < 0)
     return;
+  if (PyModule_AddObject(m, "LookupBase", OBJECT(&LookupBase)) < 0)
+    return;
+  if (PyModule_AddObject(m, "VerifyingBase", OBJECT(&VerifyingBase)) < 0)
+    return;
   if (PyModule_AddObject(m, "adapter_hooks", adapter_hooks) < 0)
     return;
 }

Modified: Zope3/trunk/src/zope/interface/adapter.py
===================================================================
--- Zope3/trunk/src/zope/interface/adapter.py	2006-05-01 13:55:42 UTC (rev 67795)
+++ Zope3/trunk/src/zope/interface/adapter.py	2006-05-01 13:55:44 UTC (rev 67796)
@@ -244,20 +244,153 @@
 
 
 _not_in_mapping = object()
-class AdapterLookup(object):
+class LookupBasePy(object):
 
-    def __init__(self, registry):
-        self._registry = registry
+    def __init__(self):
         self._cache = {}
         self._mcache = {}
         self._scache = {}
+        
+    def changed(self, ignored=None):
+        self._cache.clear()
+        self._mcache.clear()
+        self._scache.clear()
+        
+    def _getcache(self, provided, name):
+        cache = self._cache.get(provided)
+        if cache is None:
+            cache = {}
+            self._cache[provided] = cache
+        if name:
+            c = cache.get(name)
+            if c is None:
+                c = {}
+                cache[name] = c
+            cache = c
+        return cache
+
+    def lookup(self, required, provided, name=u'', default=None):
+        cache = self._getcache(provided, name)
+        if len(required) == 1:
+            result = cache.get(required[0], _not_in_mapping)
+        else:
+            result = cache.get(tuple(required), _not_in_mapping)
+
+        if result is _not_in_mapping:
+            result = self._uncached_lookup(required, provided, name)
+            if len(required) == 1:
+                cache[required[0]] = result
+            else:
+                cache[tuple(required)] = result
+
+        if result is None:
+            return default
+
+        return result
+    
+    def lookup1(self, required, provided, name=u'', default=None):
+        cache = self._getcache(provided, name)
+        result = cache.get(required, _not_in_mapping)
+        if result is _not_in_mapping:
+            return self.lookup((required, ), provided, name, default)
+
+        if result is None:
+            return default
+
+        return result
+
+    def queryAdapter(self, object, provided, name=u'', default=None):
+        return self.adapter_hook(provided, object, name, default)
+
+    def adapter_hook(self, provided, object, name=u'', default=None):
+        required = providedBy(object)
+        cache = self._getcache(provided, name)
+        factory = cache.get(required, _not_in_mapping)
+        if factory is _not_in_mapping:
+            factory = self.lookup((required, ), provided, name)
+
+        if factory is not None:
+            result = factory(object)
+            if result is not None:
+                return result
+
+        return default
+
+    def lookupAll(self, required, provided):
+        cache = self._mcache.get(provided)
+        if cache is None:
+            cache = {}
+            self._mcache[provided] = cache
+
+        required = tuple(required)
+        result = cache.get(required, _not_in_mapping)
+        if result is _not_in_mapping:
+            result = self._uncached_lookupAll(required, provided)
+            cache[required] = result
+
+        return result
+
+
+    def subscriptions(self, required, provided):
+        cache = self._scache.get(provided)
+        if cache is None:
+            cache = {}
+            self._scache[provided] = cache
+
+        required = tuple(required)
+        result = cache.get(required, _not_in_mapping)
+        if result is _not_in_mapping:
+            result = self._uncached_subscriptions(required, provided)
+            cache[required] = result
+
+        return result
+    
+LookupBase = LookupBasePy
+
+class VerifyingBasePy(LookupBasePy):
+
+    def changed(self, originally_changed):
+        LookupBasePy.changed(self, originally_changed)
+        self._verify_ro = self._registry.ro[1:]
+        self._verify_generations = [r._generation for r in self._verify_ro]
+
+    def _verify(self):
+        if ([r._generation for r in self._verify_ro]
+            != self._verify_generations):
+            self.changed(None)
+
+    def _getcache(self, provided, name):
+        self._verify()
+        return LookupBasePy._getcache(self, provided, name)
+    
+    def lookupAll(self, required, provided):
+        self._verify()
+        return LookupBasePy.lookupAll(self, required, provided)
+
+    def subscriptions(self, required, provided):
+        self._verify()
+        return LookupBasePy.subscriptions(self, required, provided)
+
+VerifyingBase = VerifyingBasePy
+
+
+try:
+    import _zope_interface_coptimizations
+except ImportError:
+    pass
+else:
+    from _zope_interface_coptimizations import LookupBase, VerifyingBase
+
+class AdapterLookupBase(object):
+
+    def __init__(self, registry):
+        self._registry = registry
         self._required = {}
         self.init_extendors()
+        super(AdapterLookupBase, self).__init__()
 
     def changed(self, ignored=None):
-        self._cache.clear()
-        self._mcache.clear()
-        self._scache.clear()
+        super(AdapterLookupBase, self).changed(None)
         for r in self._required.keys():
             r = r()
             if r is not None:
@@ -310,19 +443,6 @@
             _extendors[i] = [e for e in _extendors.get(i, ())
                              if e != provided]
 
-        
-    def _getcache(self, provided, name):
-        cache = self._cache.get(provided)
-        if cache is None:
-            cache = {}
-            self._cache[provided] = cache
-        if name:
-            c = cache.get(name)
-            if c is None:
-                c = {}
-                cache[name] = c
-            cache = c
-        return cache
 
     def _subscribe(self, *required):
         _refs = self._required
@@ -332,40 +452,26 @@
                 r.subscribe(self)
                 _refs[ref] = 1
 
-    def lookup(self, required, provided, name=u'', default=None):
-        cache = self._getcache(provided, name)
-        if len(required) == 1:
-            result = cache.get(required[0], _not_in_mapping)
-        else:
-            result = cache.get(tuple(required), _not_in_mapping)
+    def _uncached_lookup(self, required, provided, name=u''):
+        result = None
+        order = len(required)
+        for registry in self._registry.ro:
+            byorder = registry._adapters
+            if order >= len(byorder):
+                continue
 
-        if result is _not_in_mapping:
-            result = None
-            order = len(required)
-            for registry in self._registry.ro:
-                byorder = registry._adapters
-                if order >= len(byorder):
-                    continue
+            extendors = registry._v_lookup._extendors.get(provided)
+            if not extendors:
+                continue
 
-                extendors = registry._v_lookup._extendors.get(provided)
-                if not extendors:
-                    continue
+            components = byorder[order]
+            result = _lookup(components, required, extendors, name, 0,
+                             order)
+            if result is not None:
+                break
 
-                components = byorder[order]
-                result = _lookup(components, required, extendors, name, 0,
-                                 order)
-                if result is not None:
-                    break
+        self._subscribe(*required)
 
-            self._subscribe(*required)
-            if len(required) == 1:
-                cache[required[0]] = result
-            else:
-                cache[tuple(required)] = result
-
-        if result is None:
-            return default
-
         return result
 
     def queryMultiAdapter(self, objects, provided, name=u'', default=None):
@@ -378,94 +484,47 @@
             return default
 
         return result        
-    
-    def lookup1(self, required, provided, name=u'', default=None):
-        cache = self._getcache(provided, name)
-        result = cache.get(required, _not_in_mapping)
-        if result is _not_in_mapping:
-            return self.lookup((required, ), provided, name, default)
 
-        if result is None:
-            return default
+    def _uncached_lookupAll(self, required, provided):
+        order = len(required)
+        result = {}
+        for registry in reversed(self._registry.ro):
+            byorder = registry._adapters
+            if order >= len(byorder):
+                continue
+            extendors = registry._v_lookup._extendors.get(provided)
+            if not extendors:
+                continue
+            components = byorder[order]
+            _lookupAll(components, required, extendors, result, 0, order)
 
-        return result
+        self._subscribe(*required)
 
-    
-    def queryAdapter(self, object, provided, name=u'', default=None):
-        return self.adapter_hook(provided, object, name, default)
+        return tuple(result.iteritems())
 
-    def adapter_hook(self, provided, object, name=u'', default=None):
-        required = providedBy(object)
-        cache = self._getcache(provided, name)
-        factory = cache.get(required, _not_in_mapping)
-        if factory is _not_in_mapping:
-            factory = self.lookup((required, ), provided, name)
-
-        if factory is not None:
-            result = factory(object)
-            if result is not None:
-                return result
-
-        return default
-
-    def lookupAll(self, required, provided):
-        cache = self._mcache.get(provided)
-        if cache is None:
-            cache = {}
-            self._mcache[provided] = cache
-
-        required = tuple(required)
-        result = cache.get(required, _not_in_mapping)
-        if result is _not_in_mapping:
-            order = len(required)
-            result = {}
-            for registry in reversed(self._registry.ro):
-                byorder = registry._adapters
-                if order >= len(byorder):
-                    continue
-                extendors = registry._v_lookup._extendors.get(provided)
-                if not extendors:
-                    continue
-                components = byorder[order]
-                _lookupAll(components, required, extendors, result, 0, order)
-
-            self._subscribe(*required)
-            cache[required] = result
-
-        return result.iteritems()
-
     def names(self, required, provided):
         return [c[0] for c in self.lookupAll(required, provided)]
 
-    def subscriptions(self, required, provided):
-        cache = self._scache.get(provided)
-        if cache is None:
-            cache = {}
-            self._scache[provided] = cache
+    def _uncached_subscriptions(self, required, provided):
+        order = len(required)
+        result = []
+        for registry in reversed(self._registry.ro):
+            byorder = registry._subscribers
+            if order >= len(byorder):
+                continue
 
-        required = tuple(required)
-        result = cache.get(required, _not_in_mapping)
-        if result is _not_in_mapping:
-            order = len(required)
-            result = []
-            for registry in reversed(self._registry.ro):
-                byorder = registry._subscribers
-                if order >= len(byorder):
+            if provided is None:
+                extendors = (provided, )
+            else:
+                extendors = registry._v_lookup._extendors.get(provided)
+                if extendors is None:
                     continue
 
-                if provided is None:
-                    extendors = (provided, )
-                else:
-                    extendors = registry._v_lookup._extendors.get(provided)
-                    if extendors is None:
-                        continue
+            _subscriptions(byorder[order], required, extendors, u'',
+                           result, 0, order)
 
-                _subscriptions(byorder[order], required, extendors, u'',
-                               result, 0, order)
+        self._subscribe(*required)
 
-            self._subscribe(*required)
-            cache[required] = result
-
         return result
 
     def subscribers(self, objects, provided):
@@ -482,6 +541,9 @@
                     result.append(subscriber)
         return result
 
+class AdapterLookup(AdapterLookupBase, LookupBase):
+    pass
+
 class AdapterRegistry(BaseAdapterRegistry):
 
     LookupClass = AdapterLookup
@@ -518,43 +580,9 @@
             sub.changed(originally_changed)
 
 
-class VerifyingAdapterLookup(AdapterLookup):
+class VerifyingAdapterLookup(AdapterLookupBase, VerifyingBase):
+    pass
 
-    def __init__(self, registry):
-        super(VerifyingAdapterLookup, self).__init__(registry)
-
-    def changed(self, originally_changed):
-        super(VerifyingAdapterLookup, self).changed(originally_changed)
-        self._verify_ro = self._registry.ro[1:]
-        self._verify_generations = [r._generation for r in self._verify_ro]
-
-    def _verify(self):
-        if ([r._generation for r in self._verify_ro]
-            != self._verify_generations):
-            self.changed(None)
-
-    def _getcache(self, provided, name):
-        self._verify()
-
-        # The non-use of super here is intentional.  A C implementation
-        # will call AdapterLookup's C implementation directly.
-        return AdapterLookup._getcache(self, provided, name)
-    
-    def lookupAll(self, required, provided):
-        self._verify()
-
-        # The non-use of super here is intentional.  A C implementation
-        # will call AdapterLookup's C implementation directly.
-        return AdapterLookup.lookupAll(self, required, provided)
-
-    def subscriptions(self, required, provided):
-        self._verify()
-
-        # The non-use of super here is intentional.  A C implementation
-        # will call AdapterLookup's C implementation directly.
-        return AdapterLookup.subscriptions(self, required, provided)
-
-
 class VerifyingAdapterRegistry(BaseAdapterRegistry):
 
     LookupClass = VerifyingAdapterLookup



More information about the Checkins mailing list