diff options
| author | Jason Madden <jamadden@gmail.com> | 2020-04-03 09:55:43 -0500 |
|---|---|---|
| committer | Jason Madden <jamadden@gmail.com> | 2020-04-06 09:14:45 -0500 |
| commit | 10eadd6305ee57910dbcc508b293f4bf0364fd84 (patch) | |
| tree | 63a450400cf79c33cb21a1a81d4c00371bf84dcc /src/zope/interface/_zope_interface_coptimizations.c | |
| parent | 1af83ef9f90aa7a558314892b72eec6d62263981 (diff) | |
| download | zope-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.c | 26 |
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) |
