[Zope3-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 Zope3-Checkins
mailing list