summaryrefslogtreecommitdiff
path: root/src/zope/interface/_zope_interface_coptimizations.c
diff options
context:
space:
mode:
authorJason Madden <jamadden@gmail.com>2020-04-03 09:55:43 -0500
committerJason Madden <jamadden@gmail.com>2020-04-06 09:14:45 -0500
commit10eadd6305ee57910dbcc508b293f4bf0364fd84 (patch)
tree63a450400cf79c33cb21a1a81d4c00371bf84dcc /src/zope/interface/_zope_interface_coptimizations.c
parent1af83ef9f90aa7a558314892b72eec6d62263981 (diff)
downloadzope-interface-issue3.tar.gz
Let interface 'subclasses' override __adapt__.issue3
Cooperate with InterfaceClass to ensure there is no performance penalty for this. Fixes #3 +-------------------------------------------------------------+----------------+------------------------------+------------------------------+ | Benchmark | bench_master38 | bench_issue3 | bench_issue3_opt | +=============================================================+================+==============================+==============================+ | call interface (provides; deep) | 369 ns | 454 ns: 1.23x slower (+23%) | not significant | +-------------------------------------------------------------+----------------+------------------------------+------------------------------+ | call interface (provides; wide) | 373 ns | 457 ns: 1.22x slower (+22%) | 365 ns: 1.02x faster (-2%) | +-------------------------------------------------------------+----------------+------------------------------+------------------------------+ | call interface (no alternate, no conform, not provided) | 671 ns | 760 ns: 1.13x slower (+13%) | 636 ns: 1.06x faster (-5%) | +-------------------------------------------------------------+----------------+------------------------------+------------------------------+ | call interface (alternate, no conform, not provided) | 395 ns | 494 ns: 1.25x slower (+25%) | not significant | +-------------------------------------------------------------+----------------+------------------------------+------------------------------+ | call interface (no alternate, valid conform, not provided) | 250 ns | not significant | 227 ns: 1.10x faster (-9%) | +-------------------------------------------------------------+----------------+------------------------------+------------------------------+ | call interface (alternate, invalid conform, not provided) | 348 ns | 424 ns: 1.22x slower (+22%) | not significant | +-------------------------------------------------------------+----------------+------------------------------+------------------------------+
Diffstat (limited to 'src/zope/interface/_zope_interface_coptimizations.c')
-rw-r--r--src/zope/interface/_zope_interface_coptimizations.c26
1 files changed, 23 insertions, 3 deletions
diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c
index 69f5bbc..346e7f2 100644
--- a/src/zope/interface/_zope_interface_coptimizations.c
+++ b/src/zope/interface/_zope_interface_coptimizations.c
@@ -49,6 +49,8 @@ static PyObject *str_registry, *strro, *str_generation, *strchanged;
static PyObject *str__self__;
static PyObject *str__module__;
static PyObject *str__name__;
+static PyObject *str__adapt__;
+static PyObject *str_CALL_CUSTOM_ADAPT;
static PyTypeObject *Implements;
@@ -796,7 +798,7 @@ static struct PyMethodDef ib_methods[] = {
*/
static PyObject *
-ib_call(PyObject *self, PyObject *args, PyObject *kwargs)
+IB_call(PyObject *self, PyObject *args, PyObject *kwargs)
{
PyObject *conform, *obj, *alternate, *adapter;
static char *kwlist[] = {"obj", "alternate", NULL};
@@ -835,7 +837,23 @@ ib_call(PyObject *self, PyObject *args, PyObject *kwargs)
Py_DECREF(conform);
}
- adapter = __adapt__(self, obj); // XXX: should be self.__adapt__.
+ /* We differ from the Python code here. For speed, instead of always calling
+ self.__adapt__(), we check to see if the type has defined it. Checking in
+ the dict for __adapt__ isn't sufficient because there's no cheap way to
+ tell if it's the __adapt__ that InterfaceBase itself defines (our type
+ will *never* be InterfaceBase, we're always subclassed by
+ InterfaceClass). Instead, we cooperate with InterfaceClass in Python to
+ set a flag in a new subclass when this is necessary. */
+ if (PyDict_GetItem(self->ob_type->tp_dict, str_CALL_CUSTOM_ADAPT))
+ {
+ /* Doesn't matter what the value is. Simply being present is enough. */
+ adapter = PyObject_CallMethodObjArgs(self, str__adapt__, obj, NULL);
+ }
+ else
+ {
+ adapter = __adapt__(self, obj);
+ }
+
if (adapter == NULL || adapter != Py_None)
{
return adapter;
@@ -1045,7 +1063,7 @@ static PyTypeObject InterfaceBaseType = {
/* tp_as_sequence */ 0,
/* tp_as_mapping */ 0,
/* tp_hash */ (hashfunc)IB_hash,
- /* tp_call */ (ternaryfunc)ib_call,
+ /* tp_call */ (ternaryfunc)IB_call,
/* tp_str */ (reprfunc)0,
/* tp_getattro */ (getattrofunc)0,
/* tp_setattro */ (setattrofunc)0,
@@ -2023,6 +2041,8 @@ init(void)
DEFINE_STRING(__self__);
DEFINE_STRING(__name__);
DEFINE_STRING(__module__);
+ DEFINE_STRING(__adapt__);
+ DEFINE_STRING(_CALL_CUSTOM_ADAPT);
#undef DEFINE_STRING
adapter_hooks = PyList_New(0);
if (adapter_hooks == NULL)