diff options
author | robot-piglet <robot-piglet@yandex-team.com> | 2024-08-28 17:49:28 +0300 |
---|---|---|
committer | robot-piglet <robot-piglet@yandex-team.com> | 2024-08-28 17:58:46 +0300 |
commit | 05f1a7bca5400633bcb52b58affe23880df1fd0e (patch) | |
tree | 87744c3c5cb786fddbe15004779b941988a0b7d7 /contrib/python/zope.interface/py3/zope/interface/_zope_interface_coptimizations.c | |
parent | dc1a94ab8d6985d2dcf888fa1881e7b80f7042b1 (diff) | |
download | ydb-05f1a7bca5400633bcb52b58affe23880df1fd0e.tar.gz |
Intermediate changes
Diffstat (limited to 'contrib/python/zope.interface/py3/zope/interface/_zope_interface_coptimizations.c')
-rw-r--r-- | contrib/python/zope.interface/py3/zope/interface/_zope_interface_coptimizations.c | 3447 |
1 files changed, 2021 insertions, 1426 deletions
diff --git a/contrib/python/zope.interface/py3/zope/interface/_zope_interface_coptimizations.c b/contrib/python/zope.interface/py3/zope/interface/_zope_interface_coptimizations.c index 2cf453a7e6..453057a4d6 100644 --- a/contrib/python/zope.interface/py3/zope/interface/_zope_interface_coptimizations.c +++ b/contrib/python/zope.interface/py3/zope/interface/_zope_interface_coptimizations.c @@ -24,299 +24,197 @@ #define TYPE(O) ((PyTypeObject*)(O)) #define OBJECT(O) ((PyObject*)(O)) #define CLASSIC(O) ((PyClassObject*)(O)) -#ifndef PyVarObject_HEAD_INIT -#define PyVarObject_HEAD_INIT(a, b) PyObject_HEAD_INIT(a) b, -#endif #ifndef Py_TYPE #define Py_TYPE(o) ((o)->ob_type) #endif #define PyNative_FromString PyUnicode_FromString -static PyObject *str__dict__, *str__implemented__, *strextends; -static PyObject *BuiltinImplementationSpecifications, *str__provides__; -static PyObject *str__class__, *str__providedBy__; -static PyObject *empty, *fallback; -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 PyObject *str__self__; -static PyObject *str__module__; -static PyObject *str__name__; -static PyObject *str__adapt__; -static PyObject *str_CALL_CUSTOM_ADAPT; - -static PyTypeObject *Implements; - -static int imported_declarations = 0; - -static int -import_declarations(void) -{ - PyObject *declarations, *i; - - declarations = PyImport_ImportModule("zope.interface.declarations"); - if (declarations == NULL) - return -1; - - BuiltinImplementationSpecifications = PyObject_GetAttrString( - declarations, "BuiltinImplementationSpecifications"); - if (BuiltinImplementationSpecifications == NULL) - return -1; - - empty = PyObject_GetAttrString(declarations, "_empty"); - if (empty == NULL) - return -1; - - fallback = PyObject_GetAttrString(declarations, "implementedByFallback"); - if (fallback == NULL) - return -1; - - - - i = PyObject_GetAttrString(declarations, "Implements"); - if (i == NULL) - return -1; - - if (! PyType_Check(i)) - { - PyErr_SetString(PyExc_TypeError, - "zope.interface.declarations.Implements is not a type"); - return -1; +#define ASSURE_DICT(N) \ + if (N == NULL) { \ + N = PyDict_New(); \ + if (N == NULL) \ + return NULL; \ } - Implements = (PyTypeObject *)i; - - Py_DECREF(declarations); - - imported_declarations = 1; - return 0; -} - +/* + * Don't use heap-allocated types for Python < 3.11: the API needed + * to find the dynamic module, 'PyType_GetModuleByDef', was added then. + */ +#if PY_VERSION_HEX < 0x030b0000 +#define USE_STATIC_TYPES 1 +#define USE_HEAP_TYPES 0 +#else +#define USE_STATIC_TYPES 0 +#define USE_HEAP_TYPES 1 +#endif -static PyTypeObject SpecificationBaseType; /* Forward */ +#if PY_VERSION_HEX >= 0x030c0000 +/* Add MANAGED_WEAKREF flag for Python >= 3.12, and don't define + * the '.tp_weaklistoffset' slot. + * + * See: https://docs.python.org/3/c-api/typeobj.html + * #c.PyTypeObject.tp_weaklistoffset + */ +#define USE_EXPLICIT_WEAKREFLIST 0 +#define BASETYPE_FLAGS \ + Py_TPFLAGS_DEFAULT | \ + Py_TPFLAGS_BASETYPE | \ + Py_TPFLAGS_MANAGED_WEAKREF | \ + Py_TPFLAGS_HAVE_GC +#else +/* No MANAGED_WEAKREF flag for Python < 3.12, and therefore define + * the '.tp_weaklistoffset' slot, and the member whose offset it holds. + * + * See: https://docs.python.org/3/c-api/typeobj.html + * #c.PyTypeObject.tp_weaklistoffset + */ +#define USE_EXPLICIT_WEAKREFLIST 1 +#define BASETYPE_FLAGS \ + Py_TPFLAGS_DEFAULT | \ + Py_TPFLAGS_BASETYPE | \ + Py_TPFLAGS_HAVE_GC +#endif -static PyObject * -implementedByFallback(PyObject *cls) -{ - if (imported_declarations == 0 && import_declarations() < 0) - return NULL; +/* Static strings, used to invoke PyObject_GetAttr (only in hot paths) */ +static PyObject *str__class__ = NULL; +static PyObject *str__conform__ = NULL; +static PyObject *str__dict__ = NULL; +static PyObject *str__module__ = NULL; +static PyObject *str__name__ = NULL; +static PyObject *str__providedBy__ = NULL; +static PyObject *str__provides__ = NULL; +static PyObject *str__self__ = NULL; +static PyObject *str_generation = NULL; +static PyObject *str_registry = NULL; +static PyObject *strro = NULL; + +/* Static strings, used to invoke PyObject_CallMethodObjArgs */ +static PyObject *str_call_conform = NULL; +static PyObject *str_uncached_lookup = NULL; +static PyObject *str_uncached_lookupAll = NULL; +static PyObject *str_uncached_subscriptions = NULL; +static PyObject *strchanged = NULL; +static PyObject *str__adapt__ = NULL; + +/* Static strings, used to invoke PyObject_GetItem + * + * We cannot use PyDict_GetItemString, because the '__dict__' we get + * from our types can be a 'types.mappingproxy', which causes a segfault. + */ +static PyObject* str__implemented__; - return PyObject_CallFunctionObjArgs(fallback, cls, NULL); -} -static PyObject * -implementedBy(PyObject *ignored, PyObject *cls) +static int +define_static_strings() { - /* Fast retrieval of implements spec, if possible, to optimize - common case. Use fallback code if we get stuck. - */ - - PyObject *dict = NULL, *spec; - - if (PyObject_TypeCheck(cls, &PySuper_Type)) - { - // Let merging be handled by Python. - return implementedByFallback(cls); - } - - if (PyType_Check(cls)) - { - dict = TYPE(cls)->tp_dict; - Py_XINCREF(dict); + if (str__class__ != NULL) { + return 0; } - if (dict == NULL) - dict = PyObject_GetAttr(cls, str__dict__); +#define DEFINE_STATIC_STRING(S) \ + if (!(str##S = PyUnicode_FromString(#S))) \ + return -1 + + DEFINE_STATIC_STRING(__class__); + DEFINE_STATIC_STRING(__conform__); + DEFINE_STATIC_STRING(__dict__); + DEFINE_STATIC_STRING(__module__); + DEFINE_STATIC_STRING(__name__); + DEFINE_STATIC_STRING(__providedBy__); + DEFINE_STATIC_STRING(__provides__); + DEFINE_STATIC_STRING(__self__); + DEFINE_STATIC_STRING(_generation); + DEFINE_STATIC_STRING(_registry); + DEFINE_STATIC_STRING(ro); + DEFINE_STATIC_STRING(__implemented__); + DEFINE_STATIC_STRING(_call_conform); + DEFINE_STATIC_STRING(_uncached_lookup); + DEFINE_STATIC_STRING(_uncached_lookupAll); + DEFINE_STATIC_STRING(_uncached_subscriptions); + DEFINE_STATIC_STRING(changed); + DEFINE_STATIC_STRING(__adapt__); +#undef DEFINE_STATIC_STRING - if (dict == NULL) - { - /* Probably a security proxied class, use more expensive fallback code */ - PyErr_Clear(); - return implementedByFallback(cls); - } - - spec = PyObject_GetItem(dict, str__implemented__); - Py_DECREF(dict); - if (spec) - { - if (imported_declarations == 0 && import_declarations() < 0) - return NULL; + return 0; +} - if (PyObject_TypeCheck(spec, Implements)) - return spec; +/* Public module-scope functions, forward-declared here for type methods. */ +static PyObject *implementedBy(PyObject* module, PyObject *cls); +static PyObject *getObjectSpecification(PyObject *module, PyObject *ob); +static PyObject *providedBy(PyObject *module, PyObject *ob); - /* Old-style declaration, use more expensive fallback code */ - Py_DECREF(spec); - return implementedByFallback(cls); - } +/* + * Utility functions, forward-declared here for type methods. + */ +static PyObject* _get_module(PyTypeObject *typeobj); +static PyObject* _get_adapter_hooks(PyTypeObject *typeobj); +static PyTypeObject* _get_specification_base_class(PyTypeObject *typeobj); +static PyTypeObject* _get_interface_base_class(PyTypeObject *typeobj); + +#if USE_STATIC_TYPES +/* + * Global used by static IB__adapt + */ +static PyObject* adapter_hooks = NULL; - PyErr_Clear(); +/* + * Globals imported from 'zope.interface.declarations' + */ +static int imported_declarations = 0; +static PyObject* BuiltinImplementationSpecifications; +static PyObject* empty; +static PyObject* fallback; +static PyTypeObject *Implements; - /* Maybe we have a builtin */ - if (imported_declarations == 0 && import_declarations() < 0) - return NULL; +/* Import zope.interface.declarations and store results in global statics. + * + * Static alternative to '_zic_state_load_declarations' below. + */ +static int +import_declarations(void) +{ + PyObject *declarations, *i; - spec = PyDict_GetItem(BuiltinImplementationSpecifications, cls); - if (spec != NULL) - { - Py_INCREF(spec); - return spec; - } + declarations = PyImport_ImportModule("zope.interface.declarations"); + if (declarations == NULL) { return -1; } - /* We're stuck, use fallback */ - return implementedByFallback(cls); -} - -static PyObject * -getObjectSpecification(PyObject *ignored, PyObject *ob) -{ - PyObject *cls, *result; - - result = PyObject_GetAttr(ob, str__provides__); - if (!result) - { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - { - /* Propagate non AttributeError exceptions. */ - return NULL; - } - PyErr_Clear(); - } - else - { - int is_instance = -1; - is_instance = PyObject_IsInstance(result, (PyObject*)&SpecificationBaseType); - if (is_instance < 0) - { - /* Propagate all errors */ - return NULL; - } - if (is_instance) - { - return result; - } - } - - /* We do a getattr here so as not to be defeated by proxies */ - cls = PyObject_GetAttr(ob, str__class__); - if (cls == NULL) - { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - { - /* Propagate non-AttributeErrors */ - return NULL; - } - PyErr_Clear(); - if (imported_declarations == 0 && import_declarations() < 0) - return NULL; - - Py_INCREF(empty); - return empty; - } - result = implementedBy(NULL, cls); - Py_DECREF(cls); - - return result; -} - -static PyObject * -providedBy(PyObject *ignored, PyObject *ob) -{ - PyObject *result, *cls, *cp; - int is_instance = -1; - result = NULL; - - is_instance = PyObject_IsInstance(ob, (PyObject*)&PySuper_Type); - if (is_instance < 0) - { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - { - /* Propagate non-AttributeErrors */ - return NULL; - } - PyErr_Clear(); - } - if (is_instance) - { - return implementedBy(NULL, ob); - } - - result = PyObject_GetAttr(ob, str__providedBy__); - - if (result == NULL) - { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - { - return NULL; - } - - PyErr_Clear(); - return getObjectSpecification(NULL, ob); - } - - - /* We want to make sure we have a spec. We can't do a type check - because we may have a proxy, so we'll just try to get the - only attribute. - */ - if (PyObject_TypeCheck(result, &SpecificationBaseType) - || - PyObject_HasAttr(result, strextends) - ) - return result; + BuiltinImplementationSpecifications = PyObject_GetAttrString( + declarations, "BuiltinImplementationSpecifications"); + if (BuiltinImplementationSpecifications == NULL) { return -1; } - /* - The object's class doesn't understand descriptors. - Sigh. We need to get an object descriptor, but we have to be - careful. We want to use the instance's __provides__,l if - there is one, but only if it didn't come from the class. - */ - Py_DECREF(result); + empty = PyObject_GetAttrString(declarations, "_empty"); + if (empty == NULL) { return -1; } - cls = PyObject_GetAttr(ob, str__class__); - if (cls == NULL) - return NULL; + fallback = PyObject_GetAttrString(declarations, "implementedByFallback"); + if (fallback == NULL) { return -1;} - result = PyObject_GetAttr(ob, str__provides__); - if (result == NULL) - { - /* No __provides__, so just fall back to implementedBy */ - PyErr_Clear(); - result = implementedBy(NULL, cls); - Py_DECREF(cls); - return result; - } + i = PyObject_GetAttrString(declarations, "Implements"); + if (i == NULL) { return -1; } - cp = PyObject_GetAttr(cls, str__provides__); - if (cp == NULL) - { - /* The the class has no provides, assume we're done: */ - PyErr_Clear(); - Py_DECREF(cls); - return result; + if (! PyType_Check(i)) { + PyErr_SetString( + PyExc_TypeError, + "zope.interface.declarations.Implements is not a type"); + return -1; } - if (cp == result) - { - /* - Oops, we got the provides from the class. This means - the object doesn't have it's own. We should use implementedBy - */ - Py_DECREF(result); - result = implementedBy(NULL, cls); - } + Implements = (PyTypeObject *)i; - Py_DECREF(cls); - Py_DECREF(cp); + Py_DECREF(declarations); - return result; + imported_declarations = 1; + return 0; } -typedef struct { +#endif + +/* + * SpecificationBase class + */ +typedef struct +{ PyObject_HEAD - PyObject* weakreflist; /* In the past, these fields were stored in the __dict__ and were technically allowed to contain any Python object, though @@ -325,6 +223,9 @@ typedef struct { make any assumptions about contents. */ PyObject* _implied; +#if USE_EXPLICIT_WEAKREFLIST + PyObject* weakreflist; +#endif /* The remainder aren't used in C code but must be stored here to prevent instance layout conflicts. @@ -334,15 +235,22 @@ typedef struct { PyObject* _v_attrs; PyObject* __iro__; PyObject* __sro__; -} Spec; +} SB; /* We know what the fields are *supposed* to define, but they could have anything, so we need to traverse them. */ static int -Spec_traverse(Spec* self, visitproc visit, void* arg) +SB_traverse(SB* self, visitproc visit, void* arg) { +/* Visit our 'tp_type' only on Python >= 3.9, per + * https://docs.python.org/3/howto/isolating-extensions.html + * #tp-traverse-in-python-3-8-and-lower + */ +#if USE_HEAP_TYPES && PY_VERSION_HEX > 0x03090000 + Py_VISIT(Py_TYPE(self)); +#endif Py_VISIT(self->_implied); Py_VISIT(self->_dependents); Py_VISIT(self->_bases); @@ -353,7 +261,7 @@ Spec_traverse(Spec* self, visitproc visit, void* arg) } static int -Spec_clear(Spec* self) +SB_clear(SB* self) { Py_CLEAR(self->_implied); Py_CLEAR(self->_dependents); @@ -365,246 +273,295 @@ Spec_clear(Spec* self) } static void -Spec_dealloc(Spec* self) +SB_dealloc(SB* self) { - /* PyType_GenericAlloc that you get when you don't - specify a tp_alloc always tracks the object. */ - PyObject_GC_UnTrack((PyObject *)self); + PyObject_GC_UnTrack((PyObject*)self); + PyTypeObject* tp = Py_TYPE(self); +#if USE_EXPLICIT_WEAKREFLIST if (self->weakreflist != NULL) { PyObject_ClearWeakRefs(OBJECT(self)); } - Spec_clear(self); - Py_TYPE(self)->tp_free(OBJECT(self)); +#endif + SB_clear(self); + tp->tp_free(OBJECT(self)); +#if USE_HEAP_TYPES + Py_DECREF(tp); +#endif } -static PyObject * -Spec_extends(Spec *self, PyObject *other) +static char SB_extends__doc__[] = + "Test whether a specification is or extends another"; + +static PyObject* +SB_extends(SB* self, PyObject* other) { - PyObject *implied; + PyObject* implied; - implied = self->_implied; - if (implied == NULL) { - return NULL; - } + implied = self->_implied; + if (implied == NULL) { + return NULL; + } - if (PyDict_GetItem(implied, other) != NULL) - Py_RETURN_TRUE; - Py_RETURN_FALSE; + if (PyDict_GetItem(implied, other) != NULL) + Py_RETURN_TRUE; + Py_RETURN_FALSE; } -static char Spec_extends__doc__[] = -"Test whether a specification is or extends another" -; - -static char Spec_providedBy__doc__[] = -"Test whether an interface is implemented by the specification" -; - -static PyObject * -Spec_call(Spec *self, PyObject *args, PyObject *kw) +static PyObject* +SB__call__(SB* self, PyObject* args, PyObject* kw) { - PyObject *spec; + PyObject* spec; - if (! PyArg_ParseTuple(args, "O", &spec)) - return NULL; - return Spec_extends(self, spec); + if (!PyArg_ParseTuple(args, "O", &spec)) + return NULL; + return SB_extends(self, spec); } -static PyObject * -Spec_providedBy(PyObject *self, PyObject *ob) +static char SB_providedBy__doc__[] = + "Test whether an interface is implemented by the specification"; + +static PyObject* +SB_providedBy(PyObject* self, PyObject* ob) { - PyObject *decl, *item; + PyObject *decl; + PyObject *item; + PyObject *module; + PyTypeObject *specification_base_class; - decl = providedBy(NULL, ob); - if (decl == NULL) - return NULL; + module = _get_module(Py_TYPE(self)); + specification_base_class = _get_specification_base_class(Py_TYPE(self)); - if (PyObject_TypeCheck(decl, &SpecificationBaseType)) - item = Spec_extends((Spec*)decl, self); - else - /* decl is probably a security proxy. We have to go the long way - around. - */ - item = PyObject_CallFunctionObjArgs(decl, self, NULL); + decl = providedBy(module, ob); + if (decl == NULL) + return NULL; - Py_DECREF(decl); - return item; -} + if (PyObject_TypeCheck(decl, specification_base_class)) + item = SB_extends((SB*)decl, self); + else + /* decl is probably a security proxy. We have to go the long way + around. + */ + item = PyObject_CallFunctionObjArgs(decl, self, NULL); + Py_DECREF(decl); + return item; +} -static char Spec_implementedBy__doc__[] = -"Test whether the specification is implemented by a class or factory.\n" -"Raise TypeError if argument is neither a class nor a callable." -; +static char SB_implementedBy__doc__[] = + "Test whether the specification is implemented by a class or factory.\n" + "Raise TypeError if argument is neither a class nor a callable."; -static PyObject * -Spec_implementedBy(PyObject *self, PyObject *cls) +static PyObject* +SB_implementedBy(PyObject* self, PyObject* cls) { - PyObject *decl, *item; + PyObject *decl; + PyObject *item; + PyObject *module; + PyTypeObject *specification_base_class; - decl = implementedBy(NULL, cls); - if (decl == NULL) - return NULL; + module = _get_module(Py_TYPE(self)); + specification_base_class = _get_specification_base_class(Py_TYPE(self)); - if (PyObject_TypeCheck(decl, &SpecificationBaseType)) - item = Spec_extends((Spec*)decl, self); - else - item = PyObject_CallFunctionObjArgs(decl, self, NULL); + decl = implementedBy(module, cls); + if (decl == NULL) + return NULL; + + if (PyObject_TypeCheck(decl, specification_base_class)) + item = SB_extends((SB*)decl, self); + else + item = PyObject_CallFunctionObjArgs(decl, self, NULL); - Py_DECREF(decl); - return item; + Py_DECREF(decl); + return item; } -static struct PyMethodDef Spec_methods[] = { - {"providedBy", - (PyCFunction)Spec_providedBy, METH_O, - Spec_providedBy__doc__}, - {"implementedBy", - (PyCFunction)Spec_implementedBy, METH_O, - Spec_implementedBy__doc__}, - {"isOrExtends", (PyCFunction)Spec_extends, METH_O, - Spec_extends__doc__}, +static struct PyMethodDef SB_methods[] = { + { "providedBy", + (PyCFunction)SB_providedBy, + METH_O, + SB_providedBy__doc__ }, + { "implementedBy", + (PyCFunction)SB_implementedBy, + METH_O, + SB_implementedBy__doc__ }, + { "isOrExtends", + (PyCFunction)SB_extends, + METH_O, + SB_extends__doc__ }, + + { NULL, NULL } /* sentinel */ +}; - {NULL, NULL} /* sentinel */ +static PyMemberDef SB_members[] = { + { "_implied", T_OBJECT_EX, offsetof(SB, _implied), 0, "" }, + { "_dependents", T_OBJECT_EX, offsetof(SB, _dependents), 0, "" }, + { "_bases", T_OBJECT_EX, offsetof(SB, _bases), 0, "" }, + { "_v_attrs", T_OBJECT_EX, offsetof(SB, _v_attrs), 0, "" }, + { "__iro__", T_OBJECT_EX, offsetof(SB, __iro__), 0, "" }, + { "__sro__", T_OBJECT_EX, offsetof(SB, __sro__), 0, "" }, +#if USE_EXPLICIT_WEAKREFLIST + { "__weaklistoffset__", T_PYSSIZET, offsetof(SB, weakreflist), READONLY, "" }, +#endif + { NULL }, }; -static PyMemberDef Spec_members[] = { - {"_implied", T_OBJECT_EX, offsetof(Spec, _implied), 0, ""}, - {"_dependents", T_OBJECT_EX, offsetof(Spec, _dependents), 0, ""}, - {"_bases", T_OBJECT_EX, offsetof(Spec, _bases), 0, ""}, - {"_v_attrs", T_OBJECT_EX, offsetof(Spec, _v_attrs), 0, ""}, - {"__iro__", T_OBJECT_EX, offsetof(Spec, __iro__), 0, ""}, - {"__sro__", T_OBJECT_EX, offsetof(Spec, __sro__), 0, ""}, - {NULL}, +static char SB__name__[] = "_zope_interface_coptimizations.SpecificationBase"; +static char SB__doc__[] = "Base type for Specification objects"; + +#if USE_STATIC_TYPES + +/* + * Static type: SpecificationBase + */ + +static PyTypeObject SB_type_def = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = SB__name__, + .tp_doc = SB__doc__, + .tp_basicsize = sizeof(SB), + .tp_flags = BASETYPE_FLAGS, + .tp_call = (ternaryfunc)SB__call__, + .tp_traverse = (traverseproc)SB_traverse, + .tp_clear = (inquiry)SB_clear, + .tp_dealloc = (destructor)SB_dealloc, +#if USE_EXPLICIT_WEAKREFLIST + .tp_weaklistoffset = offsetof(SB, weakreflist), +#endif + .tp_methods = SB_methods, + .tp_members = SB_members, }; +#else -static PyTypeObject SpecificationBaseType = { - PyVarObject_HEAD_INIT(NULL, 0) - /* tp_name */ "_interface_coptimizations." - "SpecificationBase", - /* tp_basicsize */ sizeof(Spec), - /* tp_itemsize */ 0, - /* tp_dealloc */ (destructor)Spec_dealloc, - /* tp_print */ (printfunc)0, - /* tp_getattr */ (getattrfunc)0, - /* tp_setattr */ (setattrfunc)0, - /* tp_compare */ 0, - /* tp_repr */ (reprfunc)0, - /* tp_as_number */ 0, - /* tp_as_sequence */ 0, - /* tp_as_mapping */ 0, - /* tp_hash */ (hashfunc)0, - /* tp_call */ (ternaryfunc)Spec_call, - /* 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, - "Base type for Specification objects", - /* tp_traverse */ (traverseproc)Spec_traverse, - /* tp_clear */ (inquiry)Spec_clear, - /* tp_richcompare */ (richcmpfunc)0, - /* tp_weaklistoffset */ offsetof(Spec, weakreflist), - /* tp_iter */ (getiterfunc)0, - /* tp_iternext */ (iternextfunc)0, - /* tp_methods */ Spec_methods, - /* tp_members */ Spec_members, +/* + * Heap-based type: SpecificationBase + */ +static PyType_Slot SB_type_slots[] = { + {Py_tp_doc, SB__doc__}, + {Py_tp_call, SB__call__}, + {Py_tp_traverse, SB_traverse}, + {Py_tp_clear, SB_clear}, + {Py_tp_dealloc, SB_dealloc}, + {Py_tp_methods, SB_methods}, + {Py_tp_members, SB_members}, + {0, NULL} }; -static PyObject * -OSD_descr_get(PyObject *self, PyObject *inst, PyObject *cls) -{ - PyObject *provides; - - if (inst == NULL) - return getObjectSpecification(NULL, cls); - - provides = PyObject_GetAttr(inst, str__provides__); - /* Return __provides__ if we got it, or return NULL and propagate non-AttributeError. */ - if (provides != NULL || !PyErr_ExceptionMatches(PyExc_AttributeError)) - return provides; - - PyErr_Clear(); - return implementedBy(NULL, cls); -} - -static PyTypeObject OSDType = { - PyVarObject_HEAD_INIT(NULL, 0) - /* tp_name */ "_interface_coptimizations." - "ObjectSpecificationDescriptor", - /* tp_basicsize */ 0, - /* tp_itemsize */ 0, - /* tp_dealloc */ (destructor)0, - /* tp_print */ (printfunc)0, - /* tp_getattr */ (getattrfunc)0, - /* tp_setattr */ (setattrfunc)0, - /* tp_compare */ 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 , - "Object Specification Descriptor", - /* tp_traverse */ (traverseproc)0, - /* tp_clear */ (inquiry)0, - /* tp_richcompare */ (richcmpfunc)0, - /* tp_weaklistoffset */ (long)0, - /* tp_iter */ (getiterfunc)0, - /* tp_iternext */ (iternextfunc)0, - /* tp_methods */ 0, - /* tp_members */ 0, - /* tp_getset */ 0, - /* tp_base */ 0, - /* tp_dict */ 0, /* internal use */ - /* tp_descr_get */ (descrgetfunc)OSD_descr_get, +static PyType_Spec SB_type_spec = { + .name = SB__name__, + .basicsize = sizeof(SB), + .flags = BASETYPE_FLAGS, + .slots = SB_type_slots }; -typedef struct { - Spec spec; - /* These members are handled generically, as for Spec members. */ - PyObject* _cls; - PyObject* _implements; -} CPB; +#endif -static PyObject * -CPB_descr_get(CPB *self, PyObject *inst, PyObject *cls) +/* + * ObjectSpecificationDescriptor class + */ +#if USE_HEAP_TYPES +static int +OSD_traverse(PyObject* self, visitproc visit, void* arg) { - PyObject *implements; + Py_VISIT(Py_TYPE(self)); + return 0; +} - if (self->_cls == NULL) - return NULL; +static void +OSD_dealloc(PyObject* self) +{ + PyObject_GC_UnTrack(self); + PyTypeObject *tp = Py_TYPE(self); + tp->tp_free(OBJECT(self)); + Py_DECREF(tp); +} +#endif - if (cls == self->_cls) - { - if (inst == NULL) - { - Py_INCREF(self); - return OBJECT(self); - } +static PyObject* +OSD_descr_get(PyObject* self, PyObject* inst, PyObject* cls) +{ + PyObject* provides; + PyObject *module; + + module = _get_module(Py_TYPE(self)); - implements = self->_implements; - Py_XINCREF(implements); - return implements; + if (inst == NULL) { + return getObjectSpecification(module, cls); } - PyErr_SetObject(PyExc_AttributeError, str__provides__); - return NULL; + provides = PyObject_GetAttr(inst, str__provides__); + /* Return __provides__ if we got it, or return NULL and propagate + * non-AttributeError. */ + if (provides != NULL || !PyErr_ExceptionMatches(PyExc_AttributeError)) { + return provides; + } + + PyErr_Clear(); + + return implementedBy(module, cls); } +static char OSD__name__[] = ( + "_zope_interface_coptimizations.ObjectSpecificationDescriptor"); +static char OSD__doc__[] = "Object Specification Descriptor"; + +#if USE_STATIC_TYPES + +/* + * Static type: ObjectSpecificationDescriptor + */ + +static PyTypeObject OSD_type_def = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = OSD__name__, + .tp_doc = OSD__doc__, + /* No GC for the static version */ + .tp_flags = Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE, + .tp_descr_get = (descrgetfunc)OSD_descr_get, + /*.tp_traverse, = OSD_traverse}, not reqd for static */ + /*.tp_dealloc, = OSD_dealloc}, not reqd for static */ +}; + +#else + +/* + * Heap type: ObjectSpecificationDescriptor + */ +static PyType_Slot OSD_type_slots[] = { + {Py_tp_doc, OSD__doc__}, + {Py_tp_descr_get, OSD_descr_get}, + {Py_tp_traverse, OSD_traverse}, + {Py_tp_dealloc, OSD_dealloc}, + {0, NULL} +}; + +static PyType_Spec OSD_type_spec = { + .name = OSD__name__, + .basicsize = 0, + .flags = BASETYPE_FLAGS, + .slots = OSD_type_slots +}; + +#endif + +/* + * ClassProvidesBase class + */ +typedef struct +{ + SB spec; + /* These members are handled generically, as for SB members. */ + PyObject* _cls; + PyObject* _implements; +} CPB; + static int CPB_traverse(CPB* self, visitproc visit, void* arg) { Py_VISIT(self->_cls); Py_VISIT(self->_implements); - return Spec_traverse((Spec*)self, visit, arg); + return SB_traverse((SB*)self, visit, arg); } static int @@ -612,68 +569,153 @@ CPB_clear(CPB* self) { Py_CLEAR(self->_cls); Py_CLEAR(self->_implements); - Spec_clear((Spec*)self); + SB_clear((SB*)self); return 0; } static void CPB_dealloc(CPB* self) { - PyObject_GC_UnTrack((PyObject *)self); + PyObject_GC_UnTrack((PyObject*)self); CPB_clear(self); - Spec_dealloc((Spec*)self); + SB_dealloc((SB*)self); /* handles decrefing tp */ +} + +static PyObject* +CPB_descr_get(CPB* self, PyObject* inst, PyObject* cls) +{ + PyObject* implements; + + if (self->_cls == NULL) + return NULL; + + if (cls == self->_cls) { + if (inst == NULL) { + Py_INCREF(self); + return OBJECT(self); + } + + implements = self->_implements; + Py_XINCREF(implements); + return implements; + } + + PyErr_SetString(PyExc_AttributeError, "__provides__"); + return NULL; } static PyMemberDef CPB_members[] = { - {"_cls", T_OBJECT_EX, offsetof(CPB, _cls), 0, "Defining class."}, - {"_implements", T_OBJECT_EX, offsetof(CPB, _implements), 0, "Result of implementedBy."}, - {NULL} + { "_cls", T_OBJECT_EX, offsetof(CPB, _cls), 0, "Defining class." }, + { "_implements", + T_OBJECT_EX, + offsetof(CPB, _implements), + 0, + "Result of implementedBy." }, + { NULL } }; -static PyTypeObject CPBType = { - PyVarObject_HEAD_INIT(NULL, 0) - /* tp_name */ "_interface_coptimizations." - "ClassProvidesBase", - /* tp_basicsize */ sizeof(CPB), - /* tp_itemsize */ 0, - /* tp_dealloc */ (destructor)CPB_dealloc, - /* tp_print */ (printfunc)0, - /* tp_getattr */ (getattrfunc)0, - /* tp_setattr */ (setattrfunc)0, - /* tp_compare */ 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, - "C Base class for ClassProvides", - /* tp_traverse */ (traverseproc)CPB_traverse, - /* tp_clear */ (inquiry)CPB_clear, - /* tp_richcompare */ (richcmpfunc)0, - /* tp_weaklistoffset */ (long)0, - /* tp_iter */ (getiterfunc)0, - /* tp_iternext */ (iternextfunc)0, - /* tp_methods */ 0, - /* tp_members */ CPB_members, - /* tp_getset */ 0, - /* tp_base */ &SpecificationBaseType, - /* tp_dict */ 0, /* internal use */ - /* tp_descr_get */ (descrgetfunc)CPB_descr_get, - /* tp_descr_set */ 0, - /* tp_dictoffset */ 0, - /* tp_init */ 0, - /* tp_alloc */ 0, - /* tp_new */ 0, +static char CPB__name__[] = "_zope_interface_coptimizations.ClassProvidesBase"; +static char CPB__doc__[] = "C Base class for ClassProvides"; + +#if USE_STATIC_TYPES + +/* + * Static type: ClassProvidesBase + */ + +static PyTypeObject CPB_type_def = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = CPB__name__, + .tp_doc = CPB__doc__, + .tp_base = &SB_type_def, + .tp_basicsize = sizeof(CPB), + .tp_flags = BASETYPE_FLAGS, + .tp_descr_get = (descrgetfunc)CPB_descr_get, + .tp_traverse = (traverseproc)CPB_traverse, + .tp_clear = (inquiry)CPB_clear, + .tp_dealloc = (destructor)CPB_dealloc, + .tp_members = CPB_members, }; -/* ==================================================================== */ -/* ========== Begin: __call__ and __adapt__ =========================== */ +#else + +/* + * Heap type: ClassProvidesBase + */ +static PyType_Slot CPB_type_slots[] = { + {Py_tp_doc, CPB__doc__}, + {Py_tp_descr_get, CPB_descr_get}, + {Py_tp_traverse, CPB_traverse}, + {Py_tp_clear, CPB_clear}, + {Py_tp_dealloc, CPB_dealloc}, + {Py_tp_members, CPB_members}, + /* tp_base cannot be set as a slot -- pass to PyType_FromModuleAndSpec */ + {0, NULL} +}; + +static PyType_Spec CPB_type_spec = { + .name = CPB__name__, + .basicsize = sizeof(CPB), + .flags = BASETYPE_FLAGS, + .slots = CPB_type_slots +}; + +#endif + +/* + * InterfaceBase class + */ + +typedef struct +{ + SB spec; + PyObject* __name__; + PyObject* __module__; + Py_hash_t _v_cached_hash; +} IB; + +static int +IB_traverse(IB* self, visitproc visit, void* arg) +{ + Py_VISIT(self->__name__); + Py_VISIT(self->__module__); + return SB_traverse((SB*)self, visit, arg); +} + +static int +IB_clear(IB* self) +{ + Py_CLEAR(self->__name__); + Py_CLEAR(self->__module__); + return SB_clear((SB*)self); +} + +static void +IB_dealloc(IB* self) +{ + PyObject_GC_UnTrack((PyObject*)self); + IB_clear(self); + SB_dealloc((SB*)self); /* handles decrefing tp */ +} + +static int +IB__init__(IB* self, PyObject* args, PyObject* kwargs) +{ + static char* kwlist[] = { "__name__", "__module__", NULL }; + PyObject* module = NULL; + PyObject* name = NULL; + + if (!PyArg_ParseTupleAndKeywords( + args, kwargs, "|OO:InterfaceBase.__init__", kwlist, &name, &module)) { + return -1; + } + IB_clear(self); + self->__module__ = module ? module : Py_None; + Py_INCREF(self->__module__); + self->__name__ = name ? name : Py_None; + Py_INCREF(self->__name__); + return 0; +} /* def __adapt__(self, obj): @@ -689,88 +731,84 @@ static PyTypeObject CPBType = { */ -static PyObject * -__adapt__(PyObject *self, PyObject *obj) +const char IB__adapt____doc__[] = "Adapt an object to the receiver"; + +static PyObject* +IB__adapt__(PyObject* self, PyObject* obj) { - PyObject *decl, *args, *adapter; - int implements, i, l; + PyObject *decl; + PyObject *args; + PyObject *adapter; + PyObject *module; + PyObject *adapter_hooks; + PyTypeObject *specification_base_class; + int implements; + int i; + int l; + + module = _get_module(Py_TYPE(self)); + + decl = providedBy(module, obj); + if (decl == NULL) + return NULL; - decl = providedBy(NULL, obj); - if (decl == NULL) - return NULL; + specification_base_class = _get_specification_base_class(Py_TYPE(self)); - if (PyObject_TypeCheck(decl, &SpecificationBaseType)) - { - PyObject *implied; + if (PyObject_TypeCheck(decl, specification_base_class)) { + PyObject* implied; - implied = ((Spec*)decl)->_implied; - if (implied == NULL) - { - Py_DECREF(decl); - return NULL; + implied = ((SB*)decl)->_implied; + if (implied == NULL) { + Py_DECREF(decl); + return NULL; } - implements = PyDict_GetItem(implied, self) != NULL; - Py_DECREF(decl); - } - else - { - /* decl is probably a security proxy. We have to go the long way - around. - */ - PyObject *r; - r = PyObject_CallFunctionObjArgs(decl, self, NULL); - Py_DECREF(decl); - if (r == NULL) - return NULL; - implements = PyObject_IsTrue(r); - Py_DECREF(r); + implements = PyDict_GetItem(implied, self) != NULL; + Py_DECREF(decl); + } else { + /* decl is probably a security proxy. We have to go the long way + around. + */ + PyObject* r; + r = PyObject_CallFunctionObjArgs(decl, self, NULL); + Py_DECREF(decl); + if (r == NULL) + return NULL; + implements = PyObject_IsTrue(r); + Py_DECREF(r); } - if (implements) - { - Py_INCREF(obj); - return obj; + if (implements) { + Py_INCREF(obj); + return obj; } - l = PyList_GET_SIZE(adapter_hooks); - args = PyTuple_New(2); - if (args == NULL) - return NULL; - Py_INCREF(self); - PyTuple_SET_ITEM(args, 0, self); - Py_INCREF(obj); - PyTuple_SET_ITEM(args, 1, obj); - for (i = 0; i < l; i++) - { - adapter = PyObject_CallObject(PyList_GET_ITEM(adapter_hooks, i), args); - if (adapter == NULL || adapter != Py_None) - { - Py_DECREF(args); - return adapter; + args = PyTuple_New(2); + if (args == NULL) { return NULL; } + + Py_INCREF(self); + PyTuple_SET_ITEM(args, 0, self); + + Py_INCREF(obj); + PyTuple_SET_ITEM(args, 1, obj); + + adapter_hooks = _get_adapter_hooks(Py_TYPE(self)); + l = PyList_GET_SIZE(adapter_hooks); + for (i = 0; i < l; i++) { + adapter = PyObject_CallObject(PyList_GET_ITEM(adapter_hooks, i), args); + if (adapter == NULL || adapter != Py_None) { + Py_DECREF(args); + return adapter; } - Py_DECREF(adapter); + Py_DECREF(adapter); } - Py_DECREF(args); + Py_DECREF(args); - Py_INCREF(Py_None); - return Py_None; + Py_INCREF(Py_None); + return Py_None; } -typedef struct { - Spec spec; - PyObject* __name__; - PyObject* __module__; - Py_hash_t _v_cached_hash; -} IB; - -static struct PyMethodDef ib_methods[] = { - {"__adapt__", (PyCFunction)__adapt__, METH_O, - "Adapt an object to the receiver"}, - {NULL, NULL} /* sentinel */ -}; - /* def __call__(self, obj, alternate=_marker): try: @@ -792,120 +830,74 @@ static struct PyMethodDef ib_methods[] = { raise TypeError("Could not adapt", obj, self) */ -static PyObject * -IB_call(PyObject *self, PyObject *args, PyObject *kwargs) +static PyObject* +IB__call__(PyObject* self, PyObject* args, PyObject* kwargs) { - PyObject *conform, *obj, *alternate, *adapter; - static char *kwlist[] = {"obj", "alternate", NULL}; - conform = obj = alternate = adapter = NULL; + PyObject *conform, *obj, *alternate, *adapter; + static char* kwlist[] = { "obj", "alternate", NULL }; + conform = obj = alternate = adapter = NULL; + if (!PyArg_ParseTupleAndKeywords( + args, kwargs, "O|O", kwlist, &obj, &alternate)) + return NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O", kwlist, - &obj, &alternate)) - return NULL; + conform = PyObject_GetAttr(obj, str__conform__); + if (conform == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { + /* Propagate non-AttributeErrors */ + return NULL; + } + PyErr_Clear(); - conform = PyObject_GetAttr(obj, str__conform__); - if (conform == NULL) - { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - { - /* Propagate non-AttributeErrors */ - return NULL; - } - PyErr_Clear(); - - Py_INCREF(Py_None); - conform = Py_None; - } - - if (conform != Py_None) - { - adapter = PyObject_CallMethodObjArgs(self, str_call_conform, - conform, NULL); - Py_DECREF(conform); - if (adapter == NULL || adapter != Py_None) - return adapter; - Py_DECREF(adapter); - } - else - { - Py_DECREF(conform); - } - - /* 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; - } - Py_DECREF(adapter); - - if (alternate != NULL) - { - Py_INCREF(alternate); - return alternate; - } - - adapter = Py_BuildValue("sOO", "Could not adapt", obj, self); - if (adapter != NULL) - { - PyErr_SetObject(PyExc_TypeError, adapter); - Py_DECREF(adapter); - } - return NULL; -} + Py_INCREF(Py_None); + conform = Py_None; + } + if (conform != Py_None) { + adapter = + PyObject_CallMethodObjArgs(self, str_call_conform, conform, NULL); + Py_DECREF(conform); + if (adapter == NULL || adapter != Py_None) + return adapter; + Py_DECREF(adapter); + } else { + Py_DECREF(conform); + } -static int -IB_traverse(IB* self, visitproc visit, void* arg) -{ - Py_VISIT(self->__name__); - Py_VISIT(self->__module__); - return Spec_traverse((Spec*)self, visit, arg); -} + /* 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_GetItemString(self->ob_type->tp_dict, "_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 = IB__adapt__(self, obj); + } -static int -IB_clear(IB* self) -{ - Py_CLEAR(self->__name__); - Py_CLEAR(self->__module__); - return Spec_clear((Spec*)self); -} + if (adapter == NULL || adapter != Py_None) { + return adapter; + } + Py_DECREF(adapter); -static void -IB_dealloc(IB* self) -{ - PyObject_GC_UnTrack((PyObject *)self); - IB_clear(self); - Spec_dealloc((Spec*)self); -} + if (alternate != NULL) { + Py_INCREF(alternate); + return alternate; + } -static PyMemberDef IB_members[] = { - {"__name__", T_OBJECT_EX, offsetof(IB, __name__), 0, ""}, - // The redundancy between __module__ and __ibmodule__ is because - // __module__ is often shadowed by subclasses. - {"__module__", T_OBJECT_EX, offsetof(IB, __module__), READONLY, ""}, - {"__ibmodule__", T_OBJECT_EX, offsetof(IB, __module__), 0, ""}, - {NULL} -}; + adapter = Py_BuildValue("sOO", "Could not adapt", obj, self); + if (adapter != NULL) { + PyErr_SetObject(PyExc_TypeError, adapter); + Py_DECREF(adapter); + } + return NULL; +} static Py_hash_t -IB_hash(IB* self) +IB__hash__(IB* self) { PyObject* tuple; if (!self->__module__) { @@ -930,14 +922,13 @@ IB_hash(IB* self) return self->_v_cached_hash; } -static PyTypeObject InterfaceBaseType; - static PyObject* IB_richcompare(IB* self, PyObject* other, int op) { PyObject* othername; PyObject* othermod; PyObject* oresult; + PyTypeObject* interface_base_class; IB* otherib; int result; @@ -945,42 +936,48 @@ IB_richcompare(IB* self, PyObject* other, int op) oresult = othername = othermod = NULL; if (OBJECT(self) == other) { - switch(op) { - case Py_EQ: - case Py_LE: - case Py_GE: - Py_RETURN_TRUE; - break; - case Py_NE: - Py_RETURN_FALSE; + switch (op) { + case Py_EQ: + case Py_LE: + case Py_GE: + Py_RETURN_TRUE; + break; + case Py_NE: + Py_RETURN_FALSE; } } if (other == Py_None) { - switch(op) { - case Py_LT: - case Py_LE: - case Py_NE: - Py_RETURN_TRUE; - default: - Py_RETURN_FALSE; + switch (op) { + case Py_LT: + case Py_LE: + case Py_NE: + Py_RETURN_TRUE; + default: + Py_RETURN_FALSE; } } - if (PyObject_TypeCheck(other, &InterfaceBaseType)) { + interface_base_class = _get_interface_base_class(Py_TYPE(self)); + if (interface_base_class == NULL) { + oresult = Py_NotImplemented; + goto cleanup; + } + + if (PyObject_TypeCheck(other, interface_base_class)) { // This branch borrows references. No need to clean // up if otherib is not null. otherib = (IB*)other; othername = otherib->__name__; othermod = otherib->__module__; - } - else { - othername = PyObject_GetAttrString(other, "__name__"); + } else { + othername = PyObject_GetAttr(other, str__name__); if (othername) { - othermod = PyObject_GetAttrString(other, "__module__"); + othermod = PyObject_GetAttr(other, str__module__); } if (!othername || !othermod) { - if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_AttributeError)) { + if (PyErr_Occurred() && + PyErr_ExceptionMatches(PyExc_AttributeError)) { PyErr_Clear(); oresult = Py_NotImplemented; } @@ -998,8 +995,7 @@ IB_richcompare(IB* self, PyObject* other, int op) result = PyObject_RichCompareBool(self->__name__, othername, Py_EQ); if (result == 0) { result = PyObject_RichCompareBool(self->__name__, othername, op); - } - else if (result == 1) { + } else if (result == 1) { result = PyObject_RichCompareBool(self->__module__, othermod, op); } // If either comparison failed, we have an error set. @@ -1010,7 +1006,6 @@ IB_richcompare(IB* self, PyObject* other, int op) oresult = result ? Py_True : Py_False; - cleanup: Py_XINCREF(oresult); @@ -1019,133 +1014,126 @@ cleanup: Py_XDECREF(othermod); } return oresult; - -} - -static int -IB_init(IB* self, PyObject* args, PyObject* kwargs) -{ - static char *kwlist[] = {"__name__", "__module__", NULL}; - PyObject* module = NULL; - PyObject* name = NULL; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OO:InterfaceBase.__init__", kwlist, - &name, &module)) { - return -1; - } - IB_clear(self); - self->__module__ = module ? module : Py_None; - Py_INCREF(self->__module__); - self->__name__ = name ? name : Py_None; - Py_INCREF(self->__name__); - return 0; } +static PyMemberDef IB_members[] = { + { "__name__", T_OBJECT_EX, offsetof(IB, __name__), 0, "" }, + // The redundancy between __module__ and __ibmodule__ is because + // __module__ is often shadowed by subclasses. + { "__module__", T_OBJECT_EX, offsetof(IB, __module__), READONLY, "" }, + { "__ibmodule__", T_OBJECT_EX, offsetof(IB, __module__), 0, "" }, + { NULL } +}; -static PyTypeObject InterfaceBaseType = { - PyVarObject_HEAD_INIT(NULL, 0) - /* tp_name */ "_zope_interface_coptimizations." - "InterfaceBase", - /* tp_basicsize */ sizeof(IB), - /* tp_itemsize */ 0, - /* tp_dealloc */ (destructor)IB_dealloc, - /* tp_print */ (printfunc)0, - /* tp_getattr */ (getattrfunc)0, - /* tp_setattr */ (setattrfunc)0, - /* tp_compare */ 0, - /* tp_repr */ (reprfunc)0, - /* tp_as_number */ 0, - /* tp_as_sequence */ 0, - /* tp_as_mapping */ 0, - /* tp_hash */ (hashfunc)IB_hash, - /* tp_call */ (ternaryfunc)IB_call, - /* 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 */ "Interface base type providing __call__ and __adapt__", - /* tp_traverse */ (traverseproc)IB_traverse, - /* tp_clear */ (inquiry)IB_clear, - /* tp_richcompare */ (richcmpfunc)IB_richcompare, - /* tp_weaklistoffset */ (long)0, - /* tp_iter */ (getiterfunc)0, - /* tp_iternext */ (iternextfunc)0, - /* tp_methods */ ib_methods, - /* tp_members */ IB_members, - /* tp_getset */ 0, - /* tp_base */ &SpecificationBaseType, - /* tp_dict */ 0, - /* tp_descr_get */ 0, - /* tp_descr_set */ 0, - /* tp_dictoffset */ 0, - /* tp_init */ (initproc)IB_init, +static struct PyMethodDef IB_methods[] = { + { "__adapt__", (PyCFunction)IB__adapt__, METH_O, IB__adapt____doc__}, + { NULL, NULL } /* sentinel */ }; -/* =================== End: __call__ and __adapt__ ==================== */ -/* ==================================================================== */ +static char IB__name__[] ="_zope_interface_coptimizations.InterfaceBase"; +static char IB__doc__[] = ( + "Interface base type providing __call__ and __adapt__" +); -/* ==================================================================== */ -/* ========================== Begin: Lookup Bases ===================== */ +#if USE_STATIC_TYPES -typedef struct { - PyObject_HEAD - PyObject *_cache; - PyObject *_mcache; - PyObject *_scache; -} lookup; +/* + * Static type: InterfaceBase + */ + +static PyTypeObject IB_type_def = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = IB__name__, + .tp_doc = IB__doc__, + .tp_base = &SB_type_def, + .tp_basicsize = sizeof(IB), + .tp_flags = BASETYPE_FLAGS, + .tp_init = (initproc)IB__init__, + .tp_hash = (hashfunc)IB__hash__, + .tp_richcompare = (richcmpfunc)IB_richcompare, + .tp_call = (ternaryfunc)IB__call__, + .tp_traverse = (traverseproc)IB_traverse, + .tp_clear = (inquiry)IB_clear, + .tp_dealloc = (destructor)IB_dealloc, + .tp_methods = IB_methods, + .tp_members = IB_members, +}; -typedef struct { - PyObject_HEAD - PyObject *_cache; - PyObject *_mcache; - PyObject *_scache; - PyObject *_verify_ro; - PyObject *_verify_generations; -} verify; +#else -static int -lookup_traverse(lookup *self, visitproc visit, void *arg) -{ - int vret; +/* + * Heap type: InterfaceBase + */ +static PyType_Slot IB_type_slots[] = { + {Py_tp_doc, IB__doc__}, + {Py_tp_init, IB__init__}, + {Py_tp_hash, IB__hash__}, + {Py_tp_richcompare, IB_richcompare}, + {Py_tp_call, IB__call__}, + {Py_tp_traverse, IB_traverse}, + {Py_tp_clear, IB_clear}, + {Py_tp_dealloc, IB_dealloc}, + {Py_tp_methods, IB_methods}, + {Py_tp_members, IB_members}, + /* tp_base cannot be set as a slot -- pass to PyType_FromModuleAndSpec */ + {0, NULL} +}; - if (self->_cache) { - vret = visit(self->_cache, arg); - if (vret != 0) - return vret; - } +static PyType_Spec IB_type_spec = { + .name = IB__name__, + .basicsize = sizeof(IB), + .flags = BASETYPE_FLAGS, + .slots = IB_type_slots +}; - if (self->_mcache) { - vret = visit(self->_mcache, arg); - if (vret != 0) - return vret; - } +#endif - if (self->_scache) { - vret = visit(self->_scache, arg); - if (vret != 0) - return vret; - } +/* + * LookupBase class + */ +typedef struct +{ + PyObject_HEAD + PyObject* _cache; + PyObject* _mcache; + PyObject* _scache; +} LB; - return 0; +static int +LB_traverse(LB* self, visitproc visit, void* arg) +{ +/* Visit our 'tp_type' only on Python >= 3.9, per + * https://docs.python.org/3/howto/isolating-extensions.html + * #tp-traverse-in-python-3-8-and-lower + */ +#if USE_HEAP_TYPES && PY_VERSION_HEX > 0x03090000 + Py_VISIT(Py_TYPE(self)); +#endif + Py_VISIT(self->_cache); + Py_VISIT(self->_mcache); + Py_VISIT(self->_scache); + return 0; } static int -lookup_clear(lookup *self) +LB_clear(LB* self) { - Py_CLEAR(self->_cache); - Py_CLEAR(self->_mcache); - Py_CLEAR(self->_scache); - return 0; + Py_CLEAR(self->_cache); + Py_CLEAR(self->_mcache); + Py_CLEAR(self->_scache); + return 0; } static void -lookup_dealloc(lookup *self) +LB_dealloc(LB* self) { - PyObject_GC_UnTrack((PyObject *)self); - lookup_clear(self); - Py_TYPE(self)->tp_free((PyObject*)self); + PyObject_GC_UnTrack((PyObject*)self); + PyTypeObject* tp = Py_TYPE(self); + LB_clear(self); + tp->tp_free((PyObject*)self); +#if USE_HEAP_TYPES + Py_DECREF(tp); +#endif } /* @@ -1154,18 +1142,14 @@ lookup_dealloc(lookup *self) self._mcache.clear() self._scache.clear() */ -static PyObject * -lookup_changed(lookup *self, PyObject *ignored) +static PyObject* +LB_changed(LB* self, PyObject* ignored) { - lookup_clear(self); - Py_INCREF(Py_None); - return Py_None; + LB_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) @@ -1180,43 +1164,43 @@ lookup_changed(lookup *self, PyObject *ignored) cache = c return cache */ -static PyObject * -_subcache(PyObject *cache, PyObject *key) +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; + 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; + return subcache; } -static PyObject * -_getcache(lookup *self, PyObject *provided, PyObject *name) + +static PyObject* +_getcache(LB* self, PyObject* provided, PyObject* name) { - PyObject *cache; + PyObject* cache; - ASSURE_DICT(self->_cache); - cache = _subcache(self->_cache, provided); - if (cache == NULL) - return NULL; + ASSURE_DICT(self->_cache); - if (name != NULL && PyObject_IsTrue(name)) - cache = _subcache(cache, name); + cache = _subcache(self->_cache, provided); + if (cache == NULL) + return NULL; - return cache; -} + if (name != NULL && PyObject_IsTrue(name)) + cache = _subcache(cache, name); + return cache; +} /* def lookup(self, required, provided, name=u'', default=None): @@ -1239,86 +1223,85 @@ _getcache(lookup *self, PyObject *provided, PyObject *name) return result */ -static PyObject * -_lookup(lookup *self, - PyObject *required, PyObject *provided, PyObject *name, - PyObject *default_) -{ - PyObject *result, *key, *cache; - result = key = cache = NULL; - if ( name && !PyUnicode_Check(name) ) - { - PyErr_SetString(PyExc_ValueError, - "name is not a string or unicode"); - return NULL; - } +static PyObject* +_lookup(LB* self, + PyObject* required, + PyObject* provided, + PyObject* name, + PyObject* default_) +{ + PyObject *result, *key, *cache; + result = key = cache = NULL; + if (name && !PyUnicode_Check(name)) { + PyErr_SetString(PyExc_ValueError, "name is not a string"); + return NULL; + } - /* If `required` is a lazy sequence, it could have arbitrary side-effects, - such as clearing our caches. So we must not retrieve the cache until - after resolving it. */ - required = PySequence_Tuple(required); - if (required == NULL) - return NULL; + /* If `required` is a lazy sequence, it could have arbitrary side-effects, + such as clearing our caches. So we must not retrieve the cache until + after resolving it. */ + required = PySequence_Tuple(required); + if (required == NULL) + return NULL; + cache = _getcache(self, provided, name); + if (cache == NULL) + return NULL; - cache = _getcache(self, provided, name); - if (cache == 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; - 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; + 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; + status = PyDict_SetItem(cache, key, result); + Py_DECREF(required); + if (status < 0) { + Py_DECREF(result); + return NULL; } - } - else - { - Py_INCREF(result); - Py_DECREF(required); + } else { + Py_INCREF(result); + Py_DECREF(required); } - if (result == Py_None && default_ != NULL) - { - Py_DECREF(Py_None); - Py_INCREF(default_); - return default_; + if (result == Py_None && default_ != NULL) { + Py_DECREF(Py_None); + Py_INCREF(default_); + return default_; } - return result; + 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:LookupBase.lookup", kwlist, - &required, &provided, &name, &default_)) - return NULL; +static PyObject* +LB_lookup(LB* 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:LookupBase.lookup", + kwlist, + &required, + &provided, + &name, + &default_)) + return NULL; - return _lookup(self, required, provided, name, default_); + return _lookup(self, required, provided, name, default_); } - /* def lookup1(self, required, provided, name=u'', default=None): cache = self._getcache(provided, name) @@ -1331,59 +1314,61 @@ lookup_lookup(lookup *self, PyObject *args, PyObject *kwds) return result */ -static PyObject * -_lookup1(lookup *self, - PyObject *required, PyObject *provided, PyObject *name, - PyObject *default_) +static PyObject* +_lookup1(LB* self, + PyObject* required, + PyObject* provided, + PyObject* name, + PyObject* default_) { - PyObject *result, *cache; - - if ( name && !PyUnicode_Check(name) ) - { - PyErr_SetString(PyExc_ValueError, - "name is not a string or unicode"); - return NULL; - } - - cache = _getcache(self, provided, name); - if (cache == NULL) - return NULL; - - result = PyDict_GetItem(cache, required); - if (result == NULL) - { - PyObject *tup; + PyObject *result, *cache; - tup = PyTuple_New(1); - if (tup == NULL) + if (name && !PyUnicode_Check(name)) { + PyErr_SetString(PyExc_ValueError, "name is not a string"); return NULL; - Py_INCREF(required); - PyTuple_SET_ITEM(tup, 0, required); - result = _lookup(self, tup, provided, name, default_); - Py_DECREF(tup); } - else - { - if (result == Py_None && default_ != NULL) - { - result = default_; + + 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 { + if (result == Py_None && default_ != NULL) { + result = default_; } - Py_INCREF(result); + Py_INCREF(result); } - return result; + return result; } -static PyObject * -lookup_lookup1(lookup *self, PyObject *args, PyObject *kwds) +static PyObject* +LB_lookup1(LB* 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:LookupBase.lookup1", kwlist, - &required, &provided, &name, &default_)) - return NULL; + static char* kwlist[] = { "required", "provided", "name", "default", NULL }; + PyObject *required, *provided, *name = NULL, *default_ = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, + kwds, + "OO|OO:LookupBase.lookup1", + kwlist, + &required, + &provided, + &name, + &default_)) + return NULL; - return _lookup1(self, required, provided, name, default_); + return _lookup1(self, required, provided, name, default_); } /* @@ -1403,82 +1388,97 @@ lookup_lookup1(lookup *self, PyObject *args, PyObject *kwds) return default */ -static PyObject * -_adapter_hook(lookup *self, - PyObject *provided, PyObject *object, PyObject *name, - PyObject *default_) +static PyObject* +_adapter_hook(LB* self, + PyObject* provided, + PyObject* object, + PyObject* name, + PyObject* default_) { - PyObject *required, *factory, *result; + PyObject *required; + PyObject *factory; + PyObject *result; + PyObject *module; - if ( name && !PyUnicode_Check(name) ) - { - PyErr_SetString(PyExc_ValueError, - "name is not a string or unicode"); - return NULL; - } + module = _get_module(Py_TYPE(self)); - required = providedBy(NULL, object); - if (required == NULL) - return NULL; + if (name && !PyUnicode_Check(name)) { + PyErr_SetString(PyExc_ValueError, "name is not a string"); + return NULL; + } - factory = _lookup1(self, required, provided, name, Py_None); - Py_DECREF(required); - if (factory == NULL) - return NULL; + required = providedBy(module, object); + if (required == NULL) + return NULL; - if (factory != Py_None) - { - if (PyObject_TypeCheck(object, &PySuper_Type)) { - PyObject* self = PyObject_GetAttr(object, str__self__); - if (self == NULL) - { - Py_DECREF(factory); - return NULL; - } - // Borrow the reference to self - Py_DECREF(self); - object = self; - } - result = PyObject_CallFunctionObjArgs(factory, object, NULL); - Py_DECREF(factory); - if (result == NULL || result != Py_None) - return result; - } - else - result = factory; /* None */ + factory = _lookup1(self, required, provided, name, Py_None); + Py_DECREF(required); + if (factory == NULL) + return NULL; - if (default_ == NULL || default_ == result) /* No default specified, */ - return result; /* Return None. result is owned None */ + if (factory != Py_None) { + if (PyObject_TypeCheck(object, &PySuper_Type)) { + PyObject* self = PyObject_GetAttr(object, str__self__); + if (self == NULL) { + Py_DECREF(factory); + return NULL; + } + // Borrow the reference to self + Py_DECREF(self); + object = self; + } + result = PyObject_CallFunctionObjArgs(factory, object, NULL); + Py_DECREF(factory); + if (result == NULL || result != Py_None) + return result; + } else + result = factory; /* None */ - Py_DECREF(result); - Py_INCREF(default_); + if (default_ == NULL || default_ == result) /* No default specified, */ + return result; /* Return None. result is owned None */ - return default_; + 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:LookupBase.adapter_hook", kwlist, - &provided, &object, &name, &default_)) - return NULL; +static PyObject* +LB_adapter_hook(LB* 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:LookupBase.adapter_hook", + kwlist, + &provided, + &object, + &name, + &default_)) + return NULL; - return _adapter_hook(self, provided, object, name, default_); + return _adapter_hook(self, provided, object, name, default_); } -static PyObject * -lookup_queryAdapter(lookup *self, PyObject *args, PyObject *kwds) +static PyObject* +LB_queryAdapter(LB* 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:LookupBase.queryAdapter", kwlist, - &object, &provided, &name, &default_)) - return NULL; + static char* kwlist[] = { "object", "provided", "name", "default", NULL }; + PyObject *object, *provided, *name = NULL, *default_ = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, + kwds, + "OO|OO:LookupBase.queryAdapter", + kwlist, + &object, + &provided, + &name, + &default_)) + return NULL; - return _adapter_hook(self, provided, object, name, default_); + return _adapter_hook(self, provided, object, name, default_); } /* @@ -1496,60 +1496,57 @@ lookup_queryAdapter(lookup *self, PyObject *args, PyObject *kwds) return result */ -static PyObject * -_lookupAll(lookup *self, PyObject *required, PyObject *provided) +static PyObject* +_lookupAll(LB* self, PyObject* required, PyObject* provided) { - PyObject *cache, *result; + PyObject *cache, *result; - /* resolve before getting cache. See note in _lookup. */ - required = PySequence_Tuple(required); - if (required == NULL) - return NULL; + /* resolve before getting cache. See note in _lookup. */ + required = PySequence_Tuple(required); + if (required == NULL) + return NULL; - ASSURE_DICT(self->_mcache); - cache = _subcache(self->_mcache, provided); - if (cache == NULL) - return NULL; + ASSURE_DICT(self->_mcache); + + cache = _subcache(self->_mcache, provided); + if (cache == 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; + 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; + status = PyDict_SetItem(cache, required, result); + Py_DECREF(required); + if (status < 0) { + Py_DECREF(result); + return NULL; } - } - else - { - Py_INCREF(result); - Py_DECREF(required); + } else { + Py_INCREF(result); + Py_DECREF(required); } - return result; + return result; } -static PyObject * -lookup_lookupAll(lookup *self, PyObject *args, PyObject *kwds) + +static PyObject* +LB_lookupAll(LB* self, PyObject* args, PyObject* kwds) { - static char *kwlist[] = {"required", "provided", NULL}; - PyObject *required, *provided; + static char* kwlist[] = { "required", "provided", NULL }; + PyObject *required, *provided; - if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO:LookupBase.lookupAll", kwlist, - &required, &provided)) - return NULL; + if (!PyArg_ParseTupleAndKeywords( + args, kwds, "OO:LookupBase.lookupAll", kwlist, &required, &provided)) + return NULL; - return _lookupAll(self, required, provided); + return _lookupAll(self, required, provided); } /* @@ -1567,147 +1564,163 @@ lookup_lookupAll(lookup *self, PyObject *args, PyObject *kwds) return result */ -static PyObject * -_subscriptions(lookup *self, PyObject *required, PyObject *provided) +static PyObject* +_subscriptions(LB* self, PyObject* required, PyObject* provided) { - PyObject *cache, *result; + PyObject *cache, *result; - /* resolve before getting cache. See note in _lookup. */ - required = PySequence_Tuple(required); - if (required == NULL) - return NULL; + /* resolve before getting cache. See note in _lookup. */ + required = PySequence_Tuple(required); + if (required == NULL) + return NULL; - ASSURE_DICT(self->_scache); - cache = _subcache(self->_scache, provided); - if (cache == NULL) - return NULL; + ASSURE_DICT(self->_scache); + + cache = _subcache(self->_scache, provided); + if (cache == 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; + 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; + status = PyDict_SetItem(cache, required, result); + Py_DECREF(required); + if (status < 0) { + Py_DECREF(result); + return NULL; } - } - else - { - Py_INCREF(result); - Py_DECREF(required); + } else { + Py_INCREF(result); + Py_DECREF(required); } - return result; + return result; } -static PyObject * -lookup_subscriptions(lookup *self, PyObject *args, PyObject *kwds) + +static PyObject* +LB_subscriptions(LB* self, PyObject* args, PyObject* kwds) { - static char *kwlist[] = {"required", "provided", NULL}; - PyObject *required, *provided; + static char* kwlist[] = { "required", "provided", NULL }; + PyObject *required, *provided; - if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, - &required, &provided)) - return NULL; + if (!PyArg_ParseTupleAndKeywords( + args, kwds, "OO", kwlist, &required, &provided)) + return NULL; - return _subscriptions(self, required, provided); + return _subscriptions(self, required, provided); } -static struct PyMethodDef lookup_methods[] = { - {"changed", (PyCFunction)lookup_changed, METH_O, ""}, - {"lookup", (PyCFunction)lookup_lookup, METH_KEYWORDS | METH_VARARGS, ""}, - {"lookup1", (PyCFunction)lookup_lookup1, METH_KEYWORDS | METH_VARARGS, ""}, - {"queryAdapter", (PyCFunction)lookup_queryAdapter, METH_KEYWORDS | METH_VARARGS, ""}, - {"adapter_hook", (PyCFunction)lookup_adapter_hook, METH_KEYWORDS | METH_VARARGS, ""}, - {"lookupAll", (PyCFunction)lookup_lookupAll, METH_KEYWORDS | METH_VARARGS, ""}, - {"subscriptions", (PyCFunction)lookup_subscriptions, METH_KEYWORDS | METH_VARARGS, ""}, - {NULL, NULL} /* sentinel */ +static struct PyMethodDef LB_methods[] = { + { "changed", (PyCFunction)LB_changed, METH_O, "" }, + { "lookup", (PyCFunction)LB_lookup, METH_KEYWORDS | METH_VARARGS, "" }, + { "lookup1", + (PyCFunction)LB_lookup1, + METH_KEYWORDS | METH_VARARGS, + "" }, + { "queryAdapter", + (PyCFunction)LB_queryAdapter, + METH_KEYWORDS | METH_VARARGS, + "" }, + { "adapter_hook", + (PyCFunction)LB_adapter_hook, + METH_KEYWORDS | METH_VARARGS, + "" }, + { "lookupAll", + (PyCFunction)LB_lookupAll, + METH_KEYWORDS | METH_VARARGS, + "" }, + { "subscriptions", + (PyCFunction)LB_subscriptions, + METH_KEYWORDS | METH_VARARGS, + "" }, + { NULL, NULL } /* sentinel */ }; -static PyTypeObject LookupBase = { - PyVarObject_HEAD_INIT(NULL, 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 */ 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 char LB__name__[] = "_zope_interface_coptimizations.LookupBase"; +static char LB__doc__[] = "Base class for adapter registries"; + + +#if USE_STATIC_TYPES + +/* + * Static type: LookupBase + */ + +static PyTypeObject LB_type_def = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = LB__name__, + .tp_doc = LB__doc__, + .tp_basicsize = sizeof(LB), + .tp_flags = BASETYPE_FLAGS, + .tp_traverse = (traverseproc)LB_traverse, + .tp_clear = (inquiry)LB_clear, + .tp_dealloc = (destructor)&LB_dealloc, + .tp_methods = LB_methods, }; -static int -verifying_traverse(verify *self, visitproc visit, void *arg) -{ - int vret; +#else - vret = lookup_traverse((lookup *)self, visit, arg); - if (vret != 0) - return vret; +/* + * Heap type: LookupBase + */ +static PyType_Slot LB_type_slots[] = { + {Py_tp_doc, LB__doc__}, + {Py_tp_traverse, LB_traverse}, + {Py_tp_clear, LB_clear}, + {Py_tp_dealloc, LB_dealloc}, + {Py_tp_methods, LB_methods}, + {0, NULL} +}; - 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; - } +static PyType_Spec LB_type_spec = { + .name = LB__name__, + .basicsize = sizeof(LB), + .flags = BASETYPE_FLAGS, + .slots = LB_type_slots +}; - return 0; -} +#endif + +typedef struct +{ + LB lookup; + PyObject* _verify_ro; + PyObject* _verify_generations; +} VB; static int -verifying_clear(verify *self) +VB_traverse(VB* self, visitproc visit, void* arg) { - lookup_clear((lookup *)self); - Py_CLEAR(self->_verify_generations); - Py_CLEAR(self->_verify_ro); - return 0; + Py_VISIT(self->_verify_ro); + Py_VISIT(self->_verify_generations); + return LB_traverse((LB*)self, visit, arg); } +static int +VB_clear(VB* self) +{ + Py_CLEAR(self->_verify_generations); + Py_CLEAR(self->_verify_ro); + return LB_clear((LB*)self); +} static void -verifying_dealloc(verify *self) +VB_dealloc(VB* self) { - PyObject_GC_UnTrack((PyObject *)self); - verifying_clear(self); - Py_TYPE(self)->tp_free((PyObject*)self); + PyObject_GC_UnTrack((PyObject*)self); + PyTypeObject *tp = Py_TYPE(self); + VB_clear(self); + tp->tp_free((PyObject*)self); +#if USE_HEAP_TYPES + Py_DECREF(tp); +#endif } /* @@ -1716,65 +1729,63 @@ verifying_dealloc(verify *self) 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; +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); + PyTuple_SET_ITEM(generations, i, generation); } - return generations; + return generations; } -static PyObject * -verifying_changed(verify *self, PyObject *ignored) +static PyObject* +verify_changed(VB* self, PyObject* ignored) { - PyObject *t, *ro; + PyObject *t, *ro; - verifying_clear(self); + VB_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_GetAttr(OBJECT(self), str_registry); + if (t == NULL) + return NULL; - t = PyObject_CallFunctionObjArgs(OBJECT(&PyTuple_Type), ro, NULL); - Py_DECREF(ro); - if (t == NULL) - return NULL; + ro = PyObject_GetAttr(t, strro); + Py_DECREF(t); + if (ro == NULL) + return NULL; - ro = PyTuple_GetSlice(t, 1, PyTuple_GET_SIZE(t)); - 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_generations = _generations_tuple(ro); + if (self->_verify_generations == NULL) { + Py_DECREF(ro); + return NULL; } - self->_verify_ro = ro; + self->_verify_ro = ro; - Py_INCREF(Py_None); - return Py_None; + Py_INCREF(Py_None); + return Py_None; } /* @@ -1784,296 +1795,880 @@ verifying_changed(verify *self, PyObject *ignored) self.changed(None) */ static int -_verify(verify *self) +_verify(VB* self) { - PyObject *changed_result; + PyObject* changed_result; - if (self->_verify_ro != NULL && self->_verify_generations != NULL) - { - PyObject *generations; - int changed; + if (self->_verify_ro != NULL && self->_verify_generations != NULL) { + PyObject* generations; + int changed; - generations = _generations_tuple(self->_verify_ro); - if (generations == NULL) - return -1; + generations = _generations_tuple(self->_verify_ro); + if (generations == NULL) + return -1; - changed = PyObject_RichCompareBool(self->_verify_generations, - generations, Py_NE); - Py_DECREF(generations); - if (changed == -1) - return -1; + changed = PyObject_RichCompareBool( + self->_verify_generations, generations, Py_NE); + Py_DECREF(generations); + if (changed == -1) + return -1; - if (changed == 0) - return 0; + if (changed == 0) + return 0; } - changed_result = PyObject_CallMethodObjArgs(OBJECT(self), strchanged, - Py_None, NULL); - if (changed_result == NULL) - return -1; + changed_result = + PyObject_CallMethodObjArgs(OBJECT(self), strchanged, Py_None, NULL); + if (changed_result == NULL) + return -1; - Py_DECREF(changed_result); - return 0; + Py_DECREF(changed_result); + return 0; } -static PyObject * -verifying_lookup(verify *self, PyObject *args, PyObject *kwds) +static PyObject* +VB_lookup(VB* self, PyObject* args, PyObject* kwds) { - static char *kwlist[] = {"required", "provided", "name", "default", NULL}; - PyObject *required, *provided, *name=NULL, *default_=NULL; + 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 (!PyArg_ParseTupleAndKeywords( + args, kwds, "OO|OO", kwlist, &required, &provided, &name, &default_)) + return NULL; - if (_verify(self) < 0) - return NULL; + if (_verify(self) < 0) + return NULL; - return _lookup((lookup *)self, required, provided, name, default_); + return _lookup((LB*)self, required, provided, name, default_); } -static PyObject * -verifying_lookup1(verify *self, PyObject *args, PyObject *kwds) +static PyObject* +VB_lookup1(VB* self, PyObject* args, PyObject* kwds) { - static char *kwlist[] = {"required", "provided", "name", "default", NULL}; - PyObject *required, *provided, *name=NULL, *default_=NULL; + 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 (!PyArg_ParseTupleAndKeywords( + args, kwds, "OO|OO", kwlist, &required, &provided, &name, &default_)) + return NULL; - if (_verify(self) < 0) - return NULL; + if (_verify(self) < 0) + return NULL; - return _lookup1((lookup *)self, required, provided, name, default_); + return _lookup1((LB*)self, required, provided, name, default_); } -static PyObject * -verifying_adapter_hook(verify *self, PyObject *args, PyObject *kwds) +static PyObject* +VB_adapter_hook(VB* self, PyObject* args, PyObject* kwds) { - static char *kwlist[] = {"provided", "object", "name", "default", NULL}; - PyObject *object, *provided, *name=NULL, *default_=NULL; + 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 (!PyArg_ParseTupleAndKeywords( + args, kwds, "OO|OO", kwlist, &provided, &object, &name, &default_)) + return NULL; - if (_verify(self) < 0) - return NULL; + if (_verify(self) < 0) + return NULL; - return _adapter_hook((lookup *)self, provided, object, name, default_); + return _adapter_hook((LB*)self, provided, object, name, default_); } -static PyObject * -verifying_queryAdapter(verify *self, PyObject *args, PyObject *kwds) +static PyObject* +VB_queryAdapter(VB* self, PyObject* args, PyObject* kwds) { - static char *kwlist[] = {"object", "provided", "name", "default", NULL}; - PyObject *object, *provided, *name=NULL, *default_=NULL; + 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 (!PyArg_ParseTupleAndKeywords( + args, kwds, "OO|OO", kwlist, &object, &provided, &name, &default_)) + return NULL; - if (_verify(self) < 0) - return NULL; + if (_verify(self) < 0) + return NULL; - return _adapter_hook((lookup *)self, provided, object, name, default_); + return _adapter_hook((LB*)self, provided, object, name, default_); } -static PyObject * -verifying_lookupAll(verify *self, PyObject *args, PyObject *kwds) +static PyObject* +VB_lookupAll(VB* self, PyObject* args, PyObject* kwds) { - static char *kwlist[] = {"required", "provided", NULL}; - PyObject *required, *provided; + static char* kwlist[] = { "required", "provided", NULL }; + PyObject *required, *provided; - if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, - &required, &provided)) - return NULL; + if (!PyArg_ParseTupleAndKeywords( + args, kwds, "OO", kwlist, &required, &provided)) + return NULL; - if (_verify(self) < 0) - return NULL; + if (_verify(self) < 0) + return NULL; - return _lookupAll((lookup *)self, required, provided); + return _lookupAll((LB*)self, required, provided); } -static PyObject * -verifying_subscriptions(verify *self, PyObject *args, PyObject *kwds) +static PyObject* +VB_subscriptions(VB* self, PyObject* args, PyObject* kwds) { - static char *kwlist[] = {"required", "provided", NULL}; - PyObject *required, *provided; + static char* kwlist[] = { "required", "provided", NULL }; + PyObject *required, *provided; - if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, - &required, &provided)) - return NULL; + if (!PyArg_ParseTupleAndKeywords( + args, kwds, "OO", kwlist, &required, &provided)) + return NULL; - if (_verify(self) < 0) - return NULL; + if (_verify(self) < 0) + return NULL; - return _subscriptions((lookup *)self, required, provided); + return _subscriptions((LB*)self, required, provided); } -static struct PyMethodDef verifying_methods[] = { - {"changed", (PyCFunction)verifying_changed, METH_O, ""}, - {"lookup", (PyCFunction)verifying_lookup, METH_KEYWORDS | METH_VARARGS, ""}, - {"lookup1", (PyCFunction)verifying_lookup1, METH_KEYWORDS | METH_VARARGS, ""}, - {"queryAdapter", (PyCFunction)verifying_queryAdapter, METH_KEYWORDS | METH_VARARGS, ""}, - {"adapter_hook", (PyCFunction)verifying_adapter_hook, METH_KEYWORDS | METH_VARARGS, ""}, - {"lookupAll", (PyCFunction)verifying_lookupAll, METH_KEYWORDS | METH_VARARGS, ""}, - {"subscriptions", (PyCFunction)verifying_subscriptions, METH_KEYWORDS | METH_VARARGS, ""}, - {NULL, NULL} /* sentinel */ +static struct PyMethodDef VB_methods[] = { + { "changed", (PyCFunction)verify_changed, METH_O, "" }, + { "lookup", + (PyCFunction)VB_lookup, + METH_KEYWORDS | METH_VARARGS, + "" }, + { "lookup1", + (PyCFunction)VB_lookup1, + METH_KEYWORDS | METH_VARARGS, + "" }, + { "queryAdapter", + (PyCFunction)VB_queryAdapter, + METH_KEYWORDS | METH_VARARGS, + "" }, + { "adapter_hook", + (PyCFunction)VB_adapter_hook, + METH_KEYWORDS | METH_VARARGS, + "" }, + { "lookupAll", + (PyCFunction)VB_lookupAll, + METH_KEYWORDS | METH_VARARGS, + "" }, + { "subscriptions", + (PyCFunction)VB_subscriptions, + METH_KEYWORDS | METH_VARARGS, + "" }, + { NULL, NULL } /* sentinel */ }; -static PyTypeObject VerifyingBase = { - PyVarObject_HEAD_INIT(NULL, 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 */ 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, -}; +static char VB__name__[] = "_zope_interface_coptimizations.VerifyingBase"; +static char VB__doc__[] = "Base class for verifying adapter registries."; -/* ========================== End: Lookup Bases ======================= */ -/* ==================================================================== */ +#if USE_STATIC_TYPES +/* + * Static type: VerifyingBase + */ + +static PyTypeObject VB_type_def = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = VB__name__, + .tp_doc = VB__doc__, + .tp_base = &LB_type_def, + .tp_basicsize = sizeof(VB), + .tp_flags = BASETYPE_FLAGS, + .tp_traverse = (traverseproc)VB_traverse, + .tp_clear = (inquiry)VB_clear, + .tp_dealloc = (destructor)&VB_dealloc, + .tp_methods = VB_methods, +}; -static struct PyMethodDef m_methods[] = { - {"implementedBy", (PyCFunction)implementedBy, METH_O, - "Interfaces implemented by a class or factory.\n" - "Raises TypeError if argument is neither a class nor a callable."}, - {"getObjectSpecification", (PyCFunction)getObjectSpecification, METH_O, - "Get an object's interfaces (internal api)"}, - {"providedBy", (PyCFunction)providedBy, METH_O, - "Get an object's interfaces"}, +#else - {NULL, (PyCFunction)NULL, 0, NULL} /* sentinel */ +/* + * Heap type: VerifyingBase + */ +static PyType_Slot VB_type_slots[] = { + {Py_tp_doc, VB__doc__}, + {Py_tp_traverse, VB_traverse}, + {Py_tp_clear, VB_clear}, + {Py_tp_dealloc, VB_dealloc}, + {Py_tp_methods, VB_methods}, + /* tp_base cannot be set as a slot -- pass to PyType_FromModuleAndSpec */ + {0, NULL} }; -static char module_doc[] = "C optimizations for zope.interface\n\n"; - -static struct PyModuleDef _zic_module = { - PyModuleDef_HEAD_INIT, - "_zope_interface_coptimizations", - module_doc, - -1, - m_methods, - NULL, - NULL, - NULL, - NULL +static PyType_Spec VB_type_spec = { + .name = VB__name__, + .basicsize = sizeof(VB), + .flags = BASETYPE_FLAGS, + .slots = VB_type_slots }; -static PyObject * -init(void) +#endif + + +/* + * Module state struct: holds all data formerly kept as static globals. + */ +typedef struct { - PyObject *m; - -#define DEFINE_STRING(S) \ - if(! (str ## S = PyUnicode_FromString(# S))) return NULL - - DEFINE_STRING(__dict__); - DEFINE_STRING(__implemented__); - DEFINE_STRING(__provides__); - DEFINE_STRING(__class__); - DEFINE_STRING(__providedBy__); - DEFINE_STRING(extends); - 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); - 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) - return NULL; + /* our globals (exposed to Python) */ + PyTypeObject* specification_base_class; + PyTypeObject* object_specification_descriptor_class; + PyTypeObject* class_provides_base_class; + PyTypeObject* interface_base_class; + PyTypeObject* lookup_base_class; + PyTypeObject* verifying_base_class; + PyObject* adapter_hooks; + /* members imported from 'zope.interface.declarations' + */ + PyObject* empty; + PyObject* fallback; + PyObject* builtin_impl_specs; + PyTypeObject* implements_class; + /* flag: have we imported the next set of members yet from + * 'zope.interface.declarations? + */ + int decl_imported; +} _zic_module_state; - /* Initialize types: */ - SpecificationBaseType.tp_new = PyBaseObject_Type.tp_new; - if (PyType_Ready(&SpecificationBaseType) < 0) - return NULL; - OSDType.tp_new = PyBaseObject_Type.tp_new; - if (PyType_Ready(&OSDType) < 0) - return NULL; - CPBType.tp_new = PyBaseObject_Type.tp_new; - if (PyType_Ready(&CPBType) < 0) - return NULL; +/* + * Macro to speed lookup of state members + */ +#define _zic_state(o) ((_zic_module_state*)PyModule_GetState(o)) - InterfaceBaseType.tp_new = PyBaseObject_Type.tp_new; - if (PyType_Ready(&InterfaceBaseType) < 0) - return NULL; +static _zic_module_state* +_zic_state_init(PyObject* module) +{ + _zic_module_state* rec = _zic_state(module); + + rec->specification_base_class = NULL; + rec->object_specification_descriptor_class = NULL; + rec->class_provides_base_class = NULL; + rec->interface_base_class = NULL; + rec->lookup_base_class = NULL; + rec->verifying_base_class = NULL; + rec->adapter_hooks = NULL; + + rec->builtin_impl_specs = NULL; + rec->empty = NULL; + rec->fallback = NULL; + rec->implements_class = NULL; + rec->decl_imported = 0; + + return rec; +} - LookupBase.tp_new = PyBaseObject_Type.tp_new; - if (PyType_Ready(&LookupBase) < 0) - return NULL; +static int +_zic_state_traverse(PyObject* module, visitproc visit, void* arg) +{ + _zic_module_state* rec = _zic_state(module); - VerifyingBase.tp_new = PyBaseObject_Type.tp_new; - if (PyType_Ready(&VerifyingBase) < 0) - return NULL; + Py_VISIT(rec->specification_base_class); + Py_VISIT(rec->object_specification_descriptor_class); + Py_VISIT(rec->class_provides_base_class); + Py_VISIT(rec->interface_base_class); + Py_VISIT(rec->lookup_base_class); + Py_VISIT(rec->verifying_base_class); + Py_VISIT(rec->adapter_hooks); - m = PyModule_Create(&_zic_module); - if (m == NULL) - return NULL; + Py_VISIT(rec->builtin_impl_specs); + Py_VISIT(rec->empty); + Py_VISIT(rec->fallback); + Py_VISIT(rec->implements_class); - /* Add types: */ - if (PyModule_AddObject(m, "SpecificationBase", OBJECT(&SpecificationBaseType)) < 0) - return NULL; - if (PyModule_AddObject(m, "ObjectSpecificationDescriptor", - (PyObject *)&OSDType) < 0) - return NULL; - if (PyModule_AddObject(m, "ClassProvidesBase", OBJECT(&CPBType)) < 0) - return NULL; - if (PyModule_AddObject(m, "InterfaceBase", OBJECT(&InterfaceBaseType)) < 0) - return NULL; - if (PyModule_AddObject(m, "LookupBase", OBJECT(&LookupBase)) < 0) - return NULL; - if (PyModule_AddObject(m, "VerifyingBase", OBJECT(&VerifyingBase)) < 0) - return NULL; - if (PyModule_AddObject(m, "adapter_hooks", adapter_hooks) < 0) + return 0; +} + +static int +_zic_state_clear(PyObject* module) +{ + _zic_module_state* rec = _zic_state(module); + + Py_CLEAR(rec->specification_base_class); + Py_CLEAR(rec->object_specification_descriptor_class); + Py_CLEAR(rec->class_provides_base_class); + Py_CLEAR(rec->interface_base_class); + Py_CLEAR(rec->lookup_base_class); + Py_CLEAR(rec->verifying_base_class); + Py_CLEAR(rec->adapter_hooks); + + Py_CLEAR(rec->builtin_impl_specs); + Py_CLEAR(rec->empty); + Py_CLEAR(rec->fallback); + Py_CLEAR(rec->implements_class); + + return 0; +} + +#if USE_HEAP_TYPES +/* Import zope.interface.declarations and store results in module state. + * + * Dynamic alternative to 'import_declarations' above. + */ +static _zic_module_state* +_zic_state_load_declarations(PyObject* module) +{ + PyObject* declarations; + PyObject* builtin_impl_specs; + PyObject* empty; + PyObject* fallback; + PyObject* implements; + + _zic_module_state* rec = _zic_state(module); + + if (!rec->decl_imported) { + declarations = PyImport_ImportModule("zope.interface.declarations"); + if (declarations == NULL) { + return NULL; + } + + builtin_impl_specs = PyObject_GetAttrString( + declarations, "BuiltinImplementationSpecifications"); + if (builtin_impl_specs == NULL) { + return NULL; + } + + empty = PyObject_GetAttrString(declarations, "_empty"); + if (empty == NULL) { + return NULL; + } + + fallback = + PyObject_GetAttrString(declarations, "implementedByFallback"); + if (fallback == NULL) { + return NULL; + } + + implements = PyObject_GetAttrString(declarations, "Implements"); + if (implements == NULL) { + return NULL; + } + + if (!PyType_Check(implements)) { + PyErr_SetString( + PyExc_TypeError, + "zope.interface.declarations.Implements is not a type"); + return NULL; + } + + Py_DECREF(declarations); + + rec->builtin_impl_specs = builtin_impl_specs; + rec->empty = empty; + rec->fallback = fallback; + rec->implements_class = (PyTypeObject*)implements; + rec->decl_imported = 1; + } + return rec; +} + +#endif + +/* + * Provide access to the current module given the type. + */ + +static struct PyModuleDef _zic_module_def; + +static PyObject* +_get_module(PyTypeObject *typeobj) +{ +#if USE_STATIC_TYPES + return (PyObject*)&_zic_module_def; +#else + if (PyType_Check(typeobj)) { + /* Only added in Python 3.11 */ + return PyType_GetModuleByDef(typeobj, &_zic_module_def); + } + + PyErr_SetString(PyExc_TypeError, "_get_module: called w/ non-type"); return NULL; - return m; +#endif +} + +/* + * Fetch the adapter hooks for the current type's module. + */ +static PyObject* +_get_adapter_hooks(PyTypeObject *typeobj) +{ +#if USE_STATIC_TYPES + return adapter_hooks; +#else + PyObject* module; + _zic_module_state* rec; + + module = _get_module(typeobj); + if (module == NULL) { return NULL; } + + rec = _zic_state(module); + return rec->adapter_hooks; +#endif +} + +/* + * Fetch the 'SpecificationBase' class for the current type's module. + */ +static PyTypeObject* +_get_specification_base_class(PyTypeObject *typeobj) +{ +#if USE_STATIC_TYPES + return &SB_type_def; +#else + PyObject* module; + _zic_module_state* rec; + + module = _get_module(typeobj); + if (module == NULL) { return NULL; } + + rec = _zic_state(module); + return rec->specification_base_class; +#endif +} + +/* + * Fetch the 'InterfaceBase' class for the current type's module. + */ +static PyTypeObject* +_get_interface_base_class(PyTypeObject *typeobj) +{ +#if USE_STATIC_TYPES + return &IB_type_def; +#else + PyObject* module; + _zic_module_state* rec; + + module = _get_module(typeobj); + if (module == NULL) { return NULL; } + + rec = _zic_state(module); + return rec->interface_base_class; +#endif +} + +static PyObject* +implementedByFallback(PyObject* module, PyObject* cls) +{ +#if USE_STATIC_TYPES + if (imported_declarations == 0 && import_declarations() < 0) { + return NULL; + } + /* now use static 'fallback' */ +#else + PyObject* fallback; + + _zic_module_state* rec = _zic_state_load_declarations(module); + if (rec == NULL) { return NULL; } + + fallback = rec->fallback; +#endif + + return PyObject_CallFunctionObjArgs(fallback, cls, NULL); +} + +static char implementedBy___doc__[] = + ("Interfaces implemented by a class or factory.\n" + "Raises TypeError if argument is neither a class nor a callable."); + +static PyObject* +implementedBy(PyObject* module, PyObject* cls) +{ + /* Fast retrieval of implements spec, if possible, to optimize + common case. Use fallback code if we get stuck. + */ + PyObject *dict = NULL; + PyObject *spec; + PyTypeObject *implements_class; + PyObject *builtin_impl_specs; + +#if USE_STATIC_TYPES + if (imported_declarations == 0 && import_declarations() < 0) { + return NULL; + } + + implements_class = Implements; + builtin_impl_specs = BuiltinImplementationSpecifications; +#else + _zic_module_state* rec = _zic_state_load_declarations(module); + if (rec == NULL) { return NULL; } + + implements_class = rec->implements_class; + builtin_impl_specs = rec->builtin_impl_specs; +#endif + + if (PyObject_TypeCheck(cls, &PySuper_Type)) { + // Let merging be handled by Python. + return implementedByFallback(module, cls); + } + + if (PyType_Check(cls)) { + dict = TYPE(cls)->tp_dict; + Py_XINCREF(dict); + } + + if (dict == NULL) + dict = PyObject_GetAttr(cls, str__dict__); + + if (dict == NULL) { + /* Probably a security proxied class, use more expensive fallback code + */ + PyErr_Clear(); + return implementedByFallback(module, cls); + } + + spec = PyObject_GetItem(dict, str__implemented__); + Py_DECREF(dict); + if (spec) { + + if (PyObject_TypeCheck(spec, implements_class)) + return spec; + + /* Old-style declaration, use more expensive fallback code */ + Py_DECREF(spec); + return implementedByFallback(module, cls); + } + + PyErr_Clear(); + + /* Maybe we have a builtin */ + spec = PyDict_GetItem(builtin_impl_specs, cls); + if (spec != NULL) { + Py_INCREF(spec); + return spec; + } + + /* We're stuck, use fallback */ + return implementedByFallback(module, cls); +} + +static char getObjectSpecification___doc__[] = + ("Get an object's interfaces (internal api)"); + +static PyObject* +getObjectSpecification(PyObject* module, PyObject* ob) +{ + PyObject *cls; + PyObject *result; + PyTypeObject *specification_base_class; + PyObject *empty_; + +#if USE_STATIC_TYPES + specification_base_class = &SB_type_def; + + if (imported_declarations == 0 && import_declarations() < 0) { + return NULL; + } + empty_ = empty; /* global from import */ + +#else + _zic_module_state* rec = _zic_state_load_declarations(module); + if (rec == NULL) { return NULL; } + + specification_base_class = rec->specification_base_class; + empty_ = rec->empty; +#endif + + result = PyObject_GetAttr(ob, str__provides__); + if (!result) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { + /* Propagate non AttributeError exceptions. */ + return NULL; + } + PyErr_Clear(); + } else { + int is_instance = -1; + is_instance = + PyObject_IsInstance(result, OBJECT(specification_base_class)); + if (is_instance < 0) { + /* Propagate all errors */ + return NULL; + } + if (is_instance) { + return result; + } + } + + /* We do a getattr here so as not to be defeated by proxies */ + cls = PyObject_GetAttr(ob, str__class__); + if (cls == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { + /* Propagate non-AttributeErrors */ + return NULL; + } + PyErr_Clear(); + + Py_INCREF(empty_); + return empty_; + } + result = implementedBy(module, cls); + Py_DECREF(cls); + + return result; +} + +static char providedBy___doc__[] = ("Get an object's interfaces"); + +static PyObject* +providedBy(PyObject* module, PyObject* ob) +{ + PyObject *result = NULL; + PyObject *cls; + PyObject *cp; + PyTypeObject *specification_base_class; + int is_instance = -1; + + is_instance = PyObject_IsInstance(ob, (PyObject*)&PySuper_Type); + if (is_instance < 0) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { + /* Propagate non-AttributeErrors */ + return NULL; + } + PyErr_Clear(); + } + if (is_instance) { + return implementedBy(module, ob); + } + + result = PyObject_GetAttr(ob, str__providedBy__); + + if (result == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { + return NULL; + } + + PyErr_Clear(); + return getObjectSpecification(module, ob); + } + + /* We want to make sure we have a spec. We can't do a type check + because we may have a proxy, so we'll just try to get the + only attribute. + */ +#if USE_STATIC_TYPES + specification_base_class = &SB_type_def; +#else + _zic_module_state* rec = _zic_state(module); + specification_base_class = rec->specification_base_class; +#endif + if (PyObject_TypeCheck(result, specification_base_class) || + PyObject_HasAttrString(result, "extends")) + return result; + + /* + The object's class doesn't understand descriptors. + Sigh. We need to get an object descriptor, but we have to be + careful. We want to use the instance's __provides__,l if + there is one, but only if it didn't come from the class. + */ + Py_DECREF(result); + + cls = PyObject_GetAttr(ob, str__class__); + if (cls == NULL) + return NULL; + + result = PyObject_GetAttr(ob, str__provides__); + if (result == NULL) { + /* No __provides__, so just fall back to implementedBy */ + PyErr_Clear(); + result = implementedBy(module, cls); + Py_DECREF(cls); + return result; + } + + cp = PyObject_GetAttr(cls, str__provides__); + if (cp == NULL) { + /* The the class has no provides, assume we're done: */ + PyErr_Clear(); + Py_DECREF(cls); + return result; + } + + if (cp == result) { + /* + Oops, we got the provides from the class. This means + the object doesn't have it's own. We should use implementedBy + */ + Py_DECREF(result); + result = implementedBy(module, cls); + } + + Py_DECREF(cls); + Py_DECREF(cp); + + return result; +} + +static struct PyMethodDef _zic_module_methods[] = { + { "implementedBy", + (PyCFunction)implementedBy, + METH_O, + implementedBy___doc__ }, + { "getObjectSpecification", + (PyCFunction)getObjectSpecification, + METH_O, + getObjectSpecification___doc__ }, + { "providedBy", (PyCFunction)providedBy, METH_O, providedBy___doc__ }, + + { NULL, (PyCFunction)NULL, 0, NULL } /* sentinel */ +}; + + +/* Handler for the 'execute' phase of multi-phase initialization + * + * See: https://docs.python.org/3/c-api/module.html#multi-phase-initialization + * and: https://peps.python.org/pep-0489/#module-execution-phase + */ +static int +_zic_module_exec(PyObject* module) +{ + _zic_module_state* rec = _zic_state_init(module); + + rec->adapter_hooks = PyList_New(0); + if (rec->adapter_hooks == NULL) + return -1; + Py_INCREF(rec->adapter_hooks); + +#if USE_STATIC_TYPES + + /* Initialize static global */ + adapter_hooks = rec->adapter_hooks; + + /* Initialize types: */ + SB_type_def.tp_new = PyBaseObject_Type.tp_new; + if (PyType_Ready(&SB_type_def) < 0) { return -1; } + Py_INCREF(&SB_type_def); + rec->specification_base_class = &SB_type_def; + + OSD_type_def.tp_new = PyBaseObject_Type.tp_new; + if (PyType_Ready(&OSD_type_def) < 0) { return -1; } + Py_INCREF(&OSD_type_def); + rec->object_specification_descriptor_class = &OSD_type_def; + + CPB_type_def.tp_new = PyBaseObject_Type.tp_new; + if (PyType_Ready(&CPB_type_def) < 0) { return -1; } + Py_INCREF(&CPB_type_def); + rec->class_provides_base_class = &CPB_type_def; + + IB_type_def.tp_new = PyBaseObject_Type.tp_new; + if (PyType_Ready(&IB_type_def) < 0) { return -1; } + Py_INCREF(&IB_type_def); + rec->interface_base_class = &IB_type_def; + + LB_type_def.tp_new = PyBaseObject_Type.tp_new; + if (PyType_Ready(&LB_type_def) < 0) { return -1; } + Py_INCREF(&LB_type_def); + rec->lookup_base_class = &LB_type_def; + + VB_type_def.tp_new = PyBaseObject_Type.tp_new; + if (PyType_Ready(&VB_type_def) < 0) { return -1; } + Py_INCREF(&VB_type_def); + rec->verifying_base_class = &VB_type_def; + +#else + + PyObject *sb_class; + PyObject *osd_class; + PyObject *cpb_class; + PyObject *ib_class; + PyObject *lb_class; + PyObject *vb_class; + + /* Initialize types: + */ + sb_class = PyType_FromModuleAndSpec(module, &SB_type_spec, NULL); + if (sb_class == NULL) { return -1; } + Py_INCREF(sb_class); + rec->specification_base_class = TYPE(sb_class); + + osd_class = PyType_FromModuleAndSpec(module, &OSD_type_spec, NULL); + if (osd_class == NULL) { return -1; } + Py_INCREF(osd_class); + rec->object_specification_descriptor_class = TYPE(osd_class); + + cpb_class = PyType_FromModuleAndSpec(module, &CPB_type_spec, sb_class); + if (cpb_class == NULL) { return -1; } + Py_INCREF(cpb_class); + rec->class_provides_base_class = TYPE(cpb_class); + + ib_class = PyType_FromModuleAndSpec(module, &IB_type_spec, sb_class); + if (ib_class == NULL) { return -1; } + Py_INCREF(ib_class); + rec->interface_base_class = TYPE(ib_class); + + lb_class = PyType_FromModuleAndSpec(module, &LB_type_spec, NULL); + if (lb_class == NULL) { return -1; } + Py_INCREF(lb_class); + rec->lookup_base_class = TYPE(lb_class); + + vb_class = PyType_FromModuleAndSpec(module, &VB_type_spec, lb_class); + if (vb_class == NULL) { return -1; } + Py_INCREF(vb_class); + rec->verifying_base_class = TYPE(vb_class); + +#endif + + /* Add types to our dict FBO python; also the adapter hooks */ + if (PyModule_AddObject(module, + "SpecificationBase", OBJECT(rec->specification_base_class)) < 0) + return -1; + + if (PyModule_AddObject(module, + "ObjectSpecificationDescriptor", + OBJECT(rec->object_specification_descriptor_class)) < + 0) + return -1; + + if (PyModule_AddObject(module, + "ClassProvidesBase", OBJECT(rec->class_provides_base_class)) < 0) + return -1; + + if (PyModule_AddObject(module, + "InterfaceBase", OBJECT(rec->interface_base_class)) < 0) + return -1; + + if (PyModule_AddObject(module, + "LookupBase", OBJECT(rec->lookup_base_class)) < 0) + return -1; + + if (PyModule_AddObject(module, + "VerifyingBase", OBJECT(rec->verifying_base_class)) < 0) + return -1; + + if (PyModule_AddObject(module, "adapter_hooks", rec->adapter_hooks) < 0) + return -1; + + return 0; +} + + +/* Slot definitions for multi-phase initialization + * + * See: https://docs.python.org/3/c-api/module.html#multi-phase-initialization + * and: https://peps.python.org/pep-0489 + */ +static PyModuleDef_Slot _zic_module_slots[] = { + {Py_mod_exec, _zic_module_exec}, + {0, NULL} +}; + +static char _zic_module__doc__[] = "C optimizations for zope.interface\n\n"; + +static struct PyModuleDef _zic_module_def = { + PyModuleDef_HEAD_INIT, + .m_name = "_zope_interface_coptimizations", + .m_doc = _zic_module__doc__, + .m_size = sizeof(_zic_module_state), + .m_methods = _zic_module_methods, + .m_slots=_zic_module_slots, + .m_traverse = _zic_state_traverse, + .m_clear = _zic_state_clear, +}; + +static PyObject* +init(void) +{ + if (define_static_strings() < 0) { return NULL; } + + return PyModuleDef_Init(&_zic_module_def); } PyMODINIT_FUNC PyInit__zope_interface_coptimizations(void) { - return init(); + return init(); } #ifdef __clang__ |