summaryrefslogtreecommitdiffstats
path: root/AppPkg/Applications/Python/Python-2.7.2/Objects/typeobject.c
diff options
context:
space:
mode:
Diffstat (limited to 'AppPkg/Applications/Python/Python-2.7.2/Objects/typeobject.c')
-rw-r--r--AppPkg/Applications/Python/Python-2.7.2/Objects/typeobject.c6712
1 files changed, 6712 insertions, 0 deletions
diff --git a/AppPkg/Applications/Python/Python-2.7.2/Objects/typeobject.c b/AppPkg/Applications/Python/Python-2.7.2/Objects/typeobject.c
new file mode 100644
index 0000000000..58becb79f4
--- /dev/null
+++ b/AppPkg/Applications/Python/Python-2.7.2/Objects/typeobject.c
@@ -0,0 +1,6712 @@
+/* Type object implementation */
+
+#include "Python.h"
+#include "structmember.h"
+
+#include <ctype.h>
+
+
+/* Support type attribute cache */
+
+/* The cache can keep references to the names alive for longer than
+ they normally would. This is why the maximum size is limited to
+ MCACHE_MAX_ATTR_SIZE, since it might be a problem if very large
+ strings are used as attribute names. */
+#define MCACHE_MAX_ATTR_SIZE 100
+#define MCACHE_SIZE_EXP 10
+#define MCACHE_HASH(version, name_hash) \
+ (((unsigned int)(version) * (unsigned int)(name_hash)) \
+ >> (8*sizeof(unsigned int) - MCACHE_SIZE_EXP))
+#define MCACHE_HASH_METHOD(type, name) \
+ MCACHE_HASH((type)->tp_version_tag, \
+ ((PyStringObject *)(name))->ob_shash)
+#define MCACHE_CACHEABLE_NAME(name) \
+ PyString_CheckExact(name) && \
+ PyString_GET_SIZE(name) <= MCACHE_MAX_ATTR_SIZE
+
+struct method_cache_entry {
+ unsigned int version;
+ PyObject *name; /* reference to exactly a str or None */
+ PyObject *value; /* borrowed */
+};
+
+static struct method_cache_entry method_cache[1 << MCACHE_SIZE_EXP];
+static unsigned int next_version_tag = 0;
+
+unsigned int
+PyType_ClearCache(void)
+{
+ Py_ssize_t i;
+ unsigned int cur_version_tag = next_version_tag - 1;
+
+ for (i = 0; i < (1 << MCACHE_SIZE_EXP); i++) {
+ method_cache[i].version = 0;
+ Py_CLEAR(method_cache[i].name);
+ method_cache[i].value = NULL;
+ }
+ next_version_tag = 0;
+ /* mark all version tags as invalid */
+ PyType_Modified(&PyBaseObject_Type);
+ return cur_version_tag;
+}
+
+void
+PyType_Modified(PyTypeObject *type)
+{
+ /* Invalidate any cached data for the specified type and all
+ subclasses. This function is called after the base
+ classes, mro, or attributes of the type are altered.
+
+ Invariants:
+
+ - Py_TPFLAGS_VALID_VERSION_TAG is never set if
+ Py_TPFLAGS_HAVE_VERSION_TAG is not set (e.g. on type
+ objects coming from non-recompiled extension modules)
+
+ - before Py_TPFLAGS_VALID_VERSION_TAG can be set on a type,
+ it must first be set on all super types.
+
+ This function clears the Py_TPFLAGS_VALID_VERSION_TAG of a
+ type (so it must first clear it on all subclasses). The
+ tp_version_tag value is meaningless unless this flag is set.
+ We don't assign new version tags eagerly, but only as
+ needed.
+ */
+ PyObject *raw, *ref;
+ Py_ssize_t i, n;
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG))
+ return;
+
+ raw = type->tp_subclasses;
+ if (raw != NULL) {
+ n = PyList_GET_SIZE(raw);
+ for (i = 0; i < n; i++) {
+ ref = PyList_GET_ITEM(raw, i);
+ ref = PyWeakref_GET_OBJECT(ref);
+ if (ref != Py_None) {
+ PyType_Modified((PyTypeObject *)ref);
+ }
+ }
+ }
+ type->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG;
+}
+
+static void
+type_mro_modified(PyTypeObject *type, PyObject *bases) {
+ /*
+ Check that all base classes or elements of the mro of type are
+ able to be cached. This function is called after the base
+ classes or mro of the type are altered.
+
+ Unset HAVE_VERSION_TAG and VALID_VERSION_TAG if the type
+ inherits from an old-style class, either directly or if it
+ appears in the MRO of a new-style class. No support either for
+ custom MROs that include types that are not officially super
+ types.
+
+ Called from mro_internal, which will subsequently be called on
+ each subclass when their mro is recursively updated.
+ */
+ Py_ssize_t i, n;
+ int clear = 0;
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_HAVE_VERSION_TAG))
+ return;
+
+ n = PyTuple_GET_SIZE(bases);
+ for (i = 0; i < n; i++) {
+ PyObject *b = PyTuple_GET_ITEM(bases, i);
+ PyTypeObject *cls;
+
+ if (!PyType_Check(b) ) {
+ clear = 1;
+ break;
+ }
+
+ cls = (PyTypeObject *)b;
+
+ if (!PyType_HasFeature(cls, Py_TPFLAGS_HAVE_VERSION_TAG) ||
+ !PyType_IsSubtype(type, cls)) {
+ clear = 1;
+ break;
+ }
+ }
+
+ if (clear)
+ type->tp_flags &= ~(Py_TPFLAGS_HAVE_VERSION_TAG|
+ Py_TPFLAGS_VALID_VERSION_TAG);
+}
+
+static int
+assign_version_tag(PyTypeObject *type)
+{
+ /* Ensure that the tp_version_tag is valid and set
+ Py_TPFLAGS_VALID_VERSION_TAG. To respect the invariant, this
+ must first be done on all super classes. Return 0 if this
+ cannot be done, 1 if Py_TPFLAGS_VALID_VERSION_TAG.
+ */
+ Py_ssize_t i, n;
+ PyObject *bases;
+
+ if (PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG))
+ return 1;
+ if (!PyType_HasFeature(type, Py_TPFLAGS_HAVE_VERSION_TAG))
+ return 0;
+ if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+ return 0;
+
+ type->tp_version_tag = next_version_tag++;
+ /* for stress-testing: next_version_tag &= 0xFF; */
+
+ if (type->tp_version_tag == 0) {
+ /* wrap-around or just starting Python - clear the whole
+ cache by filling names with references to Py_None.
+ Values are also set to NULL for added protection, as they
+ are borrowed reference */
+ for (i = 0; i < (1 << MCACHE_SIZE_EXP); i++) {
+ method_cache[i].value = NULL;
+ Py_XDECREF(method_cache[i].name);
+ method_cache[i].name = Py_None;
+ Py_INCREF(Py_None);
+ }
+ /* mark all version tags as invalid */
+ PyType_Modified(&PyBaseObject_Type);
+ return 1;
+ }
+ bases = type->tp_bases;
+ n = PyTuple_GET_SIZE(bases);
+ for (i = 0; i < n; i++) {
+ PyObject *b = PyTuple_GET_ITEM(bases, i);
+ assert(PyType_Check(b));
+ if (!assign_version_tag((PyTypeObject *)b))
+ return 0;
+ }
+ type->tp_flags |= Py_TPFLAGS_VALID_VERSION_TAG;
+ return 1;
+}
+
+
+static PyMemberDef type_members[] = {
+ {"__basicsize__", T_PYSSIZET, offsetof(PyTypeObject,tp_basicsize),READONLY},
+ {"__itemsize__", T_PYSSIZET, offsetof(PyTypeObject, tp_itemsize), READONLY},
+ {"__flags__", T_LONG, offsetof(PyTypeObject, tp_flags), READONLY},
+ {"__weakrefoffset__", T_LONG,
+ offsetof(PyTypeObject, tp_weaklistoffset), READONLY},
+ {"__base__", T_OBJECT, offsetof(PyTypeObject, tp_base), READONLY},
+ {"__dictoffset__", T_LONG,
+ offsetof(PyTypeObject, tp_dictoffset), READONLY},
+ {"__mro__", T_OBJECT, offsetof(PyTypeObject, tp_mro), READONLY},
+ {0}
+};
+
+static PyObject *
+type_name(PyTypeObject *type, void *context)
+{
+ const char *s;
+
+ if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) {
+ PyHeapTypeObject* et = (PyHeapTypeObject*)type;
+
+ Py_INCREF(et->ht_name);
+ return et->ht_name;
+ }
+ else {
+ s = strrchr(type->tp_name, '.');
+ if (s == NULL)
+ s = type->tp_name;
+ else
+ s++;
+ return PyString_FromString(s);
+ }
+}
+
+static int
+type_set_name(PyTypeObject *type, PyObject *value, void *context)
+{
+ PyHeapTypeObject* et;
+
+ if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
+ PyErr_Format(PyExc_TypeError,
+ "can't set %s.__name__", type->tp_name);
+ return -1;
+ }
+ if (!value) {
+ PyErr_Format(PyExc_TypeError,
+ "can't delete %s.__name__", type->tp_name);
+ return -1;
+ }
+ if (!PyString_Check(value)) {
+ PyErr_Format(PyExc_TypeError,
+ "can only assign string to %s.__name__, not '%s'",
+ type->tp_name, Py_TYPE(value)->tp_name);
+ return -1;
+ }
+ if (strlen(PyString_AS_STRING(value))
+ != (size_t)PyString_GET_SIZE(value)) {
+ PyErr_Format(PyExc_ValueError,
+ "__name__ must not contain null bytes");
+ return -1;
+ }
+
+ et = (PyHeapTypeObject*)type;
+
+ Py_INCREF(value);
+
+ Py_DECREF(et->ht_name);
+ et->ht_name = value;
+
+ type->tp_name = PyString_AS_STRING(value);
+
+ return 0;
+}
+
+static PyObject *
+type_module(PyTypeObject *type, void *context)
+{
+ PyObject *mod;
+ char *s;
+
+ if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) {
+ mod = PyDict_GetItemString(type->tp_dict, "__module__");
+ if (!mod) {
+ PyErr_Format(PyExc_AttributeError, "__module__");
+ return 0;
+ }
+ Py_XINCREF(mod);
+ return mod;
+ }
+ else {
+ s = strrchr(type->tp_name, '.');
+ if (s != NULL)
+ return PyString_FromStringAndSize(
+ type->tp_name, (Py_ssize_t)(s - type->tp_name));
+ return PyString_FromString("__builtin__");
+ }
+}
+
+static int
+type_set_module(PyTypeObject *type, PyObject *value, void *context)
+{
+ if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
+ PyErr_Format(PyExc_TypeError,
+ "can't set %s.__module__", type->tp_name);
+ return -1;
+ }
+ if (!value) {
+ PyErr_Format(PyExc_TypeError,
+ "can't delete %s.__module__", type->tp_name);
+ return -1;
+ }
+
+ PyType_Modified(type);
+
+ return PyDict_SetItemString(type->tp_dict, "__module__", value);
+}
+
+static PyObject *
+type_abstractmethods(PyTypeObject *type, void *context)
+{
+ PyObject *mod = NULL;
+ /* type itself has an __abstractmethods__ descriptor (this). Don't return
+ that. */
+ if (type != &PyType_Type)
+ mod = PyDict_GetItemString(type->tp_dict, "__abstractmethods__");
+ if (!mod) {
+ PyErr_SetString(PyExc_AttributeError, "__abstractmethods__");
+ return NULL;
+ }
+ Py_XINCREF(mod);
+ return mod;
+}
+
+static int
+type_set_abstractmethods(PyTypeObject *type, PyObject *value, void *context)
+{
+ /* __abstractmethods__ should only be set once on a type, in
+ abc.ABCMeta.__new__, so this function doesn't do anything
+ special to update subclasses.
+ */
+ int res;
+ if (value != NULL) {
+ res = PyDict_SetItemString(type->tp_dict, "__abstractmethods__", value);
+ }
+ else {
+ res = PyDict_DelItemString(type->tp_dict, "__abstractmethods__");
+ if (res && PyErr_ExceptionMatches(PyExc_KeyError)) {
+ PyErr_SetString(PyExc_AttributeError, "__abstractmethods__");
+ return -1;
+ }
+ }
+ if (res == 0) {
+ PyType_Modified(type);
+ if (value && PyObject_IsTrue(value)) {
+ type->tp_flags |= Py_TPFLAGS_IS_ABSTRACT;
+ }
+ else {
+ type->tp_flags &= ~Py_TPFLAGS_IS_ABSTRACT;
+ }
+ }
+ return res;
+}
+
+static PyObject *
+type_get_bases(PyTypeObject *type, void *context)
+{
+ Py_INCREF(type->tp_bases);
+ return type->tp_bases;
+}
+
+static PyTypeObject *best_base(PyObject *);
+static int mro_internal(PyTypeObject *);
+static int compatible_for_assignment(PyTypeObject *, PyTypeObject *, char *);
+static int add_subclass(PyTypeObject*, PyTypeObject*);
+static void remove_subclass(PyTypeObject *, PyTypeObject *);
+static void update_all_slots(PyTypeObject *);
+
+typedef int (*update_callback)(PyTypeObject *, void *);
+static int update_subclasses(PyTypeObject *type, PyObject *name,
+ update_callback callback, void *data);
+static int recurse_down_subclasses(PyTypeObject *type, PyObject *name,
+ update_callback callback, void *data);
+
+static int
+mro_subclasses(PyTypeObject *type, PyObject* temp)
+{
+ PyTypeObject *subclass;
+ PyObject *ref, *subclasses, *old_mro;
+ Py_ssize_t i, n;
+
+ subclasses = type->tp_subclasses;
+ if (subclasses == NULL)
+ return 0;
+ assert(PyList_Check(subclasses));
+ n = PyList_GET_SIZE(subclasses);
+ for (i = 0; i < n; i++) {
+ ref = PyList_GET_ITEM(subclasses, i);
+ assert(PyWeakref_CheckRef(ref));
+ subclass = (PyTypeObject *)PyWeakref_GET_OBJECT(ref);
+ assert(subclass != NULL);
+ if ((PyObject *)subclass == Py_None)
+ continue;
+ assert(PyType_Check(subclass));
+ old_mro = subclass->tp_mro;
+ if (mro_internal(subclass) < 0) {
+ subclass->tp_mro = old_mro;
+ return -1;
+ }
+ else {
+ PyObject* tuple;
+ tuple = PyTuple_Pack(2, subclass, old_mro);
+ Py_DECREF(old_mro);
+ if (!tuple)
+ return -1;
+ if (PyList_Append(temp, tuple) < 0)
+ return -1;
+ Py_DECREF(tuple);
+ }
+ if (mro_subclasses(subclass, temp) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+static int
+type_set_bases(PyTypeObject *type, PyObject *value, void *context)
+{
+ Py_ssize_t i;
+ int r = 0;
+ PyObject *ob, *temp;
+ PyTypeObject *new_base, *old_base;
+ PyObject *old_bases, *old_mro;
+
+ if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
+ PyErr_Format(PyExc_TypeError,
+ "can't set %s.__bases__", type->tp_name);
+ return -1;
+ }
+ if (!value) {
+ PyErr_Format(PyExc_TypeError,
+ "can't delete %s.__bases__", type->tp_name);
+ return -1;
+ }
+ if (!PyTuple_Check(value)) {
+ PyErr_Format(PyExc_TypeError,
+ "can only assign tuple to %s.__bases__, not %s",
+ type->tp_name, Py_TYPE(value)->tp_name);
+ return -1;
+ }
+ if (PyTuple_GET_SIZE(value) == 0) {
+ PyErr_Format(PyExc_TypeError,
+ "can only assign non-empty tuple to %s.__bases__, not ()",
+ type->tp_name);
+ return -1;
+ }
+ for (i = 0; i < PyTuple_GET_SIZE(value); i++) {
+ ob = PyTuple_GET_ITEM(value, i);
+ if (!PyClass_Check(ob) && !PyType_Check(ob)) {
+ PyErr_Format(
+ PyExc_TypeError,
+ "%s.__bases__ must be tuple of old- or new-style classes, not '%s'",
+ type->tp_name, Py_TYPE(ob)->tp_name);
+ return -1;
+ }
+ if (PyType_Check(ob)) {
+ if (PyType_IsSubtype((PyTypeObject*)ob, type)) {
+ PyErr_SetString(PyExc_TypeError,
+ "a __bases__ item causes an inheritance cycle");
+ return -1;
+ }
+ }
+ }
+
+ new_base = best_base(value);
+
+ if (!new_base) {
+ return -1;
+ }
+
+ if (!compatible_for_assignment(type->tp_base, new_base, "__bases__"))
+ return -1;
+
+ Py_INCREF(new_base);
+ Py_INCREF(value);
+
+ old_bases = type->tp_bases;
+ old_base = type->tp_base;
+ old_mro = type->tp_mro;
+
+ type->tp_bases = value;
+ type->tp_base = new_base;
+
+ if (mro_internal(type) < 0) {
+ goto bail;
+ }
+
+ temp = PyList_New(0);
+ if (!temp)
+ goto bail;
+
+ r = mro_subclasses(type, temp);
+
+ if (r < 0) {
+ for (i = 0; i < PyList_Size(temp); i++) {
+ PyTypeObject* cls;
+ PyObject* mro;
+ PyArg_UnpackTuple(PyList_GET_ITEM(temp, i),
+ "", 2, 2, &cls, &mro);
+ Py_INCREF(mro);
+ ob = cls->tp_mro;
+ cls->tp_mro = mro;
+ Py_DECREF(ob);
+ }
+ Py_DECREF(temp);
+ goto bail;
+ }
+
+ Py_DECREF(temp);
+
+ /* any base that was in __bases__ but now isn't, we
+ need to remove |type| from its tp_subclasses.
+ conversely, any class now in __bases__ that wasn't
+ needs to have |type| added to its subclasses. */
+
+ /* for now, sod that: just remove from all old_bases,
+ add to all new_bases */
+
+ for (i = PyTuple_GET_SIZE(old_bases) - 1; i >= 0; i--) {
+ ob = PyTuple_GET_ITEM(old_bases, i);
+ if (PyType_Check(ob)) {
+ remove_subclass(
+ (PyTypeObject*)ob, type);
+ }
+ }
+
+ for (i = PyTuple_GET_SIZE(value) - 1; i >= 0; i--) {
+ ob = PyTuple_GET_ITEM(value, i);
+ if (PyType_Check(ob)) {
+ if (add_subclass((PyTypeObject*)ob, type) < 0)
+ r = -1;
+ }
+ }
+
+ update_all_slots(type);
+
+ Py_DECREF(old_bases);
+ Py_DECREF(old_base);
+ Py_DECREF(old_mro);
+
+ return r;
+
+ bail:
+ Py_DECREF(type->tp_bases);
+ Py_DECREF(type->tp_base);
+ if (type->tp_mro != old_mro) {
+ Py_DECREF(type->tp_mro);
+ }
+
+ type->tp_bases = old_bases;
+ type->tp_base = old_base;
+ type->tp_mro = old_mro;
+
+ return -1;
+}
+
+static PyObject *
+type_dict(PyTypeObject *type, void *context)
+{
+ if (type->tp_dict == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ return PyDictProxy_New(type->tp_dict);
+}
+
+static PyObject *
+type_get_doc(PyTypeObject *type, void *context)
+{
+ PyObject *result;
+ if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE) && type->tp_doc != NULL)
+ return PyString_FromString(type->tp_doc);
+ result = PyDict_GetItemString(type->tp_dict, "__doc__");
+ if (result == NULL) {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+ else if (Py_TYPE(result)->tp_descr_get) {
+ result = Py_TYPE(result)->tp_descr_get(result, NULL,
+ (PyObject *)type);
+ }
+ else {
+ Py_INCREF(result);
+ }
+ return result;
+}
+
+static PyObject *
+type___instancecheck__(PyObject *type, PyObject *inst)
+{
+ switch (_PyObject_RealIsInstance(inst, type)) {
+ case -1:
+ return NULL;
+ case 0:
+ Py_RETURN_FALSE;
+ default:
+ Py_RETURN_TRUE;
+ }
+}
+
+
+static PyObject *
+type___subclasscheck__(PyObject *type, PyObject *inst)
+{
+ switch (_PyObject_RealIsSubclass(inst, type)) {
+ case -1:
+ return NULL;
+ case 0:
+ Py_RETURN_FALSE;
+ default:
+ Py_RETURN_TRUE;
+ }
+}
+
+
+static PyGetSetDef type_getsets[] = {
+ {"__name__", (getter)type_name, (setter)type_set_name, NULL},
+ {"__bases__", (getter)type_get_bases, (setter)type_set_bases, NULL},
+ {"__module__", (getter)type_module, (setter)type_set_module, NULL},
+ {"__abstractmethods__", (getter)type_abstractmethods,
+ (setter)type_set_abstractmethods, NULL},
+ {"__dict__", (getter)type_dict, NULL, NULL},
+ {"__doc__", (getter)type_get_doc, NULL, NULL},
+ {0}
+};
+
+
+static PyObject*
+type_richcompare(PyObject *v, PyObject *w, int op)
+{
+ PyObject *result;
+ Py_uintptr_t vv, ww;
+ int c;
+
+ /* Make sure both arguments are types. */
+ if (!PyType_Check(v) || !PyType_Check(w) ||
+ /* If there is a __cmp__ method defined, let it be called instead
+ of our dumb function designed merely to warn. See bug
+ #7491. */
+ Py_TYPE(v)->tp_compare || Py_TYPE(w)->tp_compare) {
+ result = Py_NotImplemented;
+ goto out;
+ }
+
+ /* Py3K warning if comparison isn't == or != */
+ if (Py_Py3kWarningFlag && op != Py_EQ && op != Py_NE &&
+ PyErr_WarnEx(PyExc_DeprecationWarning,
+ "type inequality comparisons not supported "
+ "in 3.x", 1) < 0) {
+ return NULL;
+ }
+
+ /* Compare addresses */
+ vv = (Py_uintptr_t)v;
+ ww = (Py_uintptr_t)w;
+ switch (op) {
+ case Py_LT: c = vv < ww; break;
+ case Py_LE: c = vv <= ww; break;
+ case Py_EQ: c = vv == ww; break;
+ case Py_NE: c = vv != ww; break;
+ case Py_GT: c = vv > ww; break;
+ case Py_GE: c = vv >= ww; break;
+ default:
+ result = Py_NotImplemented;
+ goto out;
+ }
+ result = c ? Py_True : Py_False;
+
+ /* incref and return */
+ out:
+ Py_INCREF(result);
+ return result;
+}
+
+static PyObject *
+type_repr(PyTypeObject *type)
+{
+ PyObject *mod, *name, *rtn;
+ char *kind;
+
+ mod = type_module(type, NULL);
+ if (mod == NULL)
+ PyErr_Clear();
+ else if (!PyString_Check(mod)) {
+ Py_DECREF(mod);
+ mod = NULL;
+ }
+ name = type_name(type, NULL);
+ if (name == NULL)
+ return NULL;
+
+ if (type->tp_flags & Py_TPFLAGS_HEAPTYPE)
+ kind = "class";
+ else
+ kind = "type";
+
+ if (mod != NULL && strcmp(PyString_AS_STRING(mod), "__builtin__")) {
+ rtn = PyString_FromFormat("<%s '%s.%s'>",
+ kind,
+ PyString_AS_STRING(mod),
+ PyString_AS_STRING(name));
+ }
+ else
+ rtn = PyString_FromFormat("<%s '%s'>", kind, type->tp_name);
+
+ Py_XDECREF(mod);
+ Py_DECREF(name);
+ return rtn;
+}
+
+static PyObject *
+type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PyObject *obj;
+
+ if (type->tp_new == NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "cannot create '%.100s' instances",
+ type->tp_name);
+ return NULL;
+ }
+
+ obj = type->tp_new(type, args, kwds);
+ if (obj != NULL) {
+ /* Ugly exception: when the call was type(something),
+ don't call tp_init on the result. */
+ if (type == &PyType_Type &&
+ PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 1 &&
+ (kwds == NULL ||
+ (PyDict_Check(kwds) && PyDict_Size(kwds) == 0)))
+ return obj;
+ /* If the returned object is not an instance of type,
+ it won't be initialized. */
+ if (!PyType_IsSubtype(obj->ob_type, type))
+ return obj;
+ type = obj->ob_type;
+ if (PyType_HasFeature(type, Py_TPFLAGS_HAVE_CLASS) &&
+ type->tp_init != NULL &&
+ type->tp_init(obj, args, kwds) < 0) {
+ Py_DECREF(obj);
+ obj = NULL;
+ }
+ }
+ return obj;
+}
+
+PyObject *
+PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems)
+{
+ PyObject *obj;
+ const size_t size = _PyObject_VAR_SIZE(type, nitems+1);
+ /* note that we need to add one, for the sentinel */
+
+ if (PyType_IS_GC(type))
+ obj = _PyObject_GC_Malloc(size);
+ else
+ obj = (PyObject *)PyObject_MALLOC(size);
+
+ if (obj == NULL)
+ return PyErr_NoMemory();
+
+ memset(obj, '\0', size);
+
+ if (type->tp_flags & Py_TPFLAGS_HEAPTYPE)
+ Py_INCREF(type);
+
+ if (type->tp_itemsize == 0)
+ PyObject_INIT(obj, type);
+ else
+ (void) PyObject_INIT_VAR((PyVarObject *)obj, type, nitems);
+
+ if (PyType_IS_GC(type))
+ _PyObject_GC_TRACK(obj);
+ return obj;
+}
+
+PyObject *
+PyType_GenericNew(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ return type->tp_alloc(type, 0);
+}
+
+/* Helpers for subtyping */
+
+static int
+traverse_slots(PyTypeObject *type, PyObject *self, visitproc visit, void *arg)
+{
+ Py_ssize_t i, n;
+ PyMemberDef *mp;
+
+ n = Py_SIZE(type);
+ mp = PyHeapType_GET_MEMBERS((PyHeapTypeObject *)type);
+ for (i = 0; i < n; i++, mp++) {
+ if (mp->type == T_OBJECT_EX) {
+ char *addr = (char *)self + mp->offset;
+ PyObject *obj = *(PyObject **)addr;
+ if (obj != NULL) {
+ int err = visit(obj, arg);
+ if (err)
+ return err;
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+subtype_traverse(PyObject *self, visitproc visit, void *arg)
+{
+ PyTypeObject *type, *base;
+ traverseproc basetraverse;
+
+ /* Find the nearest base with a different tp_traverse,
+ and traverse slots while we're at it */
+ type = Py_TYPE(self);
+ base = type;
+ while ((basetraverse = base->tp_traverse) == subtype_traverse) {
+ if (Py_SIZE(base)) {
+ int err = traverse_slots(base, self, visit, arg);
+ if (err)
+ return err;
+ }
+ base = base->tp_base;
+ assert(base);
+ }
+
+ if (type->tp_dictoffset != base->tp_dictoffset) {
+ PyObject **dictptr = _PyObject_GetDictPtr(self);
+ if (dictptr && *dictptr)
+ Py_VISIT(*dictptr);
+ }
+
+ if (type->tp_flags & Py_TPFLAGS_HEAPTYPE)
+ /* For a heaptype, the instances count as references
+ to the type. Traverse the type so the collector
+ can find cycles involving this link. */
+ Py_VISIT(type);
+
+ if (basetraverse)
+ return basetraverse(self, visit, arg);
+ return 0;
+}
+
+static void
+clear_slots(PyTypeObject *type, PyObject *self)
+{
+ Py_ssize_t i, n;
+ PyMemberDef *mp;
+
+ n = Py_SIZE(type);
+ mp = PyHeapType_GET_MEMBERS((PyHeapTypeObject *)type);
+ for (i = 0; i < n; i++, mp++) {
+ if (mp->type == T_OBJECT_EX && !(mp->flags & READONLY)) {
+ char *addr = (char *)self + mp->offset;
+ PyObject *obj = *(PyObject **)addr;
+ if (obj != NULL) {
+ *(PyObject **)addr = NULL;
+ Py_DECREF(obj);
+ }
+ }
+ }
+}
+
+static int
+subtype_clear(PyObject *self)
+{
+ PyTypeObject *type, *base;
+ inquiry baseclear;
+
+ /* Find the nearest base with a different tp_clear
+ and clear slots while we're at it */
+ type = Py_TYPE(self);
+ base = type;
+ while ((baseclear = base->tp_clear) == subtype_clear) {
+ if (Py_SIZE(base))
+ clear_slots(base, self);
+ base = base->tp_base;
+ assert(base);
+ }
+
+ /* There's no need to clear the instance dict (if any);
+ the collector will call its tp_clear handler. */
+
+ if (baseclear)
+ return baseclear(self);
+ return 0;
+}
+
+static void
+subtype_dealloc(PyObject *self)
+{
+ PyTypeObject *type, *base;
+ destructor basedealloc;
+
+ /* Extract the type; we expect it to be a heap type */
+ type = Py_TYPE(self);
+ assert(type->tp_flags & Py_TPFLAGS_HEAPTYPE);
+
+ /* Test whether the type has GC exactly once */
+
+ if (!PyType_IS_GC(type)) {
+ /* It's really rare to find a dynamic type that doesn't have
+ GC; it can only happen when deriving from 'object' and not
+ adding any slots or instance variables. This allows
+ certain simplifications: there's no need to call
+ clear_slots(), or DECREF the dict, or clear weakrefs. */
+
+ /* Maybe call finalizer; exit early if resurrected */
+ if (type->tp_del) {
+ type->tp_del(self);
+ if (self->ob_refcnt > 0)
+ return;
+ }
+
+ /* Find the nearest base with a different tp_dealloc */
+ base = type;
+ while ((basedealloc = base->tp_dealloc) == subtype_dealloc) {
+ assert(Py_SIZE(base) == 0);
+ base = base->tp_base;
+ assert(base);
+ }
+
+ /* Extract the type again; tp_del may have changed it */
+ type = Py_TYPE(self);
+
+ /* Call the base tp_dealloc() */
+ assert(basedealloc);
+ basedealloc(self);
+
+ /* Can't reference self beyond this point */
+ Py_DECREF(type);
+
+ /* Done */
+ return;
+ }
+
+ /* We get here only if the type has GC */
+
+ /* UnTrack and re-Track around the trashcan macro, alas */
+ /* See explanation at end of function for full disclosure */
+ PyObject_GC_UnTrack(self);
+ ++_PyTrash_delete_nesting;
+ Py_TRASHCAN_SAFE_BEGIN(self);
+ --_PyTrash_delete_nesting;
+ /* DO NOT restore GC tracking at this point. weakref callbacks
+ * (if any, and whether directly here or indirectly in something we
+ * call) may trigger GC, and if self is tracked at that point, it
+ * will look like trash to GC and GC will try to delete self again.
+ */
+
+ /* Find the nearest base with a different tp_dealloc */
+ base = type;
+ while ((basedealloc = base->tp_dealloc) == subtype_dealloc) {
+ base = base->tp_base;
+ assert(base);
+ }
+
+ /* If we added a weaklist, we clear it. Do this *before* calling
+ the finalizer (__del__), clearing slots, or clearing the instance
+ dict. */
+
+ if (type->tp_weaklistoffset && !base->tp_weaklistoffset)
+ PyObject_ClearWeakRefs(self);
+
+ /* Maybe call finalizer; exit early if resurrected */
+ if (type->tp_del) {
+ _PyObject_GC_TRACK(self);
+ type->tp_del(self);
+ if (self->ob_refcnt > 0)
+ goto endlabel; /* resurrected */
+ else
+ _PyObject_GC_UNTRACK(self);
+ /* New weakrefs could be created during the finalizer call.
+ If this occurs, clear them out without calling their
+ finalizers since they might rely on part of the object
+ being finalized that has already been destroyed. */
+ if (type->tp_weaklistoffset && !base->tp_weaklistoffset) {
+ /* Modeled after GET_WEAKREFS_LISTPTR() */
+ PyWeakReference **list = (PyWeakReference **) \
+ PyObject_GET_WEAKREFS_LISTPTR(self);
+ while (*list)
+ _PyWeakref_ClearRef(*list);
+ }
+ }
+
+ /* Clear slots up to the nearest base with a different tp_dealloc */
+ base = type;
+ while (base->tp_dealloc == subtype_dealloc) {
+ if (Py_SIZE(base))
+ clear_slots(base, self);
+ base = base->tp_base;
+ assert(base);
+ }
+
+ /* If we added a dict, DECREF it */
+ if (type->tp_dictoffset && !base->tp_dictoffset) {
+ PyObject **dictptr = _PyObject_GetDictPtr(self);
+ if (dictptr != NULL) {
+ PyObject *dict = *dictptr;
+ if (dict != NULL) {
+ Py_DECREF(dict);
+ *dictptr = NULL;
+ }
+ }
+ }
+
+ /* Extract the type again; tp_del may have changed it */
+ type = Py_TYPE(self);
+
+ /* Call the base tp_dealloc(); first retrack self if
+ * basedealloc knows about gc.
+ */
+ if (PyType_IS_GC(base))
+ _PyObject_GC_TRACK(self);
+ assert(basedealloc);
+ basedealloc(self);
+
+ /* Can't reference self beyond this point */
+ Py_DECREF(type);
+
+ endlabel:
+ ++_PyTrash_delete_nesting;
+ Py_TRASHCAN_SAFE_END(self);
+ --_PyTrash_delete_nesting;
+
+ /* Explanation of the weirdness around the trashcan macros:
+
+ Q. What do the trashcan macros do?
+
+ A. Read the comment titled "Trashcan mechanism" in object.h.
+ For one, this explains why there must be a call to GC-untrack
+ before the trashcan begin macro. Without understanding the
+ trashcan code, the answers to the following questions don't make
+ sense.
+
+ Q. Why do we GC-untrack before the trashcan and then immediately
+ GC-track again afterward?
+
+ A. In the case that the base class is GC-aware, the base class
+ probably GC-untracks the object. If it does that using the
+ UNTRACK macro, this will crash when the object is already
+ untracked. Because we don't know what the base class does, the
+ only safe thing is to make sure the object is tracked when we
+ call the base class dealloc. But... The trashcan begin macro
+ requires that the object is *untracked* before it is called. So
+ the dance becomes:
+
+ GC untrack
+ trashcan begin
+ GC track
+
+ Q. Why did the last question say "immediately GC-track again"?
+ It's nowhere near immediately.
+
+ A. Because the code *used* to re-track immediately. Bad Idea.
+ self has a refcount of 0, and if gc ever gets its hands on it
+ (which can happen if any weakref callback gets invoked), it
+ looks like trash to gc too, and gc also tries to delete self
+ then. But we're already deleting self. Double deallocation is
+ a subtle disaster.
+
+ Q. Why the bizarre (net-zero) manipulation of
+ _PyTrash_delete_nesting around the trashcan macros?
+
+ A. Some base classes (e.g. list) also use the trashcan mechanism.
+ The following scenario used to be possible:
+
+ - suppose the trashcan level is one below the trashcan limit
+
+ - subtype_dealloc() is called
+
+ - the trashcan limit is not yet reached, so the trashcan level
+ is incremented and the code between trashcan begin and end is
+ executed
+
+ - this destroys much of the object's contents, including its
+ slots and __dict__
+
+ - basedealloc() is called; this is really list_dealloc(), or
+ some other type which also uses the trashcan macros
+
+ - the trashcan limit is now reached, so the object is put on the
+ trashcan's to-be-deleted-later list
+
+ - basedealloc() returns
+
+ - subtype_dealloc() decrefs the object's type
+
+ - subtype_dealloc() returns
+
+ - later, the trashcan code starts deleting the objects from its
+ to-be-deleted-later list
+
+ - subtype_dealloc() is called *AGAIN* for the same object
+
+ - at the very least (if the destroyed slots and __dict__ don't
+ cause problems) the object's type gets decref'ed a second
+ time, which is *BAD*!!!
+
+ The remedy is to make sure that if the code between trashcan
+ begin and end in subtype_dealloc() is called, the code between
+ trashcan begin and end in basedealloc() will also be called.
+ This is done by decrementing the level after passing into the
+ trashcan block, and incrementing it just before leaving the
+ block.
+
+ But now it's possible that a chain of objects consisting solely
+ of objects whose deallocator is subtype_dealloc() will defeat
+ the trashcan mechanism completely: the decremented level means
+ that the effective level never reaches the limit. Therefore, we
+ *increment* the level *before* entering the trashcan block, and
+ matchingly decrement it after leaving. This means the trashcan
+ code will trigger a little early, but that's no big deal.
+
+ Q. Are there any live examples of code in need of all this
+ complexity?
+
+ A. Yes. See SF bug 668433 for code that crashed (when Python was
+ compiled in debug mode) before the trashcan level manipulations
+ were added. For more discussion, see SF patches 581742, 575073
+ and bug 574207.
+ */
+}
+
+static PyTypeObject *solid_base(PyTypeObject *type);
+
+/* type test with subclassing support */
+
+int
+PyType_IsSubtype(PyTypeObject *a, PyTypeObject *b)
+{
+ PyObject *mro;
+
+ if (!(a->tp_flags & Py_TPFLAGS_HAVE_CLASS))
+ return b == a || b == &PyBaseObject_Type;
+
+ mro = a->tp_mro;
+ if (mro != NULL) {
+ /* Deal with multiple inheritance without recursion
+ by walking the MRO tuple */
+ Py_ssize_t i, n;
+ assert(PyTuple_Check(mro));
+ n = PyTuple_GET_SIZE(mro);
+ for (i = 0; i < n; i++) {
+ if (PyTuple_GET_ITEM(mro, i) == (PyObject *)b)
+ return 1;
+ }
+ return 0;
+ }
+ else {
+ /* a is not completely initilized yet; follow tp_base */
+ do {
+ if (a == b)
+ return 1;
+ a = a->tp_base;
+ } while (a != NULL);
+ return b == &PyBaseObject_Type;
+ }
+}
+
+/* Internal routines to do a method lookup in the type
+ without looking in the instance dictionary
+ (so we can't use PyObject_GetAttr) but still binding
+ it to the instance. The arguments are the object,
+ the method name as a C string, and the address of a
+ static variable used to cache the interned Python string.
+
+ Two variants:
+
+ - lookup_maybe() returns NULL without raising an exception
+ when the _PyType_Lookup() call fails;
+
+ - lookup_method() always raises an exception upon errors.
+
+ - _PyObject_LookupSpecial() exported for the benefit of other places.
+*/
+
+static PyObject *
+lookup_maybe(PyObject *self, char *attrstr, PyObject **attrobj)
+{
+ PyObject *res;
+
+ if (*attrobj == NULL) {
+ *attrobj = PyString_InternFromString(attrstr);
+ if (*attrobj == NULL)
+ return NULL;
+ }
+ res = _PyType_Lookup(Py_TYPE(self), *attrobj);
+ if (res != NULL) {
+ descrgetfunc f;
+ if ((f = Py_TYPE(res)->tp_descr_get) == NULL)
+ Py_INCREF(res);
+ else
+ res = f(res, self, (PyObject *)(Py_TYPE(self)));
+ }
+ return res;
+}
+
+static PyObject *
+lookup_method(PyObject *self, char *attrstr, PyObject **attrobj)
+{
+ PyObject *res = lookup_maybe(self, attrstr, attrobj);
+ if (res == NULL && !PyErr_Occurred())
+ PyErr_SetObject(PyExc_AttributeError, *attrobj);
+ return res;
+}
+
+PyObject *
+_PyObject_LookupSpecial(PyObject *self, char *attrstr, PyObject **attrobj)
+{
+ assert(!PyInstance_Check(self));
+ return lookup_maybe(self, attrstr, attrobj);
+}
+
+/* A variation of PyObject_CallMethod that uses lookup_method()
+ instead of PyObject_GetAttrString(). This uses the same convention
+ as lookup_method to cache the interned name string object. */
+
+static PyObject *
+call_method(PyObject *o, char *name, PyObject **nameobj, char *format, ...)
+{
+ va_list va;
+ PyObject *args, *func = 0, *retval;
+ va_start(va, format);
+
+ func = lookup_maybe(o, name, nameobj);
+ if (func == NULL) {
+ va_end(va);
+ if (!PyErr_Occurred())
+ PyErr_SetObject(PyExc_AttributeError, *nameobj);
+ return NULL;
+ }
+
+ if (format && *format)
+ args = Py_VaBuildValue(format, va);
+ else
+ args = PyTuple_New(0);
+
+ va_end(va);
+
+ if (args == NULL)
+ return NULL;
+
+ assert(PyTuple_Check(args));
+ retval = PyObject_Call(func, args, NULL);
+
+ Py_DECREF(args);
+ Py_DECREF(func);
+
+ return retval;
+}
+
+/* Clone of call_method() that returns NotImplemented when the lookup fails. */
+
+static PyObject *
+call_maybe(PyObject *o, char *name, PyObject **nameobj, char *format, ...)
+{
+ va_list va;
+ PyObject *args, *func = 0, *retval;
+ va_start(va, format);
+
+ func = lookup_maybe(o, name, nameobj);
+ if (func == NULL) {
+ va_end(va);
+ if (!PyErr_Occurred()) {
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+ return NULL;
+ }
+
+ if (format && *format)
+ args = Py_VaBuildValue(format, va);
+ else
+ args = PyTuple_New(0);
+
+ va_end(va);
+
+ if (args == NULL)
+ return NULL;
+
+ assert(PyTuple_Check(args));
+ retval = PyObject_Call(func, args, NULL);
+
+ Py_DECREF(args);
+ Py_DECREF(func);
+
+ return retval;
+}
+
+static int
+fill_classic_mro(PyObject *mro, PyObject *cls)
+{
+ PyObject *bases, *base;
+ Py_ssize_t i, n;
+
+ assert(PyList_Check(mro));
+ assert(PyClass_Check(cls));
+ i = PySequence_Contains(mro, cls);
+ if (i < 0)
+ return -1;
+ if (!i) {
+ if (PyList_Append(mro, cls) < 0)
+ return -1;
+ }
+ bases = ((PyClassObject *)cls)->cl_bases;
+ assert(bases && PyTuple_Check(bases));
+ n = PyTuple_GET_SIZE(bases);
+ for (i = 0; i < n; i++) {
+ base = PyTuple_GET_ITEM(bases, i);
+ if (fill_classic_mro(mro, base) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+static PyObject *
+classic_mro(PyObject *cls)
+{
+ PyObject *mro;
+
+ assert(PyClass_Check(cls));
+ mro = PyList_New(0);
+ if (mro != NULL) {
+ if (fill_classic_mro(mro, cls) == 0)
+ return mro;
+ Py_DECREF(mro);
+ }
+ return NULL;
+}
+
+/*
+ Method resolution order algorithm C3 described in
+ "A Monotonic Superclass Linearization for Dylan",
+ by Kim Barrett, Bob Cassel, Paul Haahr,
+ David A. Moon, Keith Playford, and P. Tucker Withington.
+ (OOPSLA 1996)
+
+ Some notes about the rules implied by C3:
+
+ No duplicate bases.
+ It isn't legal to repeat a class in a list of base classes.
+
+ The next three properties are the 3 constraints in "C3".
+
+ Local precendece order.
+ If A precedes B in C's MRO, then A will precede B in the MRO of all
+ subclasses of C.
+
+ Monotonicity.
+ The MRO of a class must be an extension without reordering of the
+ MRO of each of its superclasses.
+
+ Extended Precedence Graph (EPG).
+ Linearization is consistent if there is a path in the EPG from
+ each class to all its successors in the linearization. See
+ the paper for definition of EPG.
+ */
+
+static int
+tail_contains(PyObject *list, int whence, PyObject *o) {
+ Py_ssize_t j, size;
+ size = PyList_GET_SIZE(list);
+
+ for (j = whence+1; j < size; j++) {
+ if (PyList_GET_ITEM(list, j) == o)
+ return 1;
+ }
+ return 0;
+}
+
+static PyObject *
+class_name(PyObject *cls)
+{
+ PyObject *name = PyObject_GetAttrString(cls, "__name__");
+ if (name == NULL) {
+ PyErr_Clear();
+ Py_XDECREF(name);
+ name = PyObject_Repr(cls);
+ }
+ if (name == NULL)
+ return NULL;
+ if (!PyString_Check(name)) {
+ Py_DECREF(name);
+ return NULL;
+ }
+ return name;
+}
+
+static int
+check_duplicates(PyObject *list)
+{
+ Py_ssize_t i, j, n;
+ /* Let's use a quadratic time algorithm,
+ assuming that the bases lists is short.
+ */
+ n = PyList_GET_SIZE(list);
+ for (i = 0; i < n; i++) {
+ PyObject *o = PyList_GET_ITEM(list, i);
+ for (j = i + 1; j < n; j++) {
+ if (PyList_GET_ITEM(list, j) == o) {
+ o = class_name(o);
+ PyErr_Format(PyExc_TypeError,
+ "duplicate base class %s",
+ o ? PyString_AS_STRING(o) : "?");
+ Py_XDECREF(o);
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+/* Raise a TypeError for an MRO order disagreement.
+
+ It's hard to produce a good error message. In the absence of better
+ insight into error reporting, report the classes that were candidates
+ to be put next into the MRO. There is some conflict between the
+ order in which they should be put in the MRO, but it's hard to
+ diagnose what constraint can't be satisfied.
+*/
+
+static void
+set_mro_error(PyObject *to_merge, int *remain)
+{
+ Py_ssize_t i, n, off, to_merge_size;
+ char buf[1000];
+ PyObject *k, *v;
+ PyObject *set = PyDict_New();
+ if (!set) return;
+
+ to_merge_size = PyList_GET_SIZE(to_merge);
+ for (i = 0; i < to_merge_size; i++) {
+ PyObject *L = PyList_GET_ITEM(to_merge, i);
+ if (remain[i] < PyList_GET_SIZE(L)) {
+ PyObject *c = PyList_GET_ITEM(L, remain[i]);
+ if (PyDict_SetItem(set, c, Py_None) < 0) {
+ Py_DECREF(set);
+ return;
+ }
+ }
+ }
+ n = PyDict_Size(set);
+
+ off = PyOS_snprintf(buf, sizeof(buf), "Cannot create a \
+consistent method resolution\norder (MRO) for bases");
+ i = 0;
+ while (PyDict_Next(set, &i, &k, &v) && (size_t)off < sizeof(buf)) {
+ PyObject *name = class_name(k);
+ off += PyOS_snprintf(buf + off, sizeof(buf) - off, " %s",
+ name ? PyString_AS_STRING(name) : "?");
+ Py_XDECREF(name);
+ if (--n && (size_t)(off+1) < sizeof(buf)) {
+ buf[off++] = ',';
+ buf[off] = '\0';
+ }
+ }
+ PyErr_SetString(PyExc_TypeError, buf);
+ Py_DECREF(set);
+}
+
+static int
+pmerge(PyObject *acc, PyObject* to_merge) {
+ Py_ssize_t i, j, to_merge_size, empty_cnt;
+ int *remain;
+ int ok;
+
+ to_merge_size = PyList_GET_SIZE(to_merge);
+
+ /* remain stores an index into each sublist of to_merge.
+ remain[i] is the index of the next base in to_merge[i]
+ that is not included in acc.
+ */
+ remain = (int *)PyMem_MALLOC(SIZEOF_INT*to_merge_size);
+ if (remain == NULL)
+ return -1;
+ for (i = 0; i < to_merge_size; i++)
+ remain[i] = 0;
+
+ again:
+ empty_cnt = 0;
+ for (i = 0; i < to_merge_size; i++) {
+ PyObject *candidate;
+
+ PyObject *cur_list = PyList_GET_ITEM(to_merge, i);
+
+ if (remain[i] >= PyList_GET_SIZE(cur_list)) {
+ empty_cnt++;
+ continue;
+ }
+
+ /* Choose next candidate for MRO.
+
+ The input sequences alone can determine the choice.
+ If not, choose the class which appears in the MRO
+ of the earliest direct superclass of the new class.
+ */
+
+ candidate = PyList_GET_ITEM(cur_list, remain[i]);
+ for (j = 0; j < to_merge_size; j++) {
+ PyObject *j_lst = PyList_GET_ITEM(to_merge, j);
+ if (tail_contains(j_lst, remain[j], candidate)) {
+ goto skip; /* continue outer loop */
+ }
+ }
+ ok = PyList_Append(acc, candidate);
+ if (ok < 0) {
+ PyMem_Free(remain);
+ return -1;
+ }
+ for (j = 0; j < to_merge_size; j++) {
+ PyObject *j_lst = PyList_GET_ITEM(to_merge, j);
+ if (remain[j] < PyList_GET_SIZE(j_lst) &&
+ PyList_GET_ITEM(j_lst, remain[j]) == candidate) {
+ remain[j]++;
+ }
+ }
+ goto again;
+ skip: ;
+ }
+
+ if (empty_cnt == to_merge_size) {
+ PyMem_FREE(remain);
+ return 0;
+ }
+ set_mro_error(to_merge, remain);
+ PyMem_FREE(remain);
+ return -1;
+}
+
+static PyObject *
+mro_implementation(PyTypeObject *type)
+{
+ Py_ssize_t i, n;
+ int ok;
+ PyObject *bases, *result;
+ PyObject *to_merge, *bases_aslist;
+
+ if (type->tp_dict == NULL) {
+ if (PyType_Ready(type) < 0)
+ return NULL;
+ }
+
+ /* Find a superclass linearization that honors the constraints
+ of the explicit lists of bases and the constraints implied by
+ each base class.
+
+ to_merge is a list of lists, where each list is a superclass
+ linearization implied by a base class. The last element of
+ to_merge is the declared list of bases.
+ */
+
+ bases = type->tp_bases;
+ n = PyTuple_GET_SIZE(bases);
+
+ to_merge = PyList_New(n+1);
+ if (to_merge == NULL)
+ return NULL;
+
+ for (i = 0; i < n; i++) {
+ PyObject *base = PyTuple_GET_ITEM(bases, i);
+ PyObject *parentMRO;
+ if (PyType_Check(base))
+ parentMRO = PySequence_List(
+ ((PyTypeObject*)base)->tp_mro);
+ else
+ parentMRO = classic_mro(base);
+ if (parentMRO == NULL) {
+ Py_DECREF(to_merge);
+ return NULL;
+ }
+
+ PyList_SET_ITEM(to_merge, i, parentMRO);
+ }
+
+ bases_aslist = PySequence_List(bases);
+ if (bases_aslist == NULL) {
+ Py_DECREF(to_merge);
+ return NULL;
+ }
+ /* This is just a basic sanity check. */
+ if (check_duplicates(bases_aslist) < 0) {
+ Py_DECREF(to_merge);
+ Py_DECREF(bases_aslist);
+ return NULL;
+ }
+ PyList_SET_ITEM(to_merge, n, bases_aslist);
+
+ result = Py_BuildValue("[O]", (PyObject *)type);
+ if (result == NULL) {
+ Py_DECREF(to_merge);
+ return NULL;
+ }
+
+ ok = pmerge(result, to_merge);
+ Py_DECREF(to_merge);
+ if (ok < 0) {
+ Py_DECREF(result);
+ return NULL;
+ }
+
+ return result;
+}
+
+static PyObject *
+mro_external(PyObject *self)
+{
+ PyTypeObject *type = (PyTypeObject *)self;
+
+ return mro_implementation(type);
+}
+
+static int
+mro_internal(PyTypeObject *type)
+{
+ PyObject *mro, *result, *tuple;
+ int checkit = 0;
+
+ if (Py_TYPE(type) == &PyType_Type) {
+ result = mro_implementation(type);
+ }
+ else {
+ static PyObject *mro_str;
+ checkit = 1;
+ mro = lookup_method((PyObject *)type, "mro", &mro_str);
+ if (mro == NULL)
+ return -1;
+ result = PyObject_CallObject(mro, NULL);
+ Py_DECREF(mro);
+ }
+ if (result == NULL)
+ return -1;
+ tuple = PySequence_Tuple(result);
+ Py_DECREF(result);
+ if (tuple == NULL)
+ return -1;
+ if (checkit) {
+ Py_ssize_t i, len;
+ PyObject *cls;
+ PyTypeObject *solid;
+
+ solid = solid_base(type);
+
+ len = PyTuple_GET_SIZE(tuple);
+
+ for (i = 0; i < len; i++) {
+ PyTypeObject *t;
+ cls = PyTuple_GET_ITEM(tuple, i);
+ if (PyClass_Check(cls))
+ continue;
+ else if (!PyType_Check(cls)) {
+ PyErr_Format(PyExc_TypeError,
+ "mro() returned a non-class ('%.500s')",
+ Py_TYPE(cls)->tp_name);
+ Py_DECREF(tuple);
+ return -1;
+ }
+ t = (PyTypeObject*)cls;
+ if (!PyType_IsSubtype(solid, solid_base(t))) {
+ PyErr_Format(PyExc_TypeError,
+ "mro() returned base with unsuitable layout ('%.500s')",
+ t->tp_name);
+ Py_DECREF(tuple);
+ return -1;
+ }
+ }
+ }
+ type->tp_mro = tuple;
+
+ type_mro_modified(type, type->tp_mro);
+ /* corner case: the old-style super class might have been hidden
+ from the custom MRO */
+ type_mro_modified(type, type->tp_bases);
+
+ PyType_Modified(type);
+
+ return 0;
+}
+
+
+/* Calculate the best base amongst multiple base classes.
+ This is the first one that's on the path to the "solid base". */
+
+static PyTypeObject *
+best_base(PyObject *bases)
+{
+ Py_ssize_t i, n;
+ PyTypeObject *base, *winner, *candidate, *base_i;
+ PyObject *base_proto;
+
+ assert(PyTuple_Check(bases));
+ n = PyTuple_GET_SIZE(bases);
+ assert(n > 0);
+ base = NULL;
+ winner = NULL;
+ for (i = 0; i < n; i++) {
+ base_proto = PyTuple_GET_ITEM(bases, i);
+ if (PyClass_Check(base_proto))
+ continue;
+ if (!PyType_Check(base_proto)) {
+ PyErr_SetString(
+ PyExc_TypeError,
+ "bases must be types");
+ return NULL;
+ }
+ base_i = (PyTypeObject *)base_proto;
+ if (base_i->tp_dict == NULL) {
+ if (PyType_Ready(base_i) < 0)
+ return NULL;
+ }
+ candidate = solid_base(base_i);
+ if (winner == NULL) {
+ winner = candidate;
+ base = base_i;
+ }
+ else if (PyType_IsSubtype(winner, candidate))
+ ;
+ else if (PyType_IsSubtype(candidate, winner)) {
+ winner = candidate;
+ base = base_i;
+ }
+ else {
+ PyErr_SetString(
+ PyExc_TypeError,
+ "multiple bases have "
+ "instance lay-out conflict");
+ return NULL;
+ }
+ }
+ if (base == NULL)
+ PyErr_SetString(PyExc_TypeError,
+ "a new-style class can't have only classic bases");
+ return base;
+}
+
+static int
+extra_ivars(PyTypeObject *type, PyTypeObject *base)
+{
+ size_t t_size = type->tp_basicsize;
+ size_t b_size = base->tp_basicsize;
+
+ assert(t_size >= b_size); /* Else type smaller than base! */
+ if (type->tp_itemsize || base->tp_itemsize) {
+ /* If itemsize is involved, stricter rules */
+ return t_size != b_size ||
+ type->tp_itemsize != base->tp_itemsize;
+ }
+ if (type->tp_weaklistoffset && base->tp_weaklistoffset == 0 &&
+ type->tp_weaklistoffset + sizeof(PyObject *) == t_size &&
+ type->tp_flags & Py_TPFLAGS_HEAPTYPE)
+ t_size -= sizeof(PyObject *);
+ if (type->tp_dictoffset && base->tp_dictoffset == 0 &&
+ type->tp_dictoffset + sizeof(PyObject *) == t_size &&
+ type->tp_flags & Py_TPFLAGS_HEAPTYPE)
+ t_size -= sizeof(PyObject *);
+
+ return t_size != b_size;
+}
+
+static PyTypeObject *
+solid_base(PyTypeObject *type)
+{
+ PyTypeObject *base;
+
+ if (type->tp_base)
+ base = solid_base(type->tp_base);
+ else
+ base = &PyBaseObject_Type;
+ if (extra_ivars(type, base))
+ return type;
+ else
+ return base;
+}
+
+static void object_dealloc(PyObject *);
+static int object_init(PyObject *, PyObject *, PyObject *);
+static int update_slot(PyTypeObject *, PyObject *);
+static void fixup_slot_dispatchers(PyTypeObject *);
+
+/*
+ * Helpers for __dict__ descriptor. We don't want to expose the dicts
+ * inherited from various builtin types. The builtin base usually provides
+ * its own __dict__ descriptor, so we use that when we can.
+ */
+static PyTypeObject *
+get_builtin_base_with_dict(PyTypeObject *type)
+{
+ while (type->tp_base != NULL) {
+ if (type->tp_dictoffset != 0 &&
+ !(type->tp_flags & Py_TPFLAGS_HEAPTYPE))
+ return type;
+ type = type->tp_base;
+ }
+ return NULL;
+}
+
+static PyObject *
+get_dict_descriptor(PyTypeObject *type)
+{
+ static PyObject *dict_str;
+ PyObject *descr;
+
+ if (dict_str == NULL) {
+ dict_str = PyString_InternFromString("__dict__");
+ if (dict_str == NULL)
+ return NULL;
+ }
+ descr = _PyType_Lookup(type, dict_str);
+ if (descr == NULL || !PyDescr_IsData(descr))
+ return NULL;
+
+ return descr;
+}
+
+static void
+raise_dict_descr_error(PyObject *obj)
+{
+ PyErr_Format(PyExc_TypeError,
+ "this __dict__ descriptor does not support "
+ "'%.200s' objects", obj->ob_type->tp_name);
+}
+
+static PyObject *
+subtype_dict(PyObject *obj, void *context)
+{
+ PyObject **dictptr;
+ PyObject *dict;
+ PyTypeObject *base;
+
+ base = get_builtin_base_with_dict(obj->ob_type);
+ if (base != NULL) {
+ descrgetfunc func;
+ PyObject *descr = get_dict_descriptor(base);
+ if (descr == NULL) {
+ raise_dict_descr_error(obj);
+ return NULL;
+ }
+ func = descr->ob_type->tp_descr_get;
+ if (func == NULL) {
+ raise_dict_descr_error(obj);
+ return NULL;
+ }
+ return func(descr, obj, (PyObject *)(obj->ob_type));
+ }
+
+ dictptr = _PyObject_GetDictPtr(obj);
+ if (dictptr == NULL) {
+ PyErr_SetString(PyExc_AttributeError,
+ "This object has no __dict__");
+ return NULL;
+ }
+ dict = *dictptr;
+ if (dict == NULL)
+ *dictptr = dict = PyDict_New();
+ Py_XINCREF(dict);
+ return dict;
+}
+
+static int
+subtype_setdict(PyObject *obj, PyObject *value, void *context)
+{
+ PyObject **dictptr;
+ PyObject *dict;
+ PyTypeObject *base;
+
+ base = get_builtin_base_with_dict(obj->ob_type);
+ if (base != NULL) {
+ descrsetfunc func;
+ PyObject *descr = get_dict_descriptor(base);
+ if (descr == NULL) {
+ raise_dict_descr_error(obj);
+ return -1;
+ }
+ func = descr->ob_type->tp_descr_set;
+ if (func == NULL) {
+ raise_dict_descr_error(obj);
+ return -1;
+ }
+ return func(descr, obj, value);
+ }
+
+ dictptr = _PyObject_GetDictPtr(obj);
+ if (dictptr == NULL) {
+ PyErr_SetString(PyExc_AttributeError,
+ "This object has no __dict__");
+ return -1;
+ }
+ if (value != NULL && !PyDict_Check(value)) {
+ PyErr_Format(PyExc_TypeError,
+ "__dict__ must be set to a dictionary, "
+ "not a '%.200s'", Py_TYPE(value)->tp_name);
+ return -1;
+ }
+ dict = *dictptr;
+ Py_XINCREF(value);
+ *dictptr = value;
+ Py_XDECREF(dict);
+ return 0;
+}
+
+static PyObject *
+subtype_getweakref(PyObject *obj, void *context)
+{
+ PyObject **weaklistptr;
+ PyObject *result;
+
+ if (Py_TYPE(obj)->tp_weaklistoffset == 0) {
+ PyErr_SetString(PyExc_AttributeError,
+ "This object has no __weakref__");
+ return NULL;
+ }
+ assert(Py_TYPE(obj)->tp_weaklistoffset > 0);
+ assert(Py_TYPE(obj)->tp_weaklistoffset + sizeof(PyObject *) <=
+ (size_t)(Py_TYPE(obj)->tp_basicsize));
+ weaklistptr = (PyObject **)
+ ((char *)obj + Py_TYPE(obj)->tp_weaklistoffset);
+ if (*weaklistptr == NULL)
+ result = Py_None;
+ else
+ result = *weaklistptr;
+ Py_INCREF(result);
+ return result;
+}
+
+/* Three variants on the subtype_getsets list. */
+
+static PyGetSetDef subtype_getsets_full[] = {
+ {"__dict__", subtype_dict, subtype_setdict,
+ PyDoc_STR("dictionary for instance variables (if defined)")},
+ {"__weakref__", subtype_getweakref, NULL,
+ PyDoc_STR("list of weak references to the object (if defined)")},
+ {0}
+};
+
+static PyGetSetDef subtype_getsets_dict_only[] = {
+ {"__dict__", subtype_dict, subtype_setdict,
+ PyDoc_STR("dictionary for instance variables (if defined)")},
+ {0}
+};
+
+static PyGetSetDef subtype_getsets_weakref_only[] = {
+ {"__weakref__", subtype_getweakref, NULL,
+ PyDoc_STR("list of weak references to the object (if defined)")},
+ {0}
+};
+
+static int
+valid_identifier(PyObject *s)
+{
+ unsigned char *p;
+ Py_ssize_t i, n;
+
+ if (!PyString_Check(s)) {
+ PyErr_Format(PyExc_TypeError,
+ "__slots__ items must be strings, not '%.200s'",
+ Py_TYPE(s)->tp_name);
+ return 0;
+ }
+ p = (unsigned char *) PyString_AS_STRING(s);
+ n = PyString_GET_SIZE(s);
+ /* We must reject an empty name. As a hack, we bump the
+ length to 1 so that the loop will balk on the trailing \0. */
+ if (n == 0)
+ n = 1;
+ for (i = 0; i < n; i++, p++) {
+ if (!(i == 0 ? isalpha(*p) : isalnum(*p)) && *p != '_') {
+ PyErr_SetString(PyExc_TypeError,
+ "__slots__ must be identifiers");
+ return 0;
+ }
+ }
+ return 1;
+}
+
+#ifdef Py_USING_UNICODE
+/* Replace Unicode objects in slots. */
+
+static PyObject *
+_unicode_to_string(PyObject *slots, Py_ssize_t nslots)
+{
+ PyObject *tmp = NULL;
+ PyObject *slot_name, *new_name;
+ Py_ssize_t i;
+
+ for (i = 0; i < nslots; i++) {
+ if (PyUnicode_Check(slot_name = PyTuple_GET_ITEM(slots, i))) {
+ if (tmp == NULL) {
+ tmp = PySequence_List(slots);
+ if (tmp == NULL)
+ return NULL;
+ }
+ new_name = _PyUnicode_AsDefaultEncodedString(slot_name,
+ NULL);
+ if (new_name == NULL) {
+ Py_DECREF(tmp);
+ return NULL;
+ }
+ Py_INCREF(new_name);
+ PyList_SET_ITEM(tmp, i, new_name);
+ Py_DECREF(slot_name);
+ }
+ }
+ if (tmp != NULL) {
+ slots = PyList_AsTuple(tmp);
+ Py_DECREF(tmp);
+ }
+ return slots;
+}
+#endif
+
+/* Forward */
+static int
+object_init(PyObject *self, PyObject *args, PyObject *kwds);
+
+static int
+type_init(PyObject *cls, PyObject *args, PyObject *kwds)
+{
+ int res;
+
+ assert(args != NULL && PyTuple_Check(args));
+ assert(kwds == NULL || PyDict_Check(kwds));
+
+ if (kwds != NULL && PyDict_Check(kwds) && PyDict_Size(kwds) != 0) {
+ PyErr_SetString(PyExc_TypeError,
+ "type.__init__() takes no keyword arguments");
+ return -1;
+ }
+
+ if (args != NULL && PyTuple_Check(args) &&
+ (PyTuple_GET_SIZE(args) != 1 && PyTuple_GET_SIZE(args) != 3)) {
+ PyErr_SetString(PyExc_TypeError,
+ "type.__init__() takes 1 or 3 arguments");
+ return -1;
+ }
+
+ /* Call object.__init__(self) now. */
+ /* XXX Could call super(type, cls).__init__() but what's the point? */
+ args = PyTuple_GetSlice(args, 0, 0);
+ res = object_init(cls, args, NULL);
+ Py_DECREF(args);
+ return res;
+}
+
+static PyObject *
+type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
+{
+ PyObject *name, *bases, *dict;
+ static char *kwlist[] = {"name", "bases", "dict", 0};
+ PyObject *slots, *tmp, *newslots;
+ PyTypeObject *type, *base, *tmptype, *winner;
+ PyHeapTypeObject *et;
+ PyMemberDef *mp;
+ Py_ssize_t i, nbases, nslots, slotoffset, add_dict, add_weak;
+ int j, may_add_dict, may_add_weak;
+
+ assert(args != NULL && PyTuple_Check(args));
+ assert(kwds == NULL || PyDict_Check(kwds));
+
+ /* Special case: type(x) should return x->ob_type */
+ {
+ const Py_ssize_t nargs = PyTuple_GET_SIZE(args);
+ const Py_ssize_t nkwds = kwds == NULL ? 0 : PyDict_Size(kwds);
+
+ if (PyType_CheckExact(metatype) && nargs == 1 && nkwds == 0) {
+ PyObject *x = PyTuple_GET_ITEM(args, 0);
+ Py_INCREF(Py_TYPE(x));
+ return (PyObject *) Py_TYPE(x);
+ }
+
+ /* SF bug 475327 -- if that didn't trigger, we need 3
+ arguments. but PyArg_ParseTupleAndKeywords below may give
+ a msg saying type() needs exactly 3. */
+ if (nargs + nkwds != 3) {
+ PyErr_SetString(PyExc_TypeError,
+ "type() takes 1 or 3 arguments");
+ return NULL;
+ }
+ }
+
+ /* Check arguments: (name, bases, dict) */
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "SO!O!:type", kwlist,
+ &name,
+ &PyTuple_Type, &bases,
+ &PyDict_Type, &dict))
+ return NULL;
+
+ /* Determine the proper metatype to deal with this,
+ and check for metatype conflicts while we're at it.
+ Note that if some other metatype wins to contract,
+ it's possible that its instances are not types. */
+ nbases = PyTuple_GET_SIZE(bases);
+ winner = metatype;
+ for (i = 0; i < nbases; i++) {
+ tmp = PyTuple_GET_ITEM(bases, i);
+ tmptype = tmp->ob_type;
+ if (tmptype == &PyClass_Type)
+ continue; /* Special case classic classes */
+ if (PyType_IsSubtype(winner, tmptype))
+ continue;
+ if (PyType_IsSubtype(tmptype, winner)) {
+ winner = tmptype;
+ continue;
+ }
+ PyErr_SetString(PyExc_TypeError,
+ "metaclass conflict: "
+ "the metaclass of a derived class "
+ "must be a (non-strict) subclass "
+ "of the metaclasses of all its bases");
+ return NULL;
+ }
+ if (winner != metatype) {
+ if (winner->tp_new != type_new) /* Pass it to the winner */
+ return winner->tp_new(winner, args, kwds);
+ metatype = winner;
+ }
+
+ /* Adjust for empty tuple bases */
+ if (nbases == 0) {
+ bases = PyTuple_Pack(1, &PyBaseObject_Type);
+ if (bases == NULL)
+ return NULL;
+ nbases = 1;
+ }
+ else
+ Py_INCREF(bases);
+
+ /* XXX From here until type is allocated, "return NULL" leaks bases! */
+
+ /* Calculate best base, and check that all bases are type objects */
+ base = best_base(bases);
+ if (base == NULL) {
+ Py_DECREF(bases);
+ return NULL;
+ }
+ if (!PyType_HasFeature(base, Py_TPFLAGS_BASETYPE)) {
+ PyErr_Format(PyExc_TypeError,
+ "type '%.100s' is not an acceptable base type",
+ base->tp_name);
+ Py_DECREF(bases);
+ return NULL;
+ }
+
+ /* Check for a __slots__ sequence variable in dict, and count it */
+ slots = PyDict_GetItemString(dict, "__slots__");
+ nslots = 0;
+ add_dict = 0;
+ add_weak = 0;
+ may_add_dict = base->tp_dictoffset == 0;
+ may_add_weak = base->tp_weaklistoffset == 0 && base->tp_itemsize == 0;
+ if (slots == NULL) {
+ if (may_add_dict) {
+ add_dict++;
+ }
+ if (may_add_weak) {
+ add_weak++;
+ }
+ }
+ else {
+ /* Have slots */
+
+ /* Make it into a tuple */
+ if (PyString_Check(slots) || PyUnicode_Check(slots))
+ slots = PyTuple_Pack(1, slots);
+ else
+ slots = PySequence_Tuple(slots);
+ if (slots == NULL) {
+ Py_DECREF(bases);
+ return NULL;
+ }
+ assert(PyTuple_Check(slots));
+
+ /* Are slots allowed? */
+ nslots = PyTuple_GET_SIZE(slots);
+ if (nslots > 0 && base->tp_itemsize != 0) {
+ PyErr_Format(PyExc_TypeError,
+ "nonempty __slots__ "
+ "not supported for subtype of '%s'",
+ base->tp_name);
+ bad_slots:
+ Py_DECREF(bases);
+ Py_DECREF(slots);
+ return NULL;
+ }
+
+#ifdef Py_USING_UNICODE
+ tmp = _unicode_to_string(slots, nslots);
+ if (tmp == NULL)
+ goto bad_slots;
+ if (tmp != slots) {
+ Py_DECREF(slots);
+ slots = tmp;
+ }
+#endif
+ /* Check for valid slot names and two special cases */
+ for (i = 0; i < nslots; i++) {
+ PyObject *tmp = PyTuple_GET_ITEM(slots, i);
+ char *s;
+ if (!valid_identifier(tmp))
+ goto bad_slots;
+ assert(PyString_Check(tmp));
+ s = PyString_AS_STRING(tmp);
+ if (strcmp(s, "__dict__") == 0) {
+ if (!may_add_dict || add_dict) {
+ PyErr_SetString(PyExc_TypeError,
+ "__dict__ slot disallowed: "
+ "we already got one");
+ goto bad_slots;
+ }
+ add_dict++;
+ }
+ if (strcmp(s, "__weakref__") == 0) {
+ if (!may_add_weak || add_weak) {
+ PyErr_SetString(PyExc_TypeError,
+ "__weakref__ slot disallowed: "
+ "either we already got one, "
+ "or __itemsize__ != 0");
+ goto bad_slots;
+ }
+ add_weak++;
+ }
+ }
+
+ /* Copy slots into a list, mangle names and sort them.
+ Sorted names are needed for __class__ assignment.
+ Convert them back to tuple at the end.
+ */
+ newslots = PyList_New(nslots - add_dict - add_weak);
+ if (newslots == NULL)
+ goto bad_slots;
+ for (i = j = 0; i < nslots; i++) {
+ char *s;
+ tmp = PyTuple_GET_ITEM(slots, i);
+ s = PyString_AS_STRING(tmp);
+ if ((add_dict && strcmp(s, "__dict__") == 0) ||
+ (add_weak && strcmp(s, "__weakref__") == 0))
+ continue;
+ tmp =_Py_Mangle(name, tmp);
+ if (!tmp)
+ goto bad_slots;
+ PyList_SET_ITEM(newslots, j, tmp);
+ j++;
+ }
+ assert(j == nslots - add_dict - add_weak);
+ nslots = j;
+ Py_DECREF(slots);
+ if (PyList_Sort(newslots) == -1) {
+ Py_DECREF(bases);
+ Py_DECREF(newslots);
+ return NULL;
+ }
+ slots = PyList_AsTuple(newslots);
+ Py_DECREF(newslots);
+ if (slots == NULL) {
+ Py_DECREF(bases);
+ return NULL;
+ }
+
+ /* Secondary bases may provide weakrefs or dict */
+ if (nbases > 1 &&
+ ((may_add_dict && !add_dict) ||
+ (may_add_weak && !add_weak))) {
+ for (i = 0; i < nbases; i++) {
+ tmp = PyTuple_GET_ITEM(bases, i);
+ if (tmp == (PyObject *)base)
+ continue; /* Skip primary base */
+ if (PyClass_Check(tmp)) {
+ /* Classic base class provides both */
+ if (may_add_dict && !add_dict)
+ add_dict++;
+ if (may_add_weak && !add_weak)
+ add_weak++;
+ break;
+ }
+ assert(PyType_Check(tmp));
+ tmptype = (PyTypeObject *)tmp;
+ if (may_add_dict && !add_dict &&
+ tmptype->tp_dictoffset != 0)
+ add_dict++;
+ if (may_add_weak && !add_weak &&
+ tmptype->tp_weaklistoffset != 0)
+ add_weak++;
+ if (may_add_dict && !add_dict)
+ continue;
+ if (may_add_weak && !add_weak)
+ continue;
+ /* Nothing more to check */
+ break;
+ }
+ }
+ }
+
+ /* XXX From here until type is safely allocated,
+ "return NULL" may leak slots! */
+
+ /* Allocate the type object */
+ type = (PyTypeObject *)metatype->tp_alloc(metatype, nslots);
+ if (type == NULL) {
+ Py_XDECREF(slots);
+ Py_DECREF(bases);
+ return NULL;
+ }
+
+ /* Keep name and slots alive in the extended type object */
+ et = (PyHeapTypeObject *)type;
+ Py_INCREF(name);
+ et->ht_name = name;
+ et->ht_slots = slots;
+
+ /* Initialize tp_flags */
+ type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE |
+ Py_TPFLAGS_BASETYPE;
+ if (base->tp_flags & Py_TPFLAGS_HAVE_GC)
+ type->tp_flags |= Py_TPFLAGS_HAVE_GC;
+ if (base->tp_flags & Py_TPFLAGS_HAVE_NEWBUFFER)
+ type->tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER;
+
+ /* It's a new-style number unless it specifically inherits any
+ old-style numeric behavior */
+ if ((base->tp_flags & Py_TPFLAGS_CHECKTYPES) ||
+ (base->tp_as_number == NULL))
+ type->tp_flags |= Py_TPFLAGS_CHECKTYPES;
+
+ /* Initialize essential fields */
+ type->tp_as_number = &et->as_number;
+ type->tp_as_sequence = &et->as_sequence;
+ type->tp_as_mapping = &et->as_mapping;
+ type->tp_as_buffer = &et->as_buffer;
+ type->tp_name = PyString_AS_STRING(name);
+
+ /* Set tp_base and tp_bases */
+ type->tp_bases = bases;
+ Py_INCREF(base);
+ type->tp_base = base;
+
+ /* Initialize tp_dict from passed-in dict */
+ type->tp_dict = dict = PyDict_Copy(dict);
+ if (dict == NULL) {
+ Py_DECREF(type);
+ return NULL;
+ }
+
+ /* Set __module__ in the dict */
+ if (PyDict_GetItemString(dict, "__module__") == NULL) {
+ tmp = PyEval_GetGlobals();
+ if (tmp != NULL) {
+ tmp = PyDict_GetItemString(tmp, "__name__");
+ if (tmp != NULL) {
+ if (PyDict_SetItemString(dict, "__module__",
+ tmp) < 0)
+ return NULL;
+ }
+ }
+ }
+
+ /* Set tp_doc to a copy of dict['__doc__'], if the latter is there
+ and is a string. The __doc__ accessor will first look for tp_doc;
+ if that fails, it will still look into __dict__.
+ */
+ {
+ PyObject *doc = PyDict_GetItemString(dict, "__doc__");
+ if (doc != NULL && PyString_Check(doc)) {
+ const size_t n = (size_t)PyString_GET_SIZE(doc);
+ char *tp_doc = (char *)PyObject_MALLOC(n+1);
+ if (tp_doc == NULL) {
+ Py_DECREF(type);
+ return NULL;
+ }
+ memcpy(tp_doc, PyString_AS_STRING(doc), n+1);
+ type->tp_doc = tp_doc;
+ }
+ }
+
+ /* Special-case __new__: if it's a plain function,
+ make it a static function */
+ tmp = PyDict_GetItemString(dict, "__new__");
+ if (tmp != NULL && PyFunction_Check(tmp)) {
+ tmp = PyStaticMethod_New(tmp);
+ if (tmp == NULL) {
+ Py_DECREF(type);
+ return NULL;
+ }
+ PyDict_SetItemString(dict, "__new__", tmp);
+ Py_DECREF(tmp);
+ }
+
+ /* Add descriptors for custom slots from __slots__, or for __dict__ */
+ mp = PyHeapType_GET_MEMBERS(et);
+ slotoffset = base->tp_basicsize;
+ if (slots != NULL) {
+ for (i = 0; i < nslots; i++, mp++) {
+ mp->name = PyString_AS_STRING(
+ PyTuple_GET_ITEM(slots, i));
+ mp->type = T_OBJECT_EX;
+ mp->offset = slotoffset;
+
+ /* __dict__ and __weakref__ are already filtered out */
+ assert(strcmp(mp->name, "__dict__") != 0);
+ assert(strcmp(mp->name, "__weakref__") != 0);
+
+ slotoffset += sizeof(PyObject *);
+ }
+ }
+ if (add_dict) {
+ if (base->tp_itemsize)
+ type->tp_dictoffset = -(long)sizeof(PyObject *);
+ else
+ type->tp_dictoffset = slotoffset;
+ slotoffset += sizeof(PyObject *);
+ }
+ if (add_weak) {
+ assert(!base->tp_itemsize);
+ type->tp_weaklistoffset = slotoffset;
+ slotoffset += sizeof(PyObject *);
+ }
+ type->tp_basicsize = slotoffset;
+ type->tp_itemsize = base->tp_itemsize;
+ type->tp_members = PyHeapType_GET_MEMBERS(et);
+
+ if (type->tp_weaklistoffset && type->tp_dictoffset)
+ type->tp_getset = subtype_getsets_full;
+ else if (type->tp_weaklistoffset && !type->tp_dictoffset)
+ type->tp_getset = subtype_getsets_weakref_only;
+ else if (!type->tp_weaklistoffset && type->tp_dictoffset)
+ type->tp_getset = subtype_getsets_dict_only;
+ else
+ type->tp_getset = NULL;
+
+ /* Special case some slots */
+ if (type->tp_dictoffset != 0 || nslots > 0) {
+ if (base->tp_getattr == NULL && base->tp_getattro == NULL)
+ type->tp_getattro = PyObject_GenericGetAttr;
+ if (base->tp_setattr == NULL && base->tp_setattro == NULL)
+ type->tp_setattro = PyObject_GenericSetAttr;
+ }
+ type->tp_dealloc = subtype_dealloc;
+
+ /* Enable GC unless there are really no instance variables possible */
+ if (!(type->tp_basicsize == sizeof(PyObject) &&
+ type->tp_itemsize == 0))
+ type->tp_flags |= Py_TPFLAGS_HAVE_GC;
+
+ /* Always override allocation strategy to use regular heap */
+ type->tp_alloc = PyType_GenericAlloc;
+ if (type->tp_flags & Py_TPFLAGS_HAVE_GC) {
+ type->tp_free = PyObject_GC_Del;
+ type->tp_traverse = subtype_traverse;
+ type->tp_clear = subtype_clear;
+ }
+ else
+ type->tp_free = PyObject_Del;
+
+ /* Initialize the rest */
+ if (PyType_Ready(type) < 0) {
+ Py_DECREF(type);
+ return NULL;
+ }
+
+ /* Put the proper slots in place */
+ fixup_slot_dispatchers(type);
+
+ return (PyObject *)type;
+}
+
+/* Internal API to look for a name through the MRO.
+ This returns a borrowed reference, and doesn't set an exception! */
+PyObject *
+_PyType_Lookup(PyTypeObject *type, PyObject *name)
+{
+ Py_ssize_t i, n;
+ PyObject *mro, *res, *base, *dict;
+ unsigned int h;
+
+ if (MCACHE_CACHEABLE_NAME(name) &&
+ PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG)) {
+ /* fast path */
+ h = MCACHE_HASH_METHOD(type, name);
+ if (method_cache[h].version == type->tp_version_tag &&
+ method_cache[h].name == name)
+ return method_cache[h].value;
+ }
+
+ /* Look in tp_dict of types in MRO */
+ mro = type->tp_mro;
+
+ /* If mro is NULL, the type is either not yet initialized
+ by PyType_Ready(), or already cleared by type_clear().
+ Either way the safest thing to do is to return NULL. */
+ if (mro == NULL)
+ return NULL;
+
+ res = NULL;
+ assert(PyTuple_Check(mro));
+ n = PyTuple_GET_SIZE(mro);
+ for (i = 0; i < n; i++) {
+ base = PyTuple_GET_ITEM(mro, i);
+ if (PyClass_Check(base))
+ dict = ((PyClassObject *)base)->cl_dict;
+ else {
+ assert(PyType_Check(base));
+ dict = ((PyTypeObject *)base)->tp_dict;
+ }
+ assert(dict && PyDict_Check(dict));
+ res = PyDict_GetItem(dict, name);
+ if (res != NULL)
+ break;
+ }
+
+ if (MCACHE_CACHEABLE_NAME(name) && assign_version_tag(type)) {
+ h = MCACHE_HASH_METHOD(type, name);
+ method_cache[h].version = type->tp_version_tag;
+ method_cache[h].value = res; /* borrowed */
+ Py_INCREF(name);
+ Py_DECREF(method_cache[h].name);
+ method_cache[h].name = name;
+ }
+ return res;
+}
+
+/* This is similar to PyObject_GenericGetAttr(),
+ but uses _PyType_Lookup() instead of just looking in type->tp_dict. */
+static PyObject *
+type_getattro(PyTypeObject *type, PyObject *name)
+{
+ PyTypeObject *metatype = Py_TYPE(type);
+ PyObject *meta_attribute, *attribute;
+ descrgetfunc meta_get;
+
+ /* Initialize this type (we'll assume the metatype is initialized) */
+ if (type->tp_dict == NULL) {
+ if (PyType_Ready(type) < 0)
+ return NULL;
+ }
+
+ /* No readable descriptor found yet */
+ meta_get = NULL;
+
+ /* Look for the attribute in the metatype */
+ meta_attribute = _PyType_Lookup(metatype, name);
+
+ if (meta_attribute != NULL) {
+ meta_get = Py_TYPE(meta_attribute)->tp_descr_get;
+
+ if (meta_get != NULL && PyDescr_IsData(meta_attribute)) {
+ /* Data descriptors implement tp_descr_set to intercept
+ * writes. Assume the attribute is not overridden in
+ * type's tp_dict (and bases): call the descriptor now.
+ */
+ return meta_get(meta_attribute, (PyObject *)type,
+ (PyObject *)metatype);
+ }
+ Py_INCREF(meta_attribute);
+ }
+
+ /* No data descriptor found on metatype. Look in tp_dict of this
+ * type and its bases */
+ attribute = _PyType_Lookup(type, name);
+ if (attribute != NULL) {
+ /* Implement descriptor functionality, if any */
+ descrgetfunc local_get = Py_TYPE(attribute)->tp_descr_get;
+
+ Py_XDECREF(meta_attribute);
+
+ if (local_get != NULL) {
+ /* NULL 2nd argument indicates the descriptor was
+ * found on the target object itself (or a base) */
+ return local_get(attribute, (PyObject *)NULL,
+ (PyObject *)type);
+ }
+
+ Py_INCREF(attribute);
+ return attribute;
+ }
+
+ /* No attribute found in local __dict__ (or bases): use the
+ * descriptor from the metatype, if any */
+ if (meta_get != NULL) {
+ PyObject *res;
+ res = meta_get(meta_attribute, (PyObject *)type,
+ (PyObject *)metatype);
+ Py_DECREF(meta_attribute);
+ return res;
+ }
+
+ /* If an ordinary attribute was found on the metatype, return it now */
+ if (meta_attribute != NULL) {
+ return meta_attribute;
+ }
+
+ /* Give up */
+ PyErr_Format(PyExc_AttributeError,
+ "type object '%.50s' has no attribute '%.400s'",
+ type->tp_name, PyString_AS_STRING(name));
+ return NULL;
+}
+
+static int
+type_setattro(PyTypeObject *type, PyObject *name, PyObject *value)
+{
+ if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
+ PyErr_Format(
+ PyExc_TypeError,
+ "can't set attributes of built-in/extension type '%s'",
+ type->tp_name);
+ return -1;
+ }
+ if (PyObject_GenericSetAttr((PyObject *)type, name, value) < 0)
+ return -1;
+ return update_slot(type, name);
+}
+
+static void
+type_dealloc(PyTypeObject *type)
+{
+ PyHeapTypeObject *et;
+
+ /* Assert this is a heap-allocated type object */
+ assert(type->tp_flags & Py_TPFLAGS_HEAPTYPE);
+ _PyObject_GC_UNTRACK(type);
+ PyObject_ClearWeakRefs((PyObject *)type);
+ et = (PyHeapTypeObject *)type;
+ Py_XDECREF(type->tp_base);
+ Py_XDECREF(type->tp_dict);
+ Py_XDECREF(type->tp_bases);
+ Py_XDECREF(type->tp_mro);
+ Py_XDECREF(type->tp_cache);
+ Py_XDECREF(type->tp_subclasses);
+ /* A type's tp_doc is heap allocated, unlike the tp_doc slots
+ * of most other objects. It's okay to cast it to char *.
+ */
+ PyObject_Free((char *)type->tp_doc);
+ Py_XDECREF(et->ht_name);
+ Py_XDECREF(et->ht_slots);
+ Py_TYPE(type)->tp_free((PyObject *)type);
+}
+
+static PyObject *
+type_subclasses(PyTypeObject *type, PyObject *args_ignored)
+{
+ PyObject *list, *raw, *ref;
+ Py_ssize_t i, n;
+
+ list = PyList_New(0);
+ if (list == NULL)
+ return NULL;
+ raw = type->tp_subclasses;
+ if (raw == NULL)
+ return list;
+ assert(PyList_Check(raw));
+ n = PyList_GET_SIZE(raw);
+ for (i = 0; i < n; i++) {
+ ref = PyList_GET_ITEM(raw, i);
+ assert(PyWeakref_CheckRef(ref));
+ ref = PyWeakref_GET_OBJECT(ref);
+ if (ref != Py_None) {
+ if (PyList_Append(list, ref) < 0) {
+ Py_DECREF(list);
+ return NULL;
+ }
+ }
+ }
+ return list;
+}
+
+static PyMethodDef type_methods[] = {
+ {"mro", (PyCFunction)mro_external, METH_NOARGS,
+ PyDoc_STR("mro() -> list\nreturn a type's method resolution order")},
+ {"__subclasses__", (PyCFunction)type_subclasses, METH_NOARGS,
+ PyDoc_STR("__subclasses__() -> list of immediate subclasses")},
+ {"__instancecheck__", type___instancecheck__, METH_O,
+ PyDoc_STR("__instancecheck__() -> bool\ncheck if an object is an instance")},
+ {"__subclasscheck__", type___subclasscheck__, METH_O,
+ PyDoc_STR("__subclasscheck__() -> bool\ncheck if a class is a subclass")},
+ {0}
+};
+
+PyDoc_STRVAR(type_doc,
+"type(object) -> the object's type\n"
+"type(name, bases, dict) -> a new type");
+
+static int
+type_traverse(PyTypeObject *type, visitproc visit, void *arg)
+{
+ /* Because of type_is_gc(), the collector only calls this
+ for heaptypes. */
+ assert(type->tp_flags & Py_TPFLAGS_HEAPTYPE);
+
+ Py_VISIT(type->tp_dict);
+ Py_VISIT(type->tp_cache);
+ Py_VISIT(type->tp_mro);
+ Py_VISIT(type->tp_bases);
+ Py_VISIT(type->tp_base);
+
+ /* There's no need to visit type->tp_subclasses or
+ ((PyHeapTypeObject *)type)->ht_slots, because they can't be involved
+ in cycles; tp_subclasses is a list of weak references,
+ and slots is a tuple of strings. */
+
+ return 0;
+}
+
+static int
+type_clear(PyTypeObject *type)
+{
+ /* Because of type_is_gc(), the collector only calls this
+ for heaptypes. */
+ assert(type->tp_flags & Py_TPFLAGS_HEAPTYPE);
+
+ /* The only field we need to clear is tp_mro, which is part of a
+ hard cycle (its first element is the class itself) that won't
+ be broken otherwise (it's a tuple and tuples don't have a
+ tp_clear handler). None of the other fields need to be
+ cleared, and here's why:
+
+ tp_dict:
+ It is a dict, so the collector will call its tp_clear.
+
+ tp_cache:
+ Not used; if it were, it would be a dict.
+
+ tp_bases, tp_base:
+ If these are involved in a cycle, there must be at least
+ one other, mutable object in the cycle, e.g. a base
+ class's dict; the cycle will be broken that way.
+
+ tp_subclasses:
+ A list of weak references can't be part of a cycle; and
+ lists have their own tp_clear.
+
+ slots (in PyHeapTypeObject):
+ A tuple of strings can't be part of a cycle.
+ */
+
+ Py_CLEAR(type->tp_mro);
+
+ return 0;
+}
+
+static int
+type_is_gc(PyTypeObject *type)
+{
+ return type->tp_flags & Py_TPFLAGS_HEAPTYPE;
+}
+
+PyTypeObject PyType_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ "type", /* tp_name */
+ sizeof(PyHeapTypeObject), /* tp_basicsize */
+ sizeof(PyMemberDef), /* tp_itemsize */
+ (destructor)type_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ (reprfunc)type_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ (hashfunc)_Py_HashPointer, /* tp_hash */
+ (ternaryfunc)type_call, /* tp_call */
+ 0, /* tp_str */
+ (getattrofunc)type_getattro, /* tp_getattro */
+ (setattrofunc)type_setattro, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
+ Py_TPFLAGS_BASETYPE | Py_TPFLAGS_TYPE_SUBCLASS, /* tp_flags */
+ type_doc, /* tp_doc */
+ (traverseproc)type_traverse, /* tp_traverse */
+ (inquiry)type_clear, /* tp_clear */
+ type_richcompare, /* tp_richcompare */
+ offsetof(PyTypeObject, tp_weaklist), /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ type_methods, /* tp_methods */
+ type_members, /* tp_members */
+ type_getsets, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ offsetof(PyTypeObject, tp_dict), /* tp_dictoffset */
+ type_init, /* tp_init */
+ 0, /* tp_alloc */
+ type_new, /* tp_new */
+ PyObject_GC_Del, /* tp_free */
+ (inquiry)type_is_gc, /* tp_is_gc */
+};
+
+
+/* The base type of all types (eventually)... except itself. */
+
+/* You may wonder why object.__new__() only complains about arguments
+ when object.__init__() is not overridden, and vice versa.
+
+ Consider the use cases:
+
+ 1. When neither is overridden, we want to hear complaints about
+ excess (i.e., any) arguments, since their presence could
+ indicate there's a bug.
+
+ 2. When defining an Immutable type, we are likely to override only
+ __new__(), since __init__() is called too late to initialize an
+ Immutable object. Since __new__() defines the signature for the
+ type, it would be a pain to have to override __init__() just to
+ stop it from complaining about excess arguments.
+
+ 3. When defining a Mutable type, we are likely to override only
+ __init__(). So here the converse reasoning applies: we don't
+ want to have to override __new__() just to stop it from
+ complaining.
+
+ 4. When __init__() is overridden, and the subclass __init__() calls
+ object.__init__(), the latter should complain about excess
+ arguments; ditto for __new__().
+
+ Use cases 2 and 3 make it unattractive to unconditionally check for
+ excess arguments. The best solution that addresses all four use
+ cases is as follows: __init__() complains about excess arguments
+ unless __new__() is overridden and __init__() is not overridden
+ (IOW, if __init__() is overridden or __new__() is not overridden);
+ symmetrically, __new__() complains about excess arguments unless
+ __init__() is overridden and __new__() is not overridden
+ (IOW, if __new__() is overridden or __init__() is not overridden).
+
+ However, for backwards compatibility, this breaks too much code.
+ Therefore, in 2.6, we'll *warn* about excess arguments when both
+ methods are overridden; for all other cases we'll use the above
+ rules.
+
+*/
+
+/* Forward */
+static PyObject *
+object_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
+
+static int
+excess_args(PyObject *args, PyObject *kwds)
+{
+ return PyTuple_GET_SIZE(args) ||
+ (kwds && PyDict_Check(kwds) && PyDict_Size(kwds));
+}
+
+static int
+object_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ int err = 0;
+ if (excess_args(args, kwds)) {
+ PyTypeObject *type = Py_TYPE(self);
+ if (type->tp_init != object_init &&
+ type->tp_new != object_new)
+ {
+ err = PyErr_WarnEx(PyExc_DeprecationWarning,
+ "object.__init__() takes no parameters",
+ 1);
+ }
+ else if (type->tp_init != object_init ||
+ type->tp_new == object_new)
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "object.__init__() takes no parameters");
+ err = -1;
+ }
+ }
+ return err;
+}
+
+static PyObject *
+object_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ int err = 0;
+ if (excess_args(args, kwds)) {
+ if (type->tp_new != object_new &&
+ type->tp_init != object_init)
+ {
+ err = PyErr_WarnEx(PyExc_DeprecationWarning,
+ "object.__new__() takes no parameters",
+ 1);
+ }
+ else if (type->tp_new != object_new ||
+ type->tp_init == object_init)
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "object.__new__() takes no parameters");
+ err = -1;
+ }
+ }
+ if (err < 0)
+ return NULL;
+
+ if (type->tp_flags & Py_TPFLAGS_IS_ABSTRACT) {
+ static PyObject *comma = NULL;
+ PyObject *abstract_methods = NULL;
+ PyObject *builtins;
+ PyObject *sorted;
+ PyObject *sorted_methods = NULL;
+ PyObject *joined = NULL;
+ const char *joined_str;
+
+ /* Compute ", ".join(sorted(type.__abstractmethods__))
+ into joined. */
+ abstract_methods = type_abstractmethods(type, NULL);
+ if (abstract_methods == NULL)
+ goto error;
+ builtins = PyEval_GetBuiltins();
+ if (builtins == NULL)
+ goto error;
+ sorted = PyDict_GetItemString(builtins, "sorted");
+ if (sorted == NULL)
+ goto error;
+ sorted_methods = PyObject_CallFunctionObjArgs(sorted,
+ abstract_methods,
+ NULL);
+ if (sorted_methods == NULL)
+ goto error;
+ if (comma == NULL) {
+ comma = PyString_InternFromString(", ");
+ if (comma == NULL)
+ goto error;
+ }
+ joined = PyObject_CallMethod(comma, "join",
+ "O", sorted_methods);
+ if (joined == NULL)
+ goto error;
+ joined_str = PyString_AsString(joined);
+ if (joined_str == NULL)
+ goto error;
+
+ PyErr_Format(PyExc_TypeError,
+ "Can't instantiate abstract class %s "
+ "with abstract methods %s",
+ type->tp_name,
+ joined_str);
+ error:
+ Py_XDECREF(joined);
+ Py_XDECREF(sorted_methods);
+ Py_XDECREF(abstract_methods);
+ return NULL;
+ }
+ return type->tp_alloc(type, 0);
+}
+
+static void
+object_dealloc(PyObject *self)
+{
+ Py_TYPE(self)->tp_free(self);
+}
+
+static PyObject *
+object_repr(PyObject *self)
+{
+ PyTypeObject *type;
+ PyObject *mod, *name, *rtn;
+
+ type = Py_TYPE(self);
+ mod = type_module(type, NULL);
+ if (mod == NULL)
+ PyErr_Clear();
+ else if (!PyString_Check(mod)) {
+ Py_DECREF(mod);
+ mod = NULL;
+ }
+ name = type_name(type, NULL);
+ if (name == NULL)
+ return NULL;
+ if (mod != NULL && strcmp(PyString_AS_STRING(mod), "__builtin__"))
+ rtn = PyString_FromFormat("<%s.%s object at %p>",
+ PyString_AS_STRING(mod),
+ PyString_AS_STRING(name),
+ self);
+ else
+ rtn = PyString_FromFormat("<%s object at %p>",
+ type->tp_name, self);
+ Py_XDECREF(mod);
+ Py_DECREF(name);
+ return rtn;
+}
+
+static PyObject *
+object_str(PyObject *self)
+{
+ unaryfunc f;
+
+ f = Py_TYPE(self)->tp_repr;
+ if (f == NULL)
+ f = object_repr;
+ return f(self);
+}
+
+static PyObject *
+object_get_class(PyObject *self, void *closure)
+{
+ Py_INCREF(Py_TYPE(self));
+ return (PyObject *)(Py_TYPE(self));
+}
+
+static int
+equiv_structs(PyTypeObject *a, PyTypeObject *b)
+{
+ return a == b ||
+ (a != NULL &&
+ b != NULL &&
+ a->tp_basicsize == b->tp_basicsize &&
+ a->tp_itemsize == b->tp_itemsize &&
+ a->tp_dictoffset == b->tp_dictoffset &&
+ a->tp_weaklistoffset == b->tp_weaklistoffset &&
+ ((a->tp_flags & Py_TPFLAGS_HAVE_GC) ==
+ (b->tp_flags & Py_TPFLAGS_HAVE_GC)));
+}
+
+static int
+same_slots_added(PyTypeObject *a, PyTypeObject *b)
+{
+ PyTypeObject *base = a->tp_base;
+ Py_ssize_t size;
+ PyObject *slots_a, *slots_b;
+
+ assert(base == b->tp_base);
+ size = base->tp_basicsize;
+ if (a->tp_dictoffset == size && b->tp_dictoffset == size)
+ size += sizeof(PyObject *);
+ if (a->tp_weaklistoffset == size && b->tp_weaklistoffset == size)
+ size += sizeof(PyObject *);
+
+ /* Check slots compliance */
+ slots_a = ((PyHeapTypeObject *)a)->ht_slots;
+ slots_b = ((PyHeapTypeObject *)b)->ht_slots;
+ if (slots_a && slots_b) {
+ if (PyObject_Compare(slots_a, slots_b) != 0)
+ return 0;
+ size += sizeof(PyObject *) * PyTuple_GET_SIZE(slots_a);
+ }
+ return size == a->tp_basicsize && size == b->tp_basicsize;
+}
+
+static int
+compatible_for_assignment(PyTypeObject* oldto, PyTypeObject* newto, char* attr)
+{
+ PyTypeObject *newbase, *oldbase;
+
+ if (newto->tp_dealloc != oldto->tp_dealloc ||
+ newto->tp_free != oldto->tp_free)
+ {
+ PyErr_Format(PyExc_TypeError,
+ "%s assignment: "
+ "'%s' deallocator differs from '%s'",
+ attr,
+ newto->tp_name,
+ oldto->tp_name);
+ return 0;
+ }
+ newbase = newto;
+ oldbase = oldto;
+ while (equiv_structs(newbase, newbase->tp_base))
+ newbase = newbase->tp_base;
+ while (equiv_structs(oldbase, oldbase->tp_base))
+ oldbase = oldbase->tp_base;
+ if (newbase != oldbase &&
+ (newbase->tp_base != oldbase->tp_base ||
+ !same_slots_added(newbase, oldbase))) {
+ PyErr_Format(PyExc_TypeError,
+ "%s assignment: "
+ "'%s' object layout differs from '%s'",
+ attr,
+ newto->tp_name,
+ oldto->tp_name);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int
+object_set_class(PyObject *self, PyObject *value, void *closure)
+{
+ PyTypeObject *oldto = Py_TYPE(self);
+ PyTypeObject *newto;
+
+ if (value == NULL) {
+ PyErr_SetString(PyExc_TypeError,
+ "can't delete __class__ attribute");
+ return -1;
+ }
+ if (!PyType_Check(value)) {
+ PyErr_Format(PyExc_TypeError,
+ "__class__ must be set to new-style class, not '%s' object",
+ Py_TYPE(value)->tp_name);
+ return -1;
+ }
+ newto = (PyTypeObject *)value;
+ if (!(newto->tp_flags & Py_TPFLAGS_HEAPTYPE) ||
+ !(oldto->tp_flags & Py_TPFLAGS_HEAPTYPE))
+ {
+ PyErr_Format(PyExc_TypeError,
+ "__class__ assignment: only for heap types");
+ return -1;
+ }
+ if (compatible_for_assignment(newto, oldto, "__class__")) {
+ Py_INCREF(newto);
+ Py_TYPE(self) = newto;
+ Py_DECREF(oldto);
+ return 0;
+ }
+ else {
+ return -1;
+ }
+}
+
+static PyGetSetDef object_getsets[] = {
+ {"__class__", object_get_class, object_set_class,
+ PyDoc_STR("the object's class")},
+ {0}
+};
+
+
+/* Stuff to implement __reduce_ex__ for pickle protocols >= 2.
+ We fall back to helpers in copy_reg for:
+ - pickle protocols < 2
+ - calculating the list of slot names (done only once per class)
+ - the __newobj__ function (which is used as a token but never called)
+*/
+
+static PyObject *
+import_copyreg(void)
+{
+ static PyObject *copyreg_str;
+
+ if (!copyreg_str) {
+ copyreg_str = PyString_InternFromString("copy_reg");
+ if (copyreg_str == NULL)
+ return NULL;
+ }
+
+ return PyImport_Import(copyreg_str);
+}
+
+static PyObject *
+slotnames(PyObject *cls)
+{
+ PyObject *clsdict;
+ PyObject *copyreg;
+ PyObject *slotnames;
+
+ if (!PyType_Check(cls)) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ clsdict = ((PyTypeObject *)cls)->tp_dict;
+ slotnames = PyDict_GetItemString(clsdict, "__slotnames__");
+ if (slotnames != NULL && PyList_Check(slotnames)) {
+ Py_INCREF(slotnames);
+ return slotnames;
+ }
+
+ copyreg = import_copyreg();
+ if (copyreg == NULL)
+ return NULL;
+
+ slotnames = PyObject_CallMethod(copyreg, "_slotnames", "O", cls);
+ Py_DECREF(copyreg);
+ if (slotnames != NULL &&
+ slotnames != Py_None &&
+ !PyList_Check(slotnames))
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "copy_reg._slotnames didn't return a list or None");
+ Py_DECREF(slotnames);
+ slotnames = NULL;
+ }
+
+ return slotnames;
+}
+
+static PyObject *
+reduce_2(PyObject *obj)
+{
+ PyObject *cls, *getnewargs;
+ PyObject *args = NULL, *args2 = NULL;
+ PyObject *getstate = NULL, *state = NULL, *names = NULL;
+ PyObject *slots = NULL, *listitems = NULL, *dictitems = NULL;
+ PyObject *copyreg = NULL, *newobj = NULL, *res = NULL;
+ Py_ssize_t i, n;
+
+ cls = PyObject_GetAttrString(obj, "__class__");
+ if (cls == NULL)
+ return NULL;
+
+ getnewargs = PyObject_GetAttrString(obj, "__getnewargs__");
+ if (getnewargs != NULL) {
+ args = PyObject_CallObject(getnewargs, NULL);
+ Py_DECREF(getnewargs);
+ if (args != NULL && !PyTuple_Check(args)) {
+ PyErr_Format(PyExc_TypeError,
+ "__getnewargs__ should return a tuple, "
+ "not '%.200s'", Py_TYPE(args)->tp_name);
+ goto end;
+ }
+ }
+ else {
+ PyErr_Clear();
+ args = PyTuple_New(0);
+ }
+ if (args == NULL)
+ goto end;
+
+ getstate = PyObject_GetAttrString(obj, "__getstate__");
+ if (getstate != NULL) {
+ state = PyObject_CallObject(getstate, NULL);
+ Py_DECREF(getstate);
+ if (state == NULL)
+ goto end;
+ }
+ else {
+ PyErr_Clear();
+ state = PyObject_GetAttrString(obj, "__dict__");
+ if (state == NULL) {
+ PyErr_Clear();
+ state = Py_None;
+ Py_INCREF(state);
+ }
+ names = slotnames(cls);
+ if (names == NULL)
+ goto end;
+ if (names != Py_None) {
+ assert(PyList_Check(names));
+ slots = PyDict_New();
+ if (slots == NULL)
+ goto end;
+ n = 0;
+ /* Can't pre-compute the list size; the list
+ is stored on the class so accessible to other
+ threads, which may be run by DECREF */
+ for (i = 0; i < PyList_GET_SIZE(names); i++) {
+ PyObject *name, *value;
+ name = PyList_GET_ITEM(names, i);
+ value = PyObject_GetAttr(obj, name);
+ if (value == NULL)
+ PyErr_Clear();
+ else {
+ int err = PyDict_SetItem(slots, name,
+ value);
+ Py_DECREF(value);
+ if (err)
+ goto end;
+ n++;
+ }
+ }
+ if (n) {
+ state = Py_BuildValue("(NO)", state, slots);
+ if (state == NULL)
+ goto end;
+ }
+ }
+ }
+
+ if (!PyList_Check(obj)) {
+ listitems = Py_None;
+ Py_INCREF(listitems);
+ }
+ else {
+ listitems = PyObject_GetIter(obj);
+ if (listitems == NULL)
+ goto end;
+ }
+
+ if (!PyDict_Check(obj)) {
+ dictitems = Py_None;
+ Py_INCREF(dictitems);
+ }
+ else {
+ dictitems = PyObject_CallMethod(obj, "iteritems", "");
+ if (dictitems == NULL)
+ goto end;
+ }
+
+ copyreg = import_copyreg();
+ if (copyreg == NULL)
+ goto end;
+ newobj = PyObject_GetAttrString(copyreg, "__newobj__");
+ if (newobj == NULL)
+ goto end;
+
+ n = PyTuple_GET_SIZE(args);
+ args2 = PyTuple_New(n+1);
+ if (args2 == NULL)
+ goto end;
+ PyTuple_SET_ITEM(args2, 0, cls);
+ cls = NULL;
+ for (i = 0; i < n; i++) {
+ PyObject *v = PyTuple_GET_ITEM(args, i);
+ Py_INCREF(v);
+ PyTuple_SET_ITEM(args2, i+1, v);
+ }
+
+ res = PyTuple_Pack(5, newobj, args2, state, listitems, dictitems);
+
+ end:
+ Py_XDECREF(cls);
+ Py_XDECREF(args);
+ Py_XDECREF(args2);
+ Py_XDECREF(slots);
+ Py_XDECREF(state);
+ Py_XDECREF(names);
+ Py_XDECREF(listitems);
+ Py_XDECREF(dictitems);
+ Py_XDECREF(copyreg);
+ Py_XDECREF(newobj);
+ return res;
+}
+
+/*
+ * There were two problems when object.__reduce__ and object.__reduce_ex__
+ * were implemented in the same function:
+ * - trying to pickle an object with a custom __reduce__ method that
+ * fell back to object.__reduce__ in certain circumstances led to
+ * infinite recursion at Python level and eventual RuntimeError.
+ * - Pickling objects that lied about their type by overwriting the
+ * __class__ descriptor could lead to infinite recursion at C level
+ * and eventual segfault.
+ *
+ * Because of backwards compatibility, the two methods still have to
+ * behave in the same way, even if this is not required by the pickle
+ * protocol. This common functionality was moved to the _common_reduce
+ * function.
+ */
+static PyObject *
+_common_reduce(PyObject *self, int proto)
+{
+ PyObject *copyreg, *res;
+
+ if (proto >= 2)
+ return reduce_2(self);
+
+ copyreg = import_copyreg();
+ if (!copyreg)
+ return NULL;
+
+ res = PyEval_CallMethod(copyreg, "_reduce_ex", "(Oi)", self, proto);
+ Py_DECREF(copyreg);
+
+ return res;
+}
+
+static PyObject *
+object_reduce(PyObject *self, PyObject *args)
+{
+ int proto = 0;
+
+ if (!PyArg_ParseTuple(args, "|i:__reduce__", &proto))
+ return NULL;
+
+ return _common_reduce(self, proto);
+}
+
+static PyObject *
+object_reduce_ex(PyObject *self, PyObject *args)
+{
+ PyObject *reduce, *res;
+ int proto = 0;
+
+ if (!PyArg_ParseTuple(args, "|i:__reduce_ex__", &proto))
+ return NULL;
+
+ reduce = PyObject_GetAttrString(self, "__reduce__");
+ if (reduce == NULL)
+ PyErr_Clear();
+ else {
+ PyObject *cls, *clsreduce, *objreduce;
+ int override;
+ cls = PyObject_GetAttrString(self, "__class__");
+ if (cls == NULL) {
+ Py_DECREF(reduce);
+ return NULL;
+ }
+ clsreduce = PyObject_GetAttrString(cls, "__reduce__");
+ Py_DECREF(cls);
+ if (clsreduce == NULL) {
+ Py_DECREF(reduce);
+ return NULL;
+ }
+ objreduce = PyDict_GetItemString(PyBaseObject_Type.tp_dict,
+ "__reduce__");
+ override = (clsreduce != objreduce);
+ Py_DECREF(clsreduce);
+ if (override) {
+ res = PyObject_CallObject(reduce, NULL);
+ Py_DECREF(reduce);
+ return res;
+ }
+ else
+ Py_DECREF(reduce);
+ }
+
+ return _common_reduce(self, proto);
+}
+
+static PyObject *
+object_subclasshook(PyObject *cls, PyObject *args)
+{
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+}
+
+PyDoc_STRVAR(object_subclasshook_doc,
+"Abstract classes can override this to customize issubclass().\n"
+"\n"
+"This is invoked early on by abc.ABCMeta.__subclasscheck__().\n"
+"It should return True, False or NotImplemented. If it returns\n"
+"NotImplemented, the normal algorithm is used. Otherwise, it\n"
+"overrides the normal algorithm (and the outcome is cached).\n");
+
+/*
+ from PEP 3101, this code implements:
+
+ class object:
+ def __format__(self, format_spec):
+ if isinstance(format_spec, str):
+ return format(str(self), format_spec)
+ elif isinstance(format_spec, unicode):
+ return format(unicode(self), format_spec)
+*/
+static PyObject *
+object_format(PyObject *self, PyObject *args)
+{
+ PyObject *format_spec;
+ PyObject *self_as_str = NULL;
+ PyObject *result = NULL;
+ Py_ssize_t format_len;
+
+ if (!PyArg_ParseTuple(args, "O:__format__", &format_spec))
+ return NULL;
+#ifdef Py_USING_UNICODE
+ if (PyUnicode_Check(format_spec)) {
+ format_len = PyUnicode_GET_SIZE(format_spec);
+ self_as_str = PyObject_Unicode(self);
+ } else if (PyString_Check(format_spec)) {
+#else
+ if (PyString_Check(format_spec)) {
+#endif
+ format_len = PyString_GET_SIZE(format_spec);
+ self_as_str = PyObject_Str(self);
+ } else {
+ PyErr_SetString(PyExc_TypeError,
+ "argument to __format__ must be unicode or str");
+ return NULL;
+ }
+
+ if (self_as_str != NULL) {
+ /* Issue 7994: If we're converting to a string, we
+ should reject format specifications */
+ if (format_len > 0) {
+ if (PyErr_WarnEx(PyExc_PendingDeprecationWarning,
+ "object.__format__ with a non-empty format "
+ "string is deprecated", 1) < 0) {
+ goto done;
+ }
+ /* Eventually this will become an error:
+ PyErr_Format(PyExc_TypeError,
+ "non-empty format string passed to object.__format__");
+ goto done;
+ */
+ }
+ result = PyObject_Format(self_as_str, format_spec);
+ }
+
+done:
+ Py_XDECREF(self_as_str);
+
+ return result;
+}
+
+static PyObject *
+object_sizeof(PyObject *self, PyObject *args)
+{
+ Py_ssize_t res, isize;
+
+ res = 0;
+ isize = self->ob_type->tp_itemsize;
+ if (isize > 0)
+ res = self->ob_type->ob_size * isize;
+ res += self->ob_type->tp_basicsize;
+
+ return PyInt_FromSsize_t(res);
+}
+
+static PyMethodDef object_methods[] = {
+ {"__reduce_ex__", object_reduce_ex, METH_VARARGS,
+ PyDoc_STR("helper for pickle")},
+ {"__reduce__", object_reduce, METH_VARARGS,
+ PyDoc_STR("helper for pickle")},
+ {"__subclasshook__", object_subclasshook, METH_CLASS | METH_VARARGS,
+ object_subclasshook_doc},
+ {"__format__", object_format, METH_VARARGS,
+ PyDoc_STR("default object formatter")},
+ {"__sizeof__", object_sizeof, METH_NOARGS,
+ PyDoc_STR("__sizeof__() -> int\nsize of object in memory, in bytes")},
+ {0}
+};
+
+
+PyTypeObject PyBaseObject_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ "object", /* tp_name */
+ sizeof(PyObject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ object_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ object_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ (hashfunc)_Py_HashPointer, /* tp_hash */
+ 0, /* tp_call */
+ object_str, /* tp_str */
+ PyObject_GenericGetAttr, /* tp_getattro */
+ PyObject_GenericSetAttr, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ PyDoc_STR("The most base type"), /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ object_methods, /* tp_methods */
+ 0, /* tp_members */
+ object_getsets, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ object_init, /* tp_init */
+ PyType_GenericAlloc, /* tp_alloc */
+ object_new, /* tp_new */
+ PyObject_Del, /* tp_free */
+};
+
+
+/* Initialize the __dict__ in a type object */
+
+static int
+add_methods(PyTypeObject *type, PyMethodDef *meth)
+{
+ PyObject *dict = type->tp_dict;
+
+ for (; meth->ml_name != NULL; meth++) {
+ PyObject *descr;
+ if (PyDict_GetItemString(dict, meth->ml_name) &&
+ !(meth->ml_flags & METH_COEXIST))
+ continue;
+ if (meth->ml_flags & METH_CLASS) {
+ if (meth->ml_flags & METH_STATIC) {
+ PyErr_SetString(PyExc_ValueError,
+ "method cannot be both class and static");
+ return -1;
+ }
+ descr = PyDescr_NewClassMethod(type, meth);
+ }
+ else if (meth->ml_flags & METH_STATIC) {
+ PyObject *cfunc = PyCFunction_New(meth, NULL);
+ if (cfunc == NULL)
+ return -1;
+ descr = PyStaticMethod_New(cfunc);
+ Py_DECREF(cfunc);
+ }
+ else {
+ descr = PyDescr_NewMethod(type, meth);
+ }
+ if (descr == NULL)
+ return -1;
+ if (PyDict_SetItemString(dict, meth->ml_name, descr) < 0)
+ return -1;
+ Py_DECREF(descr);
+ }
+ return 0;
+}
+
+static int
+add_members(PyTypeObject *type, PyMemberDef *memb)
+{
+ PyObject *dict = type->tp_dict;
+
+ for (; memb->name != NULL; memb++) {
+ PyObject *descr;
+ if (PyDict_GetItemString(dict, memb->name))
+ continue;
+ descr = PyDescr_NewMember(type, memb);
+ if (descr == NULL)
+ return -1;
+ if (PyDict_SetItemString(dict, memb->name, descr) < 0)
+ return -1;
+ Py_DECREF(descr);
+ }
+ return 0;
+}
+
+static int
+add_getset(PyTypeObject *type, PyGetSetDef *gsp)
+{
+ PyObject *dict = type->tp_dict;
+
+ for (; gsp->name != NULL; gsp++) {
+ PyObject *descr;
+ if (PyDict_GetItemString(dict, gsp->name))
+ continue;
+ descr = PyDescr_NewGetSet(type, gsp);
+
+ if (descr == NULL)
+ return -1;
+ if (PyDict_SetItemString(dict, gsp->name, descr) < 0)
+ return -1;
+ Py_DECREF(descr);
+ }
+ return 0;
+}
+
+#define BUFFER_FLAGS (Py_TPFLAGS_HAVE_GETCHARBUFFER | Py_TPFLAGS_HAVE_NEWBUFFER)
+
+static void
+inherit_special(PyTypeObject *type, PyTypeObject *base)
+{
+ Py_ssize_t oldsize, newsize;
+
+ /* Special flag magic */
+ if (!type->tp_as_buffer && base->tp_as_buffer) {
+ type->tp_flags &= ~BUFFER_FLAGS;
+ type->tp_flags |=
+ base->tp_flags & BUFFER_FLAGS;
+ }
+ if (!type->tp_as_sequence && base->tp_as_sequence) {
+ type->tp_flags &= ~Py_TPFLAGS_HAVE_SEQUENCE_IN;
+ type->tp_flags |= base->tp_flags & Py_TPFLAGS_HAVE_SEQUENCE_IN;
+ }
+ if ((type->tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS) !=
+ (base->tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS)) {
+ if ((!type->tp_as_number && base->tp_as_number) ||
+ (!type->tp_as_sequence && base->tp_as_sequence)) {
+ type->tp_flags &= ~Py_TPFLAGS_HAVE_INPLACEOPS;
+ if (!type->tp_as_number && !type->tp_as_sequence) {
+ type->tp_flags |= base->tp_flags &
+ Py_TPFLAGS_HAVE_INPLACEOPS;
+ }
+ }
+ /* Wow */
+ }
+ if (!type->tp_as_number && base->tp_as_number) {
+ type->tp_flags &= ~Py_TPFLAGS_CHECKTYPES;
+ type->tp_flags |= base->tp_flags & Py_TPFLAGS_CHECKTYPES;
+ }
+
+ /* Copying basicsize is connected to the GC flags */
+ oldsize = base->tp_basicsize;
+ newsize = type->tp_basicsize ? type->tp_basicsize : oldsize;
+ if (!(type->tp_flags & Py_TPFLAGS_HAVE_GC) &&
+ (base->tp_flags & Py_TPFLAGS_HAVE_GC) &&
+ (type->tp_flags & Py_TPFLAGS_HAVE_RICHCOMPARE/*GC slots exist*/) &&
+ (!type->tp_traverse && !type->tp_clear)) {
+ type->tp_flags |= Py_TPFLAGS_HAVE_GC;
+ if (type->tp_traverse == NULL)
+ type->tp_traverse = base->tp_traverse;
+ if (type->tp_clear == NULL)
+ type->tp_clear = base->tp_clear;
+ }
+ if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_CLASS) {
+ /* The condition below could use some explanation.
+ It appears that tp_new is not inherited for static types
+ whose base class is 'object'; this seems to be a precaution
+ so that old extension types don't suddenly become
+ callable (object.__new__ wouldn't insure the invariants
+ that the extension type's own factory function ensures).
+ Heap types, of course, are under our control, so they do
+ inherit tp_new; static extension types that specify some
+ other built-in type as the default are considered
+ new-style-aware so they also inherit object.__new__. */
+ if (base != &PyBaseObject_Type ||
+ (type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
+ if (type->tp_new == NULL)
+ type->tp_new = base->tp_new;
+ }
+ }
+ type->tp_basicsize = newsize;
+
+ /* Copy other non-function slots */
+
+#undef COPYVAL
+#define COPYVAL(SLOT) \
+ if (type->SLOT == 0) type->SLOT = base->SLOT
+
+ COPYVAL(tp_itemsize);
+ if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_WEAKREFS) {
+ COPYVAL(tp_weaklistoffset);
+ }
+ if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_CLASS) {
+ COPYVAL(tp_dictoffset);
+ }
+
+ /* Setup fast subclass flags */
+ if (PyType_IsSubtype(base, (PyTypeObject*)PyExc_BaseException))
+ type->tp_flags |= Py_TPFLAGS_BASE_EXC_SUBCLASS;
+ else if (PyType_IsSubtype(base, &PyType_Type))
+ type->tp_flags |= Py_TPFLAGS_TYPE_SUBCLASS;
+ else if (PyType_IsSubtype(base, &PyInt_Type))
+ type->tp_flags |= Py_TPFLAGS_INT_SUBCLASS;
+ else if (PyType_IsSubtype(base, &PyLong_Type))
+ type->tp_flags |= Py_TPFLAGS_LONG_SUBCLASS;
+ else if (PyType_IsSubtype(base, &PyString_Type))
+ type->tp_flags |= Py_TPFLAGS_STRING_SUBCLASS;
+#ifdef Py_USING_UNICODE
+ else if (PyType_IsSubtype(base, &PyUnicode_Type))
+ type->tp_flags |= Py_TPFLAGS_UNICODE_SUBCLASS;
+#endif
+ else if (PyType_IsSubtype(base, &PyTuple_Type))
+ type->tp_flags |= Py_TPFLAGS_TUPLE_SUBCLASS;
+ else if (PyType_IsSubtype(base, &PyList_Type))
+ type->tp_flags |= Py_TPFLAGS_LIST_SUBCLASS;
+ else if (PyType_IsSubtype(base, &PyDict_Type))
+ type->tp_flags |= Py_TPFLAGS_DICT_SUBCLASS;
+}
+
+static int
+overrides_name(PyTypeObject *type, char *name)
+{
+ PyObject *dict = type->tp_dict;
+
+ assert(dict != NULL);
+ if (PyDict_GetItemString(dict, name) != NULL) {
+ return 1;
+ }
+ return 0;
+}
+
+#define OVERRIDES_HASH(x) overrides_name(x, "__hash__")
+#define OVERRIDES_EQ(x) overrides_name(x, "__eq__")
+
+static void
+inherit_slots(PyTypeObject *type, PyTypeObject *base)
+{
+ PyTypeObject *basebase;
+
+#undef SLOTDEFINED
+#undef COPYSLOT
+#undef COPYNUM
+#undef COPYSEQ
+#undef COPYMAP
+#undef COPYBUF
+
+#define SLOTDEFINED(SLOT) \
+ (base->SLOT != 0 && \
+ (basebase == NULL || base->SLOT != basebase->SLOT))
+
+#define COPYSLOT(SLOT) \
+ if (!type->SLOT && SLOTDEFINED(SLOT)) type->SLOT = base->SLOT
+
+#define COPYNUM(SLOT) COPYSLOT(tp_as_number->SLOT)
+#define COPYSEQ(SLOT) COPYSLOT(tp_as_sequence->SLOT)
+#define COPYMAP(SLOT) COPYSLOT(tp_as_mapping->SLOT)
+#define COPYBUF(SLOT) COPYSLOT(tp_as_buffer->SLOT)
+
+ /* This won't inherit indirect slots (from tp_as_number etc.)
+ if type doesn't provide the space. */
+
+ if (type->tp_as_number != NULL && base->tp_as_number != NULL) {
+ basebase = base->tp_base;
+ if (basebase->tp_as_number == NULL)
+ basebase = NULL;
+ COPYNUM(nb_add);
+ COPYNUM(nb_subtract);
+ COPYNUM(nb_multiply);
+ COPYNUM(nb_divide);
+ COPYNUM(nb_remainder);
+ COPYNUM(nb_divmod);
+ COPYNUM(nb_power);
+ COPYNUM(nb_negative);
+ COPYNUM(nb_positive);
+ COPYNUM(nb_absolute);
+ COPYNUM(nb_nonzero);
+ COPYNUM(nb_invert);
+ COPYNUM(nb_lshift);
+ COPYNUM(nb_rshift);
+ COPYNUM(nb_and);
+ COPYNUM(nb_xor);
+ COPYNUM(nb_or);
+ COPYNUM(nb_coerce);
+ COPYNUM(nb_int);
+ COPYNUM(nb_long);
+ COPYNUM(nb_float);
+ COPYNUM(nb_oct);
+ COPYNUM(nb_hex);
+ COPYNUM(nb_inplace_add);
+ COPYNUM(nb_inplace_subtract);
+ COPYNUM(nb_inplace_multiply);
+ COPYNUM(nb_inplace_divide);
+ COPYNUM(nb_inplace_remainder);
+ COPYNUM(nb_inplace_power);
+ COPYNUM(nb_inplace_lshift);
+ COPYNUM(nb_inplace_rshift);
+ COPYNUM(nb_inplace_and);
+ COPYNUM(nb_inplace_xor);
+ COPYNUM(nb_inplace_or);
+ if (base->tp_flags & Py_TPFLAGS_CHECKTYPES) {
+ COPYNUM(nb_true_divide);
+ COPYNUM(nb_floor_divide);
+ COPYNUM(nb_inplace_true_divide);
+ COPYNUM(nb_inplace_floor_divide);
+ }
+ if (base->tp_flags & Py_TPFLAGS_HAVE_INDEX) {
+ COPYNUM(nb_index);
+ }
+ }
+
+ if (type->tp_as_sequence != NULL && base->tp_as_sequence != NULL) {
+ basebase = base->tp_base;
+ if (basebase->tp_as_sequence == NULL)
+ basebase = NULL;
+ COPYSEQ(sq_length);
+ COPYSEQ(sq_concat);
+ COPYSEQ(sq_repeat);
+ COPYSEQ(sq_item);
+ COPYSEQ(sq_slice);
+ COPYSEQ(sq_ass_item);
+ COPYSEQ(sq_ass_slice);
+ COPYSEQ(sq_contains);
+ COPYSEQ(sq_inplace_concat);
+ COPYSEQ(sq_inplace_repeat);
+ }
+
+ if (type->tp_as_mapping != NULL && base->tp_as_mapping != NULL) {
+ basebase = base->tp_base;
+ if (basebase->tp_as_mapping == NULL)
+ basebase = NULL;
+ COPYMAP(mp_length);
+ COPYMAP(mp_subscript);
+ COPYMAP(mp_ass_subscript);
+ }
+
+ if (type->tp_as_buffer != NULL && base->tp_as_buffer != NULL) {
+ basebase = base->tp_base;
+ if (basebase->tp_as_buffer == NULL)
+ basebase = NULL;
+ COPYBUF(bf_getreadbuffer);
+ COPYBUF(bf_getwritebuffer);
+ COPYBUF(bf_getsegcount);
+ COPYBUF(bf_getcharbuffer);
+ COPYBUF(bf_getbuffer);
+ COPYBUF(bf_releasebuffer);
+ }
+
+ basebase = base->tp_base;
+
+ COPYSLOT(tp_dealloc);
+ COPYSLOT(tp_print);
+ if (type->tp_getattr == NULL && type->tp_getattro == NULL) {
+ type->tp_getattr = base->tp_getattr;
+ type->tp_getattro = base->tp_getattro;
+ }
+ if (type->tp_setattr == NULL && type->tp_setattro == NULL) {
+ type->tp_setattr = base->tp_setattr;
+ type->tp_setattro = base->tp_setattro;
+ }
+ /* tp_compare see tp_richcompare */
+ COPYSLOT(tp_repr);
+ /* tp_hash see tp_richcompare */
+ COPYSLOT(tp_call);
+ COPYSLOT(tp_str);
+ if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_RICHCOMPARE) {
+ if (type->tp_compare == NULL &&
+ type->tp_richcompare == NULL &&
+ type->tp_hash == NULL)
+ {
+ type->tp_compare = base->tp_compare;
+ type->tp_richcompare = base->tp_richcompare;
+ type->tp_hash = base->tp_hash;
+ /* Check for changes to inherited methods in Py3k*/
+ if (Py_Py3kWarningFlag) {
+ if (base->tp_hash &&
+ (base->tp_hash != PyObject_HashNotImplemented) &&
+ !OVERRIDES_HASH(type)) {
+ if (OVERRIDES_EQ(type)) {
+ if (PyErr_WarnPy3k("Overriding "
+ "__eq__ blocks inheritance "
+ "of __hash__ in 3.x",
+ 1) < 0)
+ /* XXX This isn't right. If the warning is turned
+ into an exception, we should be communicating
+ the error back to the caller, but figuring out
+ how to clean up in that case is tricky. See
+ issue 8627 for more. */
+ PyErr_Clear();
+ }
+ }
+ }
+ }
+ }
+ else {
+ COPYSLOT(tp_compare);
+ }
+ if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_ITER) {
+ COPYSLOT(tp_iter);
+ COPYSLOT(tp_iternext);
+ }
+ if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_CLASS) {
+ COPYSLOT(tp_descr_get);
+ COPYSLOT(tp_descr_set);
+ COPYSLOT(tp_dictoffset);
+ COPYSLOT(tp_init);
+ COPYSLOT(tp_alloc);
+ COPYSLOT(tp_is_gc);
+ if ((type->tp_flags & Py_TPFLAGS_HAVE_GC) ==
+ (base->tp_flags & Py_TPFLAGS_HAVE_GC)) {
+ /* They agree about gc. */
+ COPYSLOT(tp_free);
+ }
+ else if ((type->tp_flags & Py_TPFLAGS_HAVE_GC) &&
+ type->tp_free == NULL &&
+ base->tp_free == _PyObject_Del) {
+ /* A bit of magic to plug in the correct default
+ * tp_free function when a derived class adds gc,
+ * didn't define tp_free, and the base uses the
+ * default non-gc tp_free.
+ */
+ type->tp_free = PyObject_GC_Del;
+ }
+ /* else they didn't agree about gc, and there isn't something
+ * obvious to be done -- the type is on its own.
+ */
+ }
+}
+
+static int add_operators(PyTypeObject *);
+
+int
+PyType_Ready(PyTypeObject *type)
+{
+ PyObject *dict, *bases;
+ PyTypeObject *base;
+ Py_ssize_t i, n;
+
+ if (type->tp_flags & Py_TPFLAGS_READY) {
+ assert(type->tp_dict != NULL);
+ return 0;
+ }
+ assert((type->tp_flags & Py_TPFLAGS_READYING) == 0);
+
+ type->tp_flags |= Py_TPFLAGS_READYING;
+
+#ifdef Py_TRACE_REFS
+ /* PyType_Ready is the closest thing we have to a choke point
+ * for type objects, so is the best place I can think of to try
+ * to get type objects into the doubly-linked list of all objects.
+ * Still, not all type objects go thru PyType_Ready.
+ */
+ _Py_AddToAllObjects((PyObject *)type, 0);
+#endif
+
+ /* Initialize tp_base (defaults to BaseObject unless that's us) */
+ base = type->tp_base;
+ if (base == NULL && type != &PyBaseObject_Type) {
+ base = type->tp_base = &PyBaseObject_Type;
+ Py_INCREF(base);
+ }
+
+ /* Now the only way base can still be NULL is if type is
+ * &PyBaseObject_Type.
+ */
+
+ /* Initialize the base class */
+ if (base && base->tp_dict == NULL) {
+ if (PyType_Ready(base) < 0)
+ goto error;
+ }
+
+ /* Initialize ob_type if NULL. This means extensions that want to be
+ compilable separately on Windows can call PyType_Ready() instead of
+ initializing the ob_type field of their type objects. */
+ /* The test for base != NULL is really unnecessary, since base is only
+ NULL when type is &PyBaseObject_Type, and we know its ob_type is
+ not NULL (it's initialized to &PyType_Type). But coverity doesn't
+ know that. */
+ if (Py_TYPE(type) == NULL && base != NULL)
+ Py_TYPE(type) = Py_TYPE(base);
+
+ /* Initialize tp_bases */
+ bases = type->tp_bases;
+ if (bases == NULL) {
+ if (base == NULL)
+ bases = PyTuple_New(0);
+ else
+ bases = PyTuple_Pack(1, base);
+ if (bases == NULL)
+ goto error;
+ type->tp_bases = bases;
+ }
+
+ /* Initialize tp_dict */
+ dict = type->tp_dict;
+ if (dict == NULL) {
+ dict = PyDict_New();
+ if (dict == NULL)
+ goto error;
+ type->tp_dict = dict;
+ }
+
+ /* Add type-specific descriptors to tp_dict */
+ if (add_operators(type) < 0)
+ goto error;
+ if (type->tp_methods != NULL) {
+ if (add_methods(type, type->tp_methods) < 0)
+ goto error;
+ }
+ if (type->tp_members != NULL) {
+ if (add_members(type, type->tp_members) < 0)
+ goto error;
+ }
+ if (type->tp_getset != NULL) {
+ if (add_getset(type, type->tp_getset) < 0)
+ goto error;
+ }
+
+ /* Calculate method resolution order */
+ if (mro_internal(type) < 0) {
+ goto error;
+ }
+
+ /* Inherit special flags from dominant base */
+ if (type->tp_base != NULL)
+ inherit_special(type, type->tp_base);
+
+ /* Initialize tp_dict properly */
+ bases = type->tp_mro;
+ assert(bases != NULL);
+ assert(PyTuple_Check(bases));
+ n = PyTuple_GET_SIZE(bases);
+ for (i = 1; i < n; i++) {
+ PyObject *b = PyTuple_GET_ITEM(bases, i);
+ if (PyType_Check(b))
+ inherit_slots(type, (PyTypeObject *)b);
+ }
+
+ /* Sanity check for tp_free. */
+ if (PyType_IS_GC(type) && (type->tp_flags & Py_TPFLAGS_BASETYPE) &&
+ (type->tp_free == NULL || type->tp_free == PyObject_Del)) {
+ /* This base class needs to call tp_free, but doesn't have
+ * one, or its tp_free is for non-gc'ed objects.
+ */
+ PyErr_Format(PyExc_TypeError, "type '%.100s' participates in "
+ "gc and is a base type but has inappropriate "
+ "tp_free slot",
+ type->tp_name);
+ goto error;
+ }
+
+ /* if the type dictionary doesn't contain a __doc__, set it from
+ the tp_doc slot.
+ */
+ if (PyDict_GetItemString(type->tp_dict, "__doc__") == NULL) {
+ if (type->tp_doc != NULL) {
+ PyObject *doc = PyString_FromString(type->tp_doc);
+ if (doc == NULL)
+ goto error;
+ PyDict_SetItemString(type->tp_dict, "__doc__", doc);
+ Py_DECREF(doc);
+ } else {
+ PyDict_SetItemString(type->tp_dict,
+ "__doc__", Py_None);
+ }
+ }
+
+ /* Some more special stuff */
+ base = type->tp_base;
+ if (base != NULL) {
+ if (type->tp_as_number == NULL)
+ type->tp_as_number = base->tp_as_number;
+ if (type->tp_as_sequence == NULL)
+ type->tp_as_sequence = base->tp_as_sequence;
+ if (type->tp_as_mapping == NULL)
+ type->tp_as_mapping = base->tp_as_mapping;
+ if (type->tp_as_buffer == NULL)
+ type->tp_as_buffer = base->tp_as_buffer;
+ }
+
+ /* Link into each base class's list of subclasses */
+ bases = type->tp_bases;
+ n = PyTuple_GET_SIZE(bases);
+ for (i = 0; i < n; i++) {
+ PyObject *b = PyTuple_GET_ITEM(bases, i);
+ if (PyType_Check(b) &&
+ add_subclass((PyTypeObject *)b, type) < 0)
+ goto error;
+ }
+
+ /* All done -- set the ready flag */
+ assert(type->tp_dict != NULL);
+ type->tp_flags =
+ (type->tp_flags & ~Py_TPFLAGS_READYING) | Py_TPFLAGS_READY;
+ return 0;
+
+ error:
+ type->tp_flags &= ~Py_TPFLAGS_READYING;
+ return -1;
+}
+
+static int
+add_subclass(PyTypeObject *base, PyTypeObject *type)
+{
+ Py_ssize_t i;
+ int result;
+ PyObject *list, *ref, *newobj;
+
+ list = base->tp_subclasses;
+ if (list == NULL) {
+ base->tp_subclasses = list = PyList_New(0);
+ if (list == NULL)
+ return -1;
+ }
+ assert(PyList_Check(list));
+ newobj = PyWeakref_NewRef((PyObject *)type, NULL);
+ i = PyList_GET_SIZE(list);
+ while (--i >= 0) {
+ ref = PyList_GET_ITEM(list, i);
+ assert(PyWeakref_CheckRef(ref));
+ if (PyWeakref_GET_OBJECT(ref) == Py_None)
+ return PyList_SetItem(list, i, newobj);
+ }
+ result = PyList_Append(list, newobj);
+ Py_DECREF(newobj);
+ return result;
+}
+
+static void
+remove_subclass(PyTypeObject *base, PyTypeObject *type)
+{
+ Py_ssize_t i;
+ PyObject *list, *ref;
+
+ list = base->tp_subclasses;
+ if (list == NULL) {
+ return;
+ }
+ assert(PyList_Check(list));
+ i = PyList_GET_SIZE(list);
+ while (--i >= 0) {
+ ref = PyList_GET_ITEM(list, i);
+ assert(PyWeakref_CheckRef(ref));
+ if (PyWeakref_GET_OBJECT(ref) == (PyObject*)type) {
+ /* this can't fail, right? */
+ PySequence_DelItem(list, i);
+ return;
+ }
+ }
+}
+
+static int
+check_num_args(PyObject *ob, int n)
+{
+ if (!PyTuple_CheckExact(ob)) {
+ PyErr_SetString(PyExc_SystemError,
+ "PyArg_UnpackTuple() argument list is not a tuple");
+ return 0;
+ }
+ if (n == PyTuple_GET_SIZE(ob))
+ return 1;
+ PyErr_Format(
+ PyExc_TypeError,
+ "expected %d arguments, got %zd", n, PyTuple_GET_SIZE(ob));
+ return 0;
+}
+
+/* Generic wrappers for overloadable 'operators' such as __getitem__ */
+
+/* There's a wrapper *function* for each distinct function typedef used
+ for type object slots (e.g. binaryfunc, ternaryfunc, etc.). There's a
+ wrapper *table* for each distinct operation (e.g. __len__, __add__).
+ Most tables have only one entry; the tables for binary operators have two
+ entries, one regular and one with reversed arguments. */
+
+static PyObject *
+wrap_lenfunc(PyObject *self, PyObject *args, void *wrapped)
+{
+ lenfunc func = (lenfunc)wrapped;
+ Py_ssize_t res;
+
+ if (!check_num_args(args, 0))
+ return NULL;
+ res = (*func)(self);
+ if (res == -1 && PyErr_Occurred())
+ return NULL;
+ return PyInt_FromLong((long)res);
+}
+
+static PyObject *
+wrap_inquirypred(PyObject *self, PyObject *args, void *wrapped)
+{
+ inquiry func = (inquiry)wrapped;
+ int res;
+
+ if (!check_num_args(args, 0))
+ return NULL;
+ res = (*func)(self);
+ if (res == -1 && PyErr_Occurred())
+ return NULL;
+ return PyBool_FromLong((long)res);
+}
+
+static PyObject *
+wrap_binaryfunc(PyObject *self, PyObject *args, void *wrapped)
+{
+ binaryfunc func = (binaryfunc)wrapped;
+ PyObject *other;
+
+ if (!check_num_args(args, 1))
+ return NULL;
+ other = PyTuple_GET_ITEM(args, 0);
+ return (*func)(self, other);
+}
+
+static PyObject *
+wrap_binaryfunc_l(PyObject *self, PyObject *args, void *wrapped)
+{
+ binaryfunc func = (binaryfunc)wrapped;
+ PyObject *other;
+
+ if (!check_num_args(args, 1))
+ return NULL;
+ other = PyTuple_GET_ITEM(args, 0);
+ if (!(self->ob_type->tp_flags & Py_TPFLAGS_CHECKTYPES) &&
+ !PyType_IsSubtype(other->ob_type, self->ob_type)) {
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+ return (*func)(self, other);
+}
+
+static PyObject *
+wrap_binaryfunc_r(PyObject *self, PyObject *args, void *wrapped)
+{
+ binaryfunc func = (binaryfunc)wrapped;
+ PyObject *other;
+
+ if (!check_num_args(args, 1))
+ return NULL;
+ other = PyTuple_GET_ITEM(args, 0);
+ if (!(self->ob_type->tp_flags & Py_TPFLAGS_CHECKTYPES) &&
+ !PyType_IsSubtype(other->ob_type, self->ob_type)) {
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+ return (*func)(other, self);
+}
+
+static PyObject *
+wrap_coercefunc(PyObject *self, PyObject *args, void *wrapped)
+{
+ coercion func = (coercion)wrapped;
+ PyObject *other, *res;
+ int ok;
+
+ if (!check_num_args(args, 1))
+ return NULL;
+ other = PyTuple_GET_ITEM(args, 0);
+ ok = func(&self, &other);
+ if (ok < 0)
+ return NULL;
+ if (ok > 0) {
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+ res = PyTuple_New(2);
+ if (res == NULL) {
+ Py_DECREF(self);
+ Py_DECREF(other);
+ return NULL;
+ }
+ PyTuple_SET_ITEM(res, 0, self);
+ PyTuple_SET_ITEM(res, 1, other);
+ return res;
+}
+
+static PyObject *
+wrap_ternaryfunc(PyObject *self, PyObject *args, void *wrapped)
+{
+ ternaryfunc func = (ternaryfunc)wrapped;
+ PyObject *other;
+ PyObject *third = Py_None;
+
+ /* Note: This wrapper only works for __pow__() */
+
+ if (!PyArg_UnpackTuple(args, "", 1, 2, &other, &third))
+ return NULL;
+ return (*func)(self, other, third);
+}
+
+static PyObject *
+wrap_ternaryfunc_r(PyObject *self, PyObject *args, void *wrapped)
+{
+ ternaryfunc func = (ternaryfunc)wrapped;
+ PyObject *other;
+ PyObject *third = Py_None;
+
+ /* Note: This wrapper only works for __pow__() */
+
+ if (!PyArg_UnpackTuple(args, "", 1, 2, &other, &third))
+ return NULL;
+ return (*func)(other, self, third);
+}
+
+static PyObject *
+wrap_unaryfunc(PyObject *self, PyObject *args, void *wrapped)
+{
+ unaryfunc func = (unaryfunc)wrapped;
+
+ if (!check_num_args(args, 0))
+ return NULL;
+ return (*func)(self);
+}
+
+static PyObject *
+wrap_indexargfunc(PyObject *self, PyObject *args, void *wrapped)
+{
+ ssizeargfunc func = (ssizeargfunc)wrapped;
+ PyObject* o;
+ Py_ssize_t i;
+
+ if (!PyArg_UnpackTuple(args, "", 1, 1, &o))
+ return NULL;
+ i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
+ if (i == -1 && PyErr_Occurred())
+ return NULL;
+ return (*func)(self, i);
+}
+
+static Py_ssize_t
+getindex(PyObject *self, PyObject *arg)
+{
+ Py_ssize_t i;
+
+ i = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
+ if (i == -1 && PyErr_Occurred())
+ return -1;
+ if (i < 0) {
+ PySequenceMethods *sq = Py_TYPE(self)->tp_as_sequence;
+ if (sq && sq->sq_length) {
+ Py_ssize_t n = (*sq->sq_length)(self);
+ if (n < 0)
+ return -1;
+ i += n;
+ }
+ }
+ return i;
+}
+
+static PyObject *
+wrap_sq_item(PyObject *self, PyObject *args, void *wrapped)
+{
+ ssizeargfunc func = (ssizeargfunc)wrapped;
+ PyObject *arg;
+ Py_ssize_t i;
+
+ if (PyTuple_GET_SIZE(args) == 1) {
+ arg = PyTuple_GET_ITEM(args, 0);
+ i = getindex(self, arg);
+ if (i == -1 && PyErr_Occurred())
+ return NULL;
+ return (*func)(self, i);
+ }
+ check_num_args(args, 1);
+ assert(PyErr_Occurred());
+ return NULL;
+}
+
+static PyObject *
+wrap_ssizessizeargfunc(PyObject *self, PyObject *args, void *wrapped)
+{
+ ssizessizeargfunc func = (ssizessizeargfunc)wrapped;
+ Py_ssize_t i, j;
+
+ if (!PyArg_ParseTuple(args, "nn", &i, &j))
+ return NULL;
+ return (*func)(self, i, j);
+}
+
+static PyObject *
+wrap_sq_setitem(PyObject *self, PyObject *args, void *wrapped)
+{
+ ssizeobjargproc func = (ssizeobjargproc)wrapped;
+ Py_ssize_t i;
+ int res;
+ PyObject *arg, *value;
+
+ if (!PyArg_UnpackTuple(args, "", 2, 2, &arg, &value))
+ return NULL;
+ i = getindex(self, arg);
+ if (i == -1 && PyErr_Occurred())
+ return NULL;
+ res = (*func)(self, i, value);
+ if (res == -1 && PyErr_Occurred())
+ return NULL;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+wrap_sq_delitem(PyObject *self, PyObject *args, void *wrapped)
+{
+ ssizeobjargproc func = (ssizeobjargproc)wrapped;
+ Py_ssize_t i;
+ int res;
+ PyObject *arg;
+
+ if (!check_num_args(args, 1))
+ return NULL;
+ arg = PyTuple_GET_ITEM(args, 0);
+ i = getindex(self, arg);
+ if (i == -1 && PyErr_Occurred())
+ return NULL;
+ res = (*func)(self, i, NULL);
+ if (res == -1 && PyErr_Occurred())
+ return NULL;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+wrap_ssizessizeobjargproc(PyObject *self, PyObject *args, void *wrapped)
+{
+ ssizessizeobjargproc func = (ssizessizeobjargproc)wrapped;
+ Py_ssize_t i, j;
+ int res;
+ PyObject *value;
+
+ if (!PyArg_ParseTuple(args, "nnO", &i, &j, &value))
+ return NULL;
+ res = (*func)(self, i, j, value);
+ if (res == -1 && PyErr_Occurred())
+ return NULL;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+wrap_delslice(PyObject *self, PyObject *args, void *wrapped)
+{
+ ssizessizeobjargproc func = (ssizessizeobjargproc)wrapped;
+ Py_ssize_t i, j;
+ int res;
+
+ if (!PyArg_ParseTuple(args, "nn", &i, &j))
+ return NULL;
+ res = (*func)(self, i, j, NULL);
+ if (res == -1 && PyErr_Occurred())
+ return NULL;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* XXX objobjproc is a misnomer; should be objargpred */
+static PyObject *
+wrap_objobjproc(PyObject *self, PyObject *args, void *wrapped)
+{
+ objobjproc func = (objobjproc)wrapped;
+ int res;
+ PyObject *value;
+
+ if (!check_num_args(args, 1))
+ return NULL;
+ value = PyTuple_GET_ITEM(args, 0);
+ res = (*func)(self, value);
+ if (res == -1 && PyErr_Occurred())
+ return NULL;
+ else
+ return PyBool_FromLong(res);
+}
+
+static PyObject *
+wrap_objobjargproc(PyObject *self, PyObject *args, void *wrapped)
+{
+ objobjargproc func = (objobjargproc)wrapped;
+ int res;
+ PyObject *key, *value;
+
+ if (!PyArg_UnpackTuple(args, "", 2, 2, &key, &value))
+ return NULL;
+ res = (*func)(self, key, value);
+ if (res == -1 && PyErr_Occurred())
+ return NULL;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+wrap_delitem(PyObject *self, PyObject *args, void *wrapped)
+{
+ objobjargproc func = (objobjargproc)wrapped;
+ int res;
+ PyObject *key;
+
+ if (!check_num_args(args, 1))
+ return NULL;
+ key = PyTuple_GET_ITEM(args, 0);
+ res = (*func)(self, key, NULL);
+ if (res == -1 && PyErr_Occurred())
+ return NULL;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+wrap_cmpfunc(PyObject *self, PyObject *args, void *wrapped)
+{
+ cmpfunc func = (cmpfunc)wrapped;
+ int res;
+ PyObject *other;
+
+ if (!check_num_args(args, 1))
+ return NULL;
+ other = PyTuple_GET_ITEM(args, 0);
+ if (Py_TYPE(other)->tp_compare != func &&
+ !PyType_IsSubtype(Py_TYPE(other), Py_TYPE(self))) {
+ PyErr_Format(
+ PyExc_TypeError,
+ "%s.__cmp__(x,y) requires y to be a '%s', not a '%s'",
+ Py_TYPE(self)->tp_name,
+ Py_TYPE(self)->tp_name,
+ Py_TYPE(other)->tp_name);
+ return NULL;
+ }
+ res = (*func)(self, other);
+ if (PyErr_Occurred())
+ return NULL;
+ return PyInt_FromLong((long)res);
+}
+
+/* Helper to check for object.__setattr__ or __delattr__ applied to a type.
+ This is called the Carlo Verre hack after its discoverer. */
+static int
+hackcheck(PyObject *self, setattrofunc func, char *what)
+{
+ PyTypeObject *type = Py_TYPE(self);
+ while (type && type->tp_flags & Py_TPFLAGS_HEAPTYPE)
+ type = type->tp_base;
+ /* If type is NULL now, this is a really weird type.
+ In the spirit of backwards compatibility (?), just shut up. */
+ if (type && type->tp_setattro != func) {
+ PyErr_Format(PyExc_TypeError,
+ "can't apply this %s to %s object",
+ what,
+ type->tp_name);
+ return 0;
+ }
+ return 1;
+}
+
+static PyObject *
+wrap_setattr(PyObject *self, PyObject *args, void *wrapped)
+{
+ setattrofunc func = (setattrofunc)wrapped;
+ int res;
+ PyObject *name, *value;
+
+ if (!PyArg_UnpackTuple(args, "", 2, 2, &name, &value))
+ return NULL;
+ if (!hackcheck(self, func, "__setattr__"))
+ return NULL;
+ res = (*func)(self, name, value);
+ if (res < 0)
+ return NULL;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+wrap_delattr(PyObject *self, PyObject *args, void *wrapped)
+{
+ setattrofunc func = (setattrofunc)wrapped;
+ int res;
+ PyObject *name;
+
+ if (!check_num_args(args, 1))
+ return NULL;
+ name = PyTuple_GET_ITEM(args, 0);
+ if (!hackcheck(self, func, "__delattr__"))
+ return NULL;
+ res = (*func)(self, name, NULL);
+ if (res < 0)
+ return NULL;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+wrap_hashfunc(PyObject *self, PyObject *args, void *wrapped)
+{
+ hashfunc func = (hashfunc)wrapped;
+ long res;
+
+ if (!check_num_args(args, 0))
+ return NULL;
+ res = (*func)(self);
+ if (res == -1 && PyErr_Occurred())
+ return NULL;
+ return PyInt_FromLong(res);
+}
+
+static PyObject *
+wrap_call(PyObject *self, PyObject *args, void *wrapped, PyObject *kwds)
+{
+ ternaryfunc func = (ternaryfunc)wrapped;
+
+ return (*func)(self, args, kwds);
+}
+
+static PyObject *
+wrap_richcmpfunc(PyObject *self, PyObject *args, void *wrapped, int op)
+{
+ richcmpfunc func = (richcmpfunc)wrapped;
+ PyObject *other;
+
+ if (!check_num_args(args, 1))
+ return NULL;
+ other = PyTuple_GET_ITEM(args, 0);
+ return (*func)(self, other, op);
+}
+
+#undef RICHCMP_WRAPPER
+#define RICHCMP_WRAPPER(NAME, OP) \
+static PyObject * \
+richcmp_##NAME(PyObject *self, PyObject *args, void *wrapped) \
+{ \
+ return wrap_richcmpfunc(self, args, wrapped, OP); \
+}
+
+RICHCMP_WRAPPER(lt, Py_LT)
+RICHCMP_WRAPPER(le, Py_LE)
+RICHCMP_WRAPPER(eq, Py_EQ)
+RICHCMP_WRAPPER(ne, Py_NE)
+RICHCMP_WRAPPER(gt, Py_GT)
+RICHCMP_WRAPPER(ge, Py_GE)
+
+static PyObject *
+wrap_next(PyObject *self, PyObject *args, void *wrapped)
+{
+ unaryfunc func = (unaryfunc)wrapped;
+ PyObject *res;
+
+ if (!check_num_args(args, 0))
+ return NULL;
+ res = (*func)(self);
+ if (res == NULL && !PyErr_Occurred())
+ PyErr_SetNone(PyExc_StopIteration);
+ return res;
+}
+
+static PyObject *
+wrap_descr_get(PyObject *self, PyObject *args, void *wrapped)
+{
+ descrgetfunc func = (descrgetfunc)wrapped;
+ PyObject *obj;
+ PyObject *type = NULL;
+
+ if (!PyArg_UnpackTuple(args, "", 1, 2, &obj, &type))
+ return NULL;
+ if (obj == Py_None)
+ obj = NULL;
+ if (type == Py_None)
+ type = NULL;
+ if (type == NULL &&obj == NULL) {
+ PyErr_SetString(PyExc_TypeError,
+ "__get__(None, None) is invalid");
+ return NULL;
+ }
+ return (*func)(self, obj, type);
+}
+
+static PyObject *
+wrap_descr_set(PyObject *self, PyObject *args, void *wrapped)
+{
+ descrsetfunc func = (descrsetfunc)wrapped;
+ PyObject *obj, *value;
+ int ret;
+
+ if (!PyArg_UnpackTuple(args, "", 2, 2, &obj, &value))
+ return NULL;
+ ret = (*func)(self, obj, value);
+ if (ret < 0)
+ return NULL;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+wrap_descr_delete(PyObject *self, PyObject *args, void *wrapped)
+{
+ descrsetfunc func = (descrsetfunc)wrapped;
+ PyObject *obj;
+ int ret;
+
+ if (!check_num_args(args, 1))
+ return NULL;
+ obj = PyTuple_GET_ITEM(args, 0);
+ ret = (*func)(self, obj, NULL);
+ if (ret < 0)
+ return NULL;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+wrap_init(PyObject *self, PyObject *args, void *wrapped, PyObject *kwds)
+{
+ initproc func = (initproc)wrapped;
+
+ if (func(self, args, kwds) < 0)
+ return NULL;
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject *
+tp_new_wrapper(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ PyTypeObject *type, *subtype, *staticbase;
+ PyObject *arg0, *res;
+
+ if (self == NULL || !PyType_Check(self))
+ Py_FatalError("__new__() called with non-type 'self'");
+ type = (PyTypeObject *)self;
+ if (!PyTuple_Check(args) || PyTuple_GET_SIZE(args) < 1) {
+ PyErr_Format(PyExc_TypeError,
+ "%s.__new__(): not enough arguments",
+ type->tp_name);
+ return NULL;
+ }
+ arg0 = PyTuple_GET_ITEM(args, 0);
+ if (!PyType_Check(arg0)) {
+ PyErr_Format(PyExc_TypeError,
+ "%s.__new__(X): X is not a type object (%s)",
+ type->tp_name,
+ Py_TYPE(arg0)->tp_name);
+ return NULL;
+ }
+ subtype = (PyTypeObject *)arg0;
+ if (!PyType_IsSubtype(subtype, type)) {
+ PyErr_Format(PyExc_TypeError,
+ "%s.__new__(%s): %s is not a subtype of %s",
+ type->tp_name,
+ subtype->tp_name,
+ subtype->tp_name,
+ type->tp_name);
+ return NULL;
+ }
+
+ /* Check that the use doesn't do something silly and unsafe like
+ object.__new__(dict). To do this, we check that the
+ most derived base that's not a heap type is this type. */
+ staticbase = subtype;
+ while (staticbase && (staticbase->tp_flags & Py_TPFLAGS_HEAPTYPE))
+ staticbase = staticbase->tp_base;
+ /* If staticbase is NULL now, it is a really weird type.
+ In the spirit of backwards compatibility (?), just shut up. */
+ if (staticbase && staticbase->tp_new != type->tp_new) {
+ PyErr_Format(PyExc_TypeError,
+ "%s.__new__(%s) is not safe, use %s.__new__()",
+ type->tp_name,
+ subtype->tp_name,
+ staticbase == NULL ? "?" : staticbase->tp_name);
+ return NULL;
+ }
+
+ args = PyTuple_GetSlice(args, 1, PyTuple_GET_SIZE(args));
+ if (args == NULL)
+ return NULL;
+ res = type->tp_new(subtype, args, kwds);
+ Py_DECREF(args);
+ return res;
+}
+
+static struct PyMethodDef tp_new_methoddef[] = {
+ {"__new__", (PyCFunction)tp_new_wrapper, METH_VARARGS|METH_KEYWORDS,
+ PyDoc_STR("T.__new__(S, ...) -> "
+ "a new object with type S, a subtype of T")},
+ {0}
+};
+
+static int
+add_tp_new_wrapper(PyTypeObject *type)
+{
+ PyObject *func;
+
+ if (PyDict_GetItemString(type->tp_dict, "__new__") != NULL)
+ return 0;
+ func = PyCFunction_New(tp_new_methoddef, (PyObject *)type);
+ if (func == NULL)
+ return -1;
+ if (PyDict_SetItemString(type->tp_dict, "__new__", func)) {
+ Py_DECREF(func);
+ return -1;
+ }
+ Py_DECREF(func);
+ return 0;
+}
+
+/* Slot wrappers that call the corresponding __foo__ slot. See comments
+ below at override_slots() for more explanation. */
+
+#define SLOT0(FUNCNAME, OPSTR) \
+static PyObject * \
+FUNCNAME(PyObject *self) \
+{ \
+ static PyObject *cache_str; \
+ return call_method(self, OPSTR, &cache_str, "()"); \
+}
+
+#define SLOT1(FUNCNAME, OPSTR, ARG1TYPE, ARGCODES) \
+static PyObject * \
+FUNCNAME(PyObject *self, ARG1TYPE arg1) \
+{ \
+ static PyObject *cache_str; \
+ return call_method(self, OPSTR, &cache_str, "(" ARGCODES ")", arg1); \
+}
+
+/* Boolean helper for SLOT1BINFULL().
+ right.__class__ is a nontrivial subclass of left.__class__. */
+static int
+method_is_overloaded(PyObject *left, PyObject *right, char *name)
+{
+ PyObject *a, *b;
+ int ok;
+
+ b = PyObject_GetAttrString((PyObject *)(Py_TYPE(right)), name);
+ if (b == NULL) {
+ PyErr_Clear();
+ /* If right doesn't have it, it's not overloaded */
+ return 0;
+ }
+
+ a = PyObject_GetAttrString((PyObject *)(Py_TYPE(left)), name);
+ if (a == NULL) {
+ PyErr_Clear();
+ Py_DECREF(b);
+ /* If right has it but left doesn't, it's overloaded */
+ return 1;
+ }
+
+ ok = PyObject_RichCompareBool(a, b, Py_NE);
+ Py_DECREF(a);
+ Py_DECREF(b);
+ if (ok < 0) {
+ PyErr_Clear();
+ return 0;
+ }
+
+ return ok;
+}
+
+
+#define SLOT1BINFULL(FUNCNAME, TESTFUNC, SLOTNAME, OPSTR, ROPSTR) \
+static PyObject * \
+FUNCNAME(PyObject *self, PyObject *other) \
+{ \
+ static PyObject *cache_str, *rcache_str; \
+ int do_other = Py_TYPE(self) != Py_TYPE(other) && \
+ Py_TYPE(other)->tp_as_number != NULL && \
+ Py_TYPE(other)->tp_as_number->SLOTNAME == TESTFUNC; \
+ if (Py_TYPE(self)->tp_as_number != NULL && \
+ Py_TYPE(self)->tp_as_number->SLOTNAME == TESTFUNC) { \
+ PyObject *r; \
+ if (do_other && \
+ PyType_IsSubtype(Py_TYPE(other), Py_TYPE(self)) && \
+ method_is_overloaded(self, other, ROPSTR)) { \
+ r = call_maybe( \
+ other, ROPSTR, &rcache_str, "(O)", self); \
+ if (r != Py_NotImplemented) \
+ return r; \
+ Py_DECREF(r); \
+ do_other = 0; \
+ } \
+ r = call_maybe( \
+ self, OPSTR, &cache_str, "(O)", other); \
+ if (r != Py_NotImplemented || \
+ Py_TYPE(other) == Py_TYPE(self)) \
+ return r; \
+ Py_DECREF(r); \
+ } \
+ if (do_other) { \
+ return call_maybe( \
+ other, ROPSTR, &rcache_str, "(O)", self); \
+ } \
+ Py_INCREF(Py_NotImplemented); \
+ return Py_NotImplemented; \
+}
+
+#define SLOT1BIN(FUNCNAME, SLOTNAME, OPSTR, ROPSTR) \
+ SLOT1BINFULL(FUNCNAME, FUNCNAME, SLOTNAME, OPSTR, ROPSTR)
+
+#define SLOT2(FUNCNAME, OPSTR, ARG1TYPE, ARG2TYPE, ARGCODES) \
+static PyObject * \
+FUNCNAME(PyObject *self, ARG1TYPE arg1, ARG2TYPE arg2) \
+{ \
+ static PyObject *cache_str; \
+ return call_method(self, OPSTR, &cache_str, \
+ "(" ARGCODES ")", arg1, arg2); \
+}
+
+static Py_ssize_t
+slot_sq_length(PyObject *self)
+{
+ static PyObject *len_str;
+ PyObject *res = call_method(self, "__len__", &len_str, "()");
+ Py_ssize_t len;
+
+ if (res == NULL)
+ return -1;
+ len = PyInt_AsSsize_t(res);
+ Py_DECREF(res);
+ if (len < 0) {
+ if (!PyErr_Occurred())
+ PyErr_SetString(PyExc_ValueError,
+ "__len__() should return >= 0");
+ return -1;
+ }
+ return len;
+}
+
+/* Super-optimized version of slot_sq_item.
+ Other slots could do the same... */
+static PyObject *
+slot_sq_item(PyObject *self, Py_ssize_t i)
+{
+ static PyObject *getitem_str;
+ PyObject *func, *args = NULL, *ival = NULL, *retval = NULL;
+ descrgetfunc f;
+
+ if (getitem_str == NULL) {
+ getitem_str = PyString_InternFromString("__getitem__");
+ if (getitem_str == NULL)
+ return NULL;
+ }
+ func = _PyType_Lookup(Py_TYPE(self), getitem_str);
+ if (func != NULL) {
+ if ((f = Py_TYPE(func)->tp_descr_get) == NULL)
+ Py_INCREF(func);
+ else {
+ func = f(func, self, (PyObject *)(Py_TYPE(self)));
+ if (func == NULL) {
+ return NULL;
+ }
+ }
+ ival = PyInt_FromSsize_t(i);
+ if (ival != NULL) {
+ args = PyTuple_New(1);
+ if (args != NULL) {
+ PyTuple_SET_ITEM(args, 0, ival);
+ retval = PyObject_Call(func, args, NULL);
+ Py_XDECREF(args);
+ Py_XDECREF(func);
+ return retval;
+ }
+ }
+ }
+ else {
+ PyErr_SetObject(PyExc_AttributeError, getitem_str);
+ }
+ Py_XDECREF(args);
+ Py_XDECREF(ival);
+ Py_XDECREF(func);
+ return NULL;
+}
+
+static PyObject*
+slot_sq_slice(PyObject *self, Py_ssize_t i, Py_ssize_t j)
+{
+ static PyObject *getslice_str;
+
+ if (PyErr_WarnPy3k("in 3.x, __getslice__ has been removed; "
+ "use __getitem__", 1) < 0)
+ return NULL;
+ return call_method(self, "__getslice__", &getslice_str,
+ "nn", i, j);
+}
+
+static int
+slot_sq_ass_item(PyObject *self, Py_ssize_t index, PyObject *value)
+{
+ PyObject *res;
+ static PyObject *delitem_str, *setitem_str;
+
+ if (value == NULL)
+ res = call_method(self, "__delitem__", &delitem_str,
+ "(n)", index);
+ else
+ res = call_method(self, "__setitem__", &setitem_str,
+ "(nO)", index, value);
+ if (res == NULL)
+ return -1;
+ Py_DECREF(res);
+ return 0;
+}
+
+static int
+slot_sq_ass_slice(PyObject *self, Py_ssize_t i, Py_ssize_t j, PyObject *value)
+{
+ PyObject *res;
+ static PyObject *delslice_str, *setslice_str;
+
+ if (value == NULL) {
+ if (PyErr_WarnPy3k("in 3.x, __delslice__ has been removed; "
+ "use __delitem__", 1) < 0)
+ return -1;
+ res = call_method(self, "__delslice__", &delslice_str,
+ "(nn)", i, j);
+ }
+ else {
+ if (PyErr_WarnPy3k("in 3.x, __setslice__ has been removed; "
+ "use __setitem__", 1) < 0)
+ return -1;
+ res = call_method(self, "__setslice__", &setslice_str,
+ "(nnO)", i, j, value);
+ }
+ if (res == NULL)
+ return -1;
+ Py_DECREF(res);
+ return 0;
+}
+
+static int
+slot_sq_contains(PyObject *self, PyObject *value)
+{
+ PyObject *func, *res, *args;
+ int result = -1;
+
+ static PyObject *contains_str;
+
+ func = lookup_maybe(self, "__contains__", &contains_str);
+ if (func != NULL) {
+ args = PyTuple_Pack(1, value);
+ if (args == NULL)
+ res = NULL;
+ else {
+ res = PyObject_Call(func, args, NULL);
+ Py_DECREF(args);
+ }
+ Py_DECREF(func);
+ if (res != NULL) {
+ result = PyObject_IsTrue(res);
+ Py_DECREF(res);
+ }
+ }
+ else if (! PyErr_Occurred()) {
+ /* Possible results: -1 and 1 */
+ result = (int)_PySequence_IterSearch(self, value,
+ PY_ITERSEARCH_CONTAINS);
+ }
+ return result;
+}
+
+#define slot_mp_length slot_sq_length
+
+SLOT1(slot_mp_subscript, "__getitem__", PyObject *, "O")
+
+static int
+slot_mp_ass_subscript(PyObject *self, PyObject *key, PyObject *value)
+{
+ PyObject *res;
+ static PyObject *delitem_str, *setitem_str;
+
+ if (value == NULL)
+ res = call_method(self, "__delitem__", &delitem_str,
+ "(O)", key);
+ else
+ res = call_method(self, "__setitem__", &setitem_str,
+ "(OO)", key, value);
+ if (res == NULL)
+ return -1;
+ Py_DECREF(res);
+ return 0;
+}
+
+SLOT1BIN(slot_nb_add, nb_add, "__add__", "__radd__")
+SLOT1BIN(slot_nb_subtract, nb_subtract, "__sub__", "__rsub__")
+SLOT1BIN(slot_nb_multiply, nb_multiply, "__mul__", "__rmul__")
+SLOT1BIN(slot_nb_divide, nb_divide, "__div__", "__rdiv__")
+SLOT1BIN(slot_nb_remainder, nb_remainder, "__mod__", "__rmod__")
+SLOT1BIN(slot_nb_divmod, nb_divmod, "__divmod__", "__rdivmod__")
+
+static PyObject *slot_nb_power(PyObject *, PyObject *, PyObject *);
+
+SLOT1BINFULL(slot_nb_power_binary, slot_nb_power,
+ nb_power, "__pow__", "__rpow__")
+
+static PyObject *
+slot_nb_power(PyObject *self, PyObject *other, PyObject *modulus)
+{
+ static PyObject *pow_str;
+
+ if (modulus == Py_None)
+ return slot_nb_power_binary(self, other);
+ /* Three-arg power doesn't use __rpow__. But ternary_op
+ can call this when the second argument's type uses
+ slot_nb_power, so check before calling self.__pow__. */
+ if (Py_TYPE(self)->tp_as_number != NULL &&
+ Py_TYPE(self)->tp_as_number->nb_power == slot_nb_power) {
+ return call_method(self, "__pow__", &pow_str,
+ "(OO)", other, modulus);
+ }
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+}
+
+SLOT0(slot_nb_negative, "__neg__")
+SLOT0(slot_nb_positive, "__pos__")
+SLOT0(slot_nb_absolute, "__abs__")
+
+static int
+slot_nb_nonzero(PyObject *self)
+{
+ PyObject *func, *args;
+ static PyObject *nonzero_str, *len_str;
+ int result = -1;
+ int using_len = 0;
+
+ func = lookup_maybe(self, "__nonzero__", &nonzero_str);
+ if (func == NULL) {
+ if (PyErr_Occurred())
+ return -1;
+ func = lookup_maybe(self, "__len__", &len_str);
+ if (func == NULL)
+ return PyErr_Occurred() ? -1 : 1;
+ using_len = 1;
+ }
+ args = PyTuple_New(0);
+ if (args != NULL) {
+ PyObject *temp = PyObject_Call(func, args, NULL);
+ Py_DECREF(args);
+ if (temp != NULL) {
+ if (PyInt_CheckExact(temp) || PyBool_Check(temp))
+ result = PyObject_IsTrue(temp);
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "%s should return "
+ "bool or int, returned %s",
+ (using_len ? "__len__"
+ : "__nonzero__"),
+ temp->ob_type->tp_name);
+ result = -1;
+ }
+ Py_DECREF(temp);
+ }
+ }
+ Py_DECREF(func);
+ return result;
+}
+
+
+static PyObject *
+slot_nb_index(PyObject *self)
+{
+ static PyObject *index_str;
+ return call_method(self, "__index__", &index_str, "()");
+}
+
+
+SLOT0(slot_nb_invert, "__invert__")
+SLOT1BIN(slot_nb_lshift, nb_lshift, "__lshift__", "__rlshift__")
+SLOT1BIN(slot_nb_rshift, nb_rshift, "__rshift__", "__rrshift__")
+SLOT1BIN(slot_nb_and, nb_and, "__and__", "__rand__")
+SLOT1BIN(slot_nb_xor, nb_xor, "__xor__", "__rxor__")
+SLOT1BIN(slot_nb_or, nb_or, "__or__", "__ror__")
+
+static int
+slot_nb_coerce(PyObject **a, PyObject **b)
+{
+ static PyObject *coerce_str;
+ PyObject *self = *a, *other = *b;
+
+ if (self->ob_type->tp_as_number != NULL &&
+ self->ob_type->tp_as_number->nb_coerce == slot_nb_coerce) {
+ PyObject *r;
+ r = call_maybe(
+ self, "__coerce__", &coerce_str, "(O)", other);
+ if (r == NULL)
+ return -1;
+ if (r == Py_NotImplemented) {
+ Py_DECREF(r);
+ }
+ else {
+ if (!PyTuple_Check(r) || PyTuple_GET_SIZE(r) != 2) {
+ PyErr_SetString(PyExc_TypeError,
+ "__coerce__ didn't return a 2-tuple");
+ Py_DECREF(r);
+ return -1;
+ }
+ *a = PyTuple_GET_ITEM(r, 0);
+ Py_INCREF(*a);
+ *b = PyTuple_GET_ITEM(r, 1);
+ Py_INCREF(*b);
+ Py_DECREF(r);
+ return 0;
+ }
+ }
+ if (other->ob_type->tp_as_number != NULL &&
+ other->ob_type->tp_as_number->nb_coerce == slot_nb_coerce) {
+ PyObject *r;
+ r = call_maybe(
+ other, "__coerce__", &coerce_str, "(O)", self);
+ if (r == NULL)
+ return -1;
+ if (r == Py_NotImplemented) {
+ Py_DECREF(r);
+ return 1;
+ }
+ if (!PyTuple_Check(r) || PyTuple_GET_SIZE(r) != 2) {
+ PyErr_SetString(PyExc_TypeError,
+ "__coerce__ didn't return a 2-tuple");
+ Py_DECREF(r);
+ return -1;
+ }
+ *a = PyTuple_GET_ITEM(r, 1);
+ Py_INCREF(*a);
+ *b = PyTuple_GET_ITEM(r, 0);
+ Py_INCREF(*b);
+ Py_DECREF(r);
+ return 0;
+ }
+ return 1;
+}
+
+SLOT0(slot_nb_int, "__int__")
+SLOT0(slot_nb_long, "__long__")
+SLOT0(slot_nb_float, "__float__")
+SLOT0(slot_nb_oct, "__oct__")
+SLOT0(slot_nb_hex, "__hex__")
+SLOT1(slot_nb_inplace_add, "__iadd__", PyObject *, "O")
+SLOT1(slot_nb_inplace_subtract, "__isub__", PyObject *, "O")
+SLOT1(slot_nb_inplace_multiply, "__imul__", PyObject *, "O")
+SLOT1(slot_nb_inplace_divide, "__idiv__", PyObject *, "O")
+SLOT1(slot_nb_inplace_remainder, "__imod__", PyObject *, "O")
+/* Can't use SLOT1 here, because nb_inplace_power is ternary */
+static PyObject *
+slot_nb_inplace_power(PyObject *self, PyObject * arg1, PyObject *arg2)
+{
+ static PyObject *cache_str;
+ return call_method(self, "__ipow__", &cache_str, "(" "O" ")", arg1);
+}
+SLOT1(slot_nb_inplace_lshift, "__ilshift__", PyObject *, "O")
+SLOT1(slot_nb_inplace_rshift, "__irshift__", PyObject *, "O")
+SLOT1(slot_nb_inplace_and, "__iand__", PyObject *, "O")
+SLOT1(slot_nb_inplace_xor, "__ixor__", PyObject *, "O")
+SLOT1(slot_nb_inplace_or, "__ior__", PyObject *, "O")
+SLOT1BIN(slot_nb_floor_divide, nb_floor_divide,
+ "__floordiv__", "__rfloordiv__")
+SLOT1BIN(slot_nb_true_divide, nb_true_divide, "__truediv__", "__rtruediv__")
+SLOT1(slot_nb_inplace_floor_divide, "__ifloordiv__", PyObject *, "O")
+SLOT1(slot_nb_inplace_true_divide, "__itruediv__", PyObject *, "O")
+
+static int
+half_compare(PyObject *self, PyObject *other)
+{
+ PyObject *func, *args, *res;
+ static PyObject *cmp_str;
+ Py_ssize_t c;
+
+ func = lookup_method(self, "__cmp__", &cmp_str);
+ if (func == NULL) {
+ PyErr_Clear();
+ }
+ else {
+ args = PyTuple_Pack(1, other);
+ if (args == NULL)
+ res = NULL;
+ else {
+ res = PyObject_Call(func, args, NULL);
+ Py_DECREF(args);
+ }
+ Py_DECREF(func);
+ if (res != Py_NotImplemented) {
+ if (res == NULL)
+ return -2;
+ c = PyInt_AsLong(res);
+ Py_DECREF(res);
+ if (c == -1 && PyErr_Occurred())
+ return -2;
+ return (c < 0) ? -1 : (c > 0) ? 1 : 0;
+ }
+ Py_DECREF(res);
+ }
+ return 2;
+}
+
+/* This slot is published for the benefit of try_3way_compare in object.c */
+int
+_PyObject_SlotCompare(PyObject *self, PyObject *other)
+{
+ int c;
+
+ if (Py_TYPE(self)->tp_compare == _PyObject_SlotCompare) {
+ c = half_compare(self, other);
+ if (c <= 1)
+ return c;
+ }
+ if (Py_TYPE(other)->tp_compare == _PyObject_SlotCompare) {
+ c = half_compare(other, self);
+ if (c < -1)
+ return -2;
+ if (c <= 1)
+ return -c;
+ }
+ return (void *)self < (void *)other ? -1 :
+ (void *)self > (void *)other ? 1 : 0;
+}
+
+static PyObject *
+slot_tp_repr(PyObject *self)
+{
+ PyObject *func, *res;
+ static PyObject *repr_str;
+
+ func = lookup_method(self, "__repr__", &repr_str);
+ if (func != NULL) {
+ res = PyEval_CallObject(func, NULL);
+ Py_DECREF(func);
+ return res;
+ }
+ PyErr_Clear();
+ return PyString_FromFormat("<%s object at %p>",
+ Py_TYPE(self)->tp_name, self);
+}
+
+static PyObject *
+slot_tp_str(PyObject *self)
+{
+ PyObject *func, *res;
+ static PyObject *str_str;
+
+ func = lookup_method(self, "__str__", &str_str);
+ if (func != NULL) {
+ res = PyEval_CallObject(func, NULL);
+ Py_DECREF(func);
+ return res;
+ }
+ else {
+ PyErr_Clear();
+ return slot_tp_repr(self);
+ }
+}
+
+static long
+slot_tp_hash(PyObject *self)
+{
+ PyObject *func;
+ static PyObject *hash_str, *eq_str, *cmp_str;
+ long h;
+
+ func = lookup_method(self, "__hash__", &hash_str);
+
+ if (func != NULL && func != Py_None) {
+ PyObject *res = PyEval_CallObject(func, NULL);
+ Py_DECREF(func);
+ if (res == NULL)
+ return -1;
+ if (PyLong_Check(res))
+ h = PyLong_Type.tp_hash(res);
+ else
+ h = PyInt_AsLong(res);
+ Py_DECREF(res);
+ }
+ else {
+ Py_XDECREF(func); /* may be None */
+ PyErr_Clear();
+ func = lookup_method(self, "__eq__", &eq_str);
+ if (func == NULL) {
+ PyErr_Clear();
+ func = lookup_method(self, "__cmp__", &cmp_str);
+ }
+ if (func != NULL) {
+ Py_DECREF(func);
+ return PyObject_HashNotImplemented(self);
+ }
+ PyErr_Clear();
+ h = _Py_HashPointer((void *)self);
+ }
+ if (h == -1 && !PyErr_Occurred())
+ h = -2;
+ return h;
+}
+
+static PyObject *
+slot_tp_call(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static PyObject *call_str;
+ PyObject *meth = lookup_method(self, "__call__", &call_str);
+ PyObject *res;
+
+ if (meth == NULL)
+ return NULL;
+
+ res = PyObject_Call(meth, args, kwds);
+
+ Py_DECREF(meth);
+ return res;
+}
+
+/* There are two slot dispatch functions for tp_getattro.
+
+ - slot_tp_getattro() is used when __getattribute__ is overridden
+ but no __getattr__ hook is present;
+
+ - slot_tp_getattr_hook() is used when a __getattr__ hook is present.
+
+ The code in update_one_slot() always installs slot_tp_getattr_hook(); this
+ detects the absence of __getattr__ and then installs the simpler slot if
+ necessary. */
+
+static PyObject *
+slot_tp_getattro(PyObject *self, PyObject *name)
+{
+ static PyObject *getattribute_str = NULL;
+ return call_method(self, "__getattribute__", &getattribute_str,
+ "(O)", name);
+}
+
+static PyObject *
+call_attribute(PyObject *self, PyObject *attr, PyObject *name)
+{
+ PyObject *res, *descr = NULL;
+ descrgetfunc f = Py_TYPE(attr)->tp_descr_get;
+
+ if (f != NULL) {
+ descr = f(attr, self, (PyObject *)(Py_TYPE(self)));
+ if (descr == NULL)
+ return NULL;
+ else
+ attr = descr;
+ }
+ res = PyObject_CallFunctionObjArgs(attr, name, NULL);
+ Py_XDECREF(descr);
+ return res;
+}
+
+static PyObject *
+slot_tp_getattr_hook(PyObject *self, PyObject *name)
+{
+ PyTypeObject *tp = Py_TYPE(self);
+ PyObject *getattr, *getattribute, *res;
+ static PyObject *getattribute_str = NULL;
+ static PyObject *getattr_str = NULL;
+
+ if (getattr_str == NULL) {
+ getattr_str = PyString_InternFromString("__getattr__");
+ if (getattr_str == NULL)
+ return NULL;
+ }
+ if (getattribute_str == NULL) {
+ getattribute_str =
+ PyString_InternFromString("__getattribute__");
+ if (getattribute_str == NULL)
+ return NULL;
+ }
+ /* speed hack: we could use lookup_maybe, but that would resolve the
+ method fully for each attribute lookup for classes with
+ __getattr__, even when the attribute is present. So we use
+ _PyType_Lookup and create the method only when needed, with
+ call_attribute. */
+ getattr = _PyType_Lookup(tp, getattr_str);
+ if (getattr == NULL) {
+ /* No __getattr__ hook: use a simpler dispatcher */
+ tp->tp_getattro = slot_tp_getattro;
+ return slot_tp_getattro(self, name);
+ }
+ Py_INCREF(getattr);
+ /* speed hack: we could use lookup_maybe, but that would resolve the
+ method fully for each attribute lookup for classes with
+ __getattr__, even when self has the default __getattribute__
+ method. So we use _PyType_Lookup and create the method only when
+ needed, with call_attribute. */
+ getattribute = _PyType_Lookup(tp, getattribute_str);
+ if (getattribute == NULL ||
+ (Py_TYPE(getattribute) == &PyWrapperDescr_Type &&
+ ((PyWrapperDescrObject *)getattribute)->d_wrapped ==
+ (void *)PyObject_GenericGetAttr))
+ res = PyObject_GenericGetAttr(self, name);
+ else {
+ Py_INCREF(getattribute);
+ res = call_attribute(self, getattribute, name);
+ Py_DECREF(getattribute);
+ }
+ if (res == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) {
+ PyErr_Clear();
+ res = call_attribute(self, getattr, name);
+ }
+ Py_DECREF(getattr);
+ return res;
+}
+
+static int
+slot_tp_setattro(PyObject *self, PyObject *name, PyObject *value)
+{
+ PyObject *res;
+ static PyObject *delattr_str, *setattr_str;
+
+ if (value == NULL)
+ res = call_method(self, "__delattr__", &delattr_str,
+ "(O)", name);
+ else
+ res = call_method(self, "__setattr__", &setattr_str,
+ "(OO)", name, value);
+ if (res == NULL)
+ return -1;
+ Py_DECREF(res);
+ return 0;
+}
+
+static char *name_op[] = {
+ "__lt__",
+ "__le__",
+ "__eq__",
+ "__ne__",
+ "__gt__",
+ "__ge__",
+};
+
+static PyObject *
+half_richcompare(PyObject *self, PyObject *other, int op)
+{
+ PyObject *func, *args, *res;
+ static PyObject *op_str[6];
+
+ func = lookup_method(self, name_op[op], &op_str[op]);
+ if (func == NULL) {
+ PyErr_Clear();
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+ args = PyTuple_Pack(1, other);
+ if (args == NULL)
+ res = NULL;
+ else {
+ res = PyObject_Call(func, args, NULL);
+ Py_DECREF(args);
+ }
+ Py_DECREF(func);
+ return res;
+}
+
+static PyObject *
+slot_tp_richcompare(PyObject *self, PyObject *other, int op)
+{
+ PyObject *res;
+
+ if (Py_TYPE(self)->tp_richcompare == slot_tp_richcompare) {
+ res = half_richcompare(self, other, op);
+ if (res != Py_NotImplemented)
+ return res;
+ Py_DECREF(res);
+ }
+ if (Py_TYPE(other)->tp_richcompare == slot_tp_richcompare) {
+ res = half_richcompare(other, self, _Py_SwappedOp[op]);
+ if (res != Py_NotImplemented) {
+ return res;
+ }
+ Py_DECREF(res);
+ }
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+}
+
+static PyObject *
+slot_tp_iter(PyObject *self)
+{
+ PyObject *func, *res;
+ static PyObject *iter_str, *getitem_str;
+
+ func = lookup_method(self, "__iter__", &iter_str);
+ if (func != NULL) {
+ PyObject *args;
+ args = res = PyTuple_New(0);
+ if (args != NULL) {
+ res = PyObject_Call(func, args, NULL);
+ Py_DECREF(args);
+ }
+ Py_DECREF(func);
+ return res;
+ }
+ PyErr_Clear();
+ func = lookup_method(self, "__getitem__", &getitem_str);
+ if (func == NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "'%.200s' object is not iterable",
+ Py_TYPE(self)->tp_name);
+ return NULL;
+ }
+ Py_DECREF(func);
+ return PySeqIter_New(self);
+}
+
+static PyObject *
+slot_tp_iternext(PyObject *self)
+{
+ static PyObject *next_str;
+ return call_method(self, "next", &next_str, "()");
+}
+
+static PyObject *
+slot_tp_descr_get(PyObject *self, PyObject *obj, PyObject *type)
+{
+ PyTypeObject *tp = Py_TYPE(self);
+ PyObject *get;
+ static PyObject *get_str = NULL;
+
+ if (get_str == NULL) {
+ get_str = PyString_InternFromString("__get__");
+ if (get_str == NULL)
+ return NULL;
+ }
+ get = _PyType_Lookup(tp, get_str);
+ if (get == NULL) {
+ /* Avoid further slowdowns */
+ if (tp->tp_descr_get == slot_tp_descr_get)
+ tp->tp_descr_get = NULL;
+ Py_INCREF(self);
+ return self;
+ }
+ if (obj == NULL)
+ obj = Py_None;
+ if (type == NULL)
+ type = Py_None;
+ return PyObject_CallFunctionObjArgs(get, self, obj, type, NULL);
+}
+
+static int
+slot_tp_descr_set(PyObject *self, PyObject *target, PyObject *value)
+{
+ PyObject *res;
+ static PyObject *del_str, *set_str;
+
+ if (value == NULL)
+ res = call_method(self, "__delete__", &del_str,
+ "(O)", target);
+ else
+ res = call_method(self, "__set__", &set_str,
+ "(OO)", target, value);
+ if (res == NULL)
+ return -1;
+ Py_DECREF(res);
+ return 0;
+}
+
+static int
+slot_tp_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static PyObject *init_str;
+ PyObject *meth = lookup_method(self, "__init__", &init_str);
+ PyObject *res;
+
+ if (meth == NULL)
+ return -1;
+ res = PyObject_Call(meth, args, kwds);
+ Py_DECREF(meth);
+ if (res == NULL)
+ return -1;
+ if (res != Py_None) {
+ PyErr_Format(PyExc_TypeError,
+ "__init__() should return None, not '%.200s'",
+ Py_TYPE(res)->tp_name);
+ Py_DECREF(res);
+ return -1;
+ }
+ Py_DECREF(res);
+ return 0;
+}
+
+static PyObject *
+slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ static PyObject *new_str;
+ PyObject *func;
+ PyObject *newargs, *x;
+ Py_ssize_t i, n;
+
+ if (new_str == NULL) {
+ new_str = PyString_InternFromString("__new__");
+ if (new_str == NULL)
+ return NULL;
+ }
+ func = PyObject_GetAttr((PyObject *)type, new_str);
+ if (func == NULL)
+ return NULL;
+ assert(PyTuple_Check(args));
+ n = PyTuple_GET_SIZE(args);
+ newargs = PyTuple_New(n+1);
+ if (newargs == NULL)
+ return NULL;
+ Py_INCREF(type);
+ PyTuple_SET_ITEM(newargs, 0, (PyObject *)type);
+ for (i = 0; i < n; i++) {
+ x = PyTuple_GET_ITEM(args, i);
+ Py_INCREF(x);
+ PyTuple_SET_ITEM(newargs, i+1, x);
+ }
+ x = PyObject_Call(func, newargs, kwds);
+ Py_DECREF(newargs);
+ Py_DECREF(func);
+ return x;
+}
+
+static void
+slot_tp_del(PyObject *self)
+{
+ static PyObject *del_str = NULL;
+ PyObject *del, *res;
+ PyObject *error_type, *error_value, *error_traceback;
+
+ /* Temporarily resurrect the object. */
+ assert(self->ob_refcnt == 0);
+ self->ob_refcnt = 1;
+
+ /* Save the current exception, if any. */
+ PyErr_Fetch(&error_type, &error_value, &error_traceback);
+
+ /* Execute __del__ method, if any. */
+ del = lookup_maybe(self, "__del__", &del_str);
+ if (del != NULL) {
+ res = PyEval_CallObject(del, NULL);
+ if (res == NULL)
+ PyErr_WriteUnraisable(del);
+ else
+ Py_DECREF(res);
+ Py_DECREF(del);
+ }
+
+ /* Restore the saved exception. */
+ PyErr_Restore(error_type, error_value, error_traceback);
+
+ /* Undo the temporary resurrection; can't use DECREF here, it would
+ * cause a recursive call.
+ */
+ assert(self->ob_refcnt > 0);
+ if (--self->ob_refcnt == 0)
+ return; /* this is the normal path out */
+
+ /* __del__ resurrected it! Make it look like the original Py_DECREF
+ * never happened.
+ */
+ {
+ Py_ssize_t refcnt = self->ob_refcnt;
+ _Py_NewReference(self);
+ self->ob_refcnt = refcnt;
+ }
+ assert(!PyType_IS_GC(Py_TYPE(self)) ||
+ _Py_AS_GC(self)->gc.gc_refs != _PyGC_REFS_UNTRACKED);
+ /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so
+ * we need to undo that. */
+ _Py_DEC_REFTOTAL;
+ /* If Py_TRACE_REFS, _Py_NewReference re-added self to the object
+ * chain, so no more to do there.
+ * If COUNT_ALLOCS, the original decref bumped tp_frees, and
+ * _Py_NewReference bumped tp_allocs: both of those need to be
+ * undone.
+ */
+#ifdef COUNT_ALLOCS
+ --Py_TYPE(self)->tp_frees;
+ --Py_TYPE(self)->tp_allocs;
+#endif
+}
+
+
+/* Table mapping __foo__ names to tp_foo offsets and slot_tp_foo wrapper
+ functions. The offsets here are relative to the 'PyHeapTypeObject'
+ structure, which incorporates the additional structures used for numbers,
+ sequences and mappings.
+ Note that multiple names may map to the same slot (e.g. __eq__,
+ __ne__ etc. all map to tp_richcompare) and one name may map to multiple
+ slots (e.g. __str__ affects tp_str as well as tp_repr). The table is
+ terminated with an all-zero entry. (This table is further initialized and
+ sorted in init_slotdefs() below.) */
+
+typedef struct wrapperbase slotdef;
+
+#undef TPSLOT
+#undef FLSLOT
+#undef ETSLOT
+#undef SQSLOT
+#undef MPSLOT
+#undef NBSLOT
+#undef UNSLOT
+#undef IBSLOT
+#undef BINSLOT
+#undef RBINSLOT
+
+#define TPSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
+ {NAME, offsetof(PyTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, \
+ PyDoc_STR(DOC)}
+#define FLSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC, FLAGS) \
+ {NAME, offsetof(PyTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, \
+ PyDoc_STR(DOC), FLAGS}
+#define ETSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
+ {NAME, offsetof(PyHeapTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, \
+ PyDoc_STR(DOC)}
+#define SQSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
+ ETSLOT(NAME, as_sequence.SLOT, FUNCTION, WRAPPER, DOC)
+#define MPSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
+ ETSLOT(NAME, as_mapping.SLOT, FUNCTION, WRAPPER, DOC)
+#define NBSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
+ ETSLOT(NAME, as_number.SLOT, FUNCTION, WRAPPER, DOC)
+#define UNSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
+ ETSLOT(NAME, as_number.SLOT, FUNCTION, WRAPPER, \
+ "x." NAME "() <==> " DOC)
+#define IBSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
+ ETSLOT(NAME, as_number.SLOT, FUNCTION, WRAPPER, \
+ "x." NAME "(y) <==> x" DOC "y")
+#define BINSLOT(NAME, SLOT, FUNCTION, DOC) \
+ ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_l, \
+ "x." NAME "(y) <==> x" DOC "y")
+#define RBINSLOT(NAME, SLOT, FUNCTION, DOC) \
+ ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_r, \
+ "x." NAME "(y) <==> y" DOC "x")
+#define BINSLOTNOTINFIX(NAME, SLOT, FUNCTION, DOC) \
+ ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_l, \
+ "x." NAME "(y) <==> " DOC)
+#define RBINSLOTNOTINFIX(NAME, SLOT, FUNCTION, DOC) \
+ ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_r, \
+ "x." NAME "(y) <==> " DOC)
+
+static slotdef slotdefs[] = {
+ SQSLOT("__len__", sq_length, slot_sq_length, wrap_lenfunc,
+ "x.__len__() <==> len(x)"),
+ /* Heap types defining __add__/__mul__ have sq_concat/sq_repeat == NULL.
+ The logic in abstract.c always falls back to nb_add/nb_multiply in
+ this case. Defining both the nb_* and the sq_* slots to call the
+ user-defined methods has unexpected side-effects, as shown by
+ test_descr.notimplemented() */
+ SQSLOT("__add__", sq_concat, NULL, wrap_binaryfunc,
+ "x.__add__(y) <==> x+y"),
+ SQSLOT("__mul__", sq_repeat, NULL, wrap_indexargfunc,
+ "x.__mul__(n) <==> x*n"),
+ SQSLOT("__rmul__", sq_repeat, NULL, wrap_indexargfunc,
+ "x.__rmul__(n) <==> n*x"),
+ SQSLOT("__getitem__", sq_item, slot_sq_item, wrap_sq_item,
+ "x.__getitem__(y) <==> x[y]"),
+ SQSLOT("__getslice__", sq_slice, slot_sq_slice, wrap_ssizessizeargfunc,
+ "x.__getslice__(i, j) <==> x[i:j]\n\
+ \n\
+ Use of negative indices is not supported."),
+ SQSLOT("__setitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_setitem,
+ "x.__setitem__(i, y) <==> x[i]=y"),
+ SQSLOT("__delitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_delitem,
+ "x.__delitem__(y) <==> del x[y]"),
+ SQSLOT("__setslice__", sq_ass_slice, slot_sq_ass_slice,
+ wrap_ssizessizeobjargproc,
+ "x.__setslice__(i, j, y) <==> x[i:j]=y\n\
+ \n\
+ Use of negative indices is not supported."),
+ SQSLOT("__delslice__", sq_ass_slice, slot_sq_ass_slice, wrap_delslice,
+ "x.__delslice__(i, j) <==> del x[i:j]\n\
+ \n\
+ Use of negative indices is not supported."),
+ SQSLOT("__contains__", sq_contains, slot_sq_contains, wrap_objobjproc,
+ "x.__contains__(y) <==> y in x"),
+ SQSLOT("__iadd__", sq_inplace_concat, NULL,
+ wrap_binaryfunc, "x.__iadd__(y) <==> x+=y"),
+ SQSLOT("__imul__", sq_inplace_repeat, NULL,
+ wrap_indexargfunc, "x.__imul__(y) <==> x*=y"),
+
+ MPSLOT("__len__", mp_length, slot_mp_length, wrap_lenfunc,
+ "x.__len__() <==> len(x)"),
+ MPSLOT("__getitem__", mp_subscript, slot_mp_subscript,
+ wrap_binaryfunc,
+ "x.__getitem__(y) <==> x[y]"),
+ MPSLOT("__setitem__", mp_ass_subscript, slot_mp_ass_subscript,
+ wrap_objobjargproc,
+ "x.__setitem__(i, y) <==> x[i]=y"),
+ MPSLOT("__delitem__", mp_ass_subscript, slot_mp_ass_subscript,
+ wrap_delitem,
+ "x.__delitem__(y) <==> del x[y]"),
+
+ BINSLOT("__add__", nb_add, slot_nb_add,
+ "+"),
+ RBINSLOT("__radd__", nb_add, slot_nb_add,
+ "+"),
+ BINSLOT("__sub__", nb_subtract, slot_nb_subtract,
+ "-"),
+ RBINSLOT("__rsub__", nb_subtract, slot_nb_subtract,
+ "-"),
+ BINSLOT("__mul__", nb_multiply, slot_nb_multiply,
+ "*"),
+ RBINSLOT("__rmul__", nb_multiply, slot_nb_multiply,
+ "*"),
+ BINSLOT("__div__", nb_divide, slot_nb_divide,
+ "/"),
+ RBINSLOT("__rdiv__", nb_divide, slot_nb_divide,
+ "/"),
+ BINSLOT("__mod__", nb_remainder, slot_nb_remainder,
+ "%"),
+ RBINSLOT("__rmod__", nb_remainder, slot_nb_remainder,
+ "%"),
+ BINSLOTNOTINFIX("__divmod__", nb_divmod, slot_nb_divmod,
+ "divmod(x, y)"),
+ RBINSLOTNOTINFIX("__rdivmod__", nb_divmod, slot_nb_divmod,
+ "divmod(y, x)"),
+ NBSLOT("__pow__", nb_power, slot_nb_power, wrap_ternaryfunc,
+ "x.__pow__(y[, z]) <==> pow(x, y[, z])"),
+ NBSLOT("__rpow__", nb_power, slot_nb_power, wrap_ternaryfunc_r,
+ "y.__rpow__(x[, z]) <==> pow(x, y[, z])"),
+ UNSLOT("__neg__", nb_negative, slot_nb_negative, wrap_unaryfunc, "-x"),
+ UNSLOT("__pos__", nb_positive, slot_nb_positive, wrap_unaryfunc, "+x"),
+ UNSLOT("__abs__", nb_absolute, slot_nb_absolute, wrap_unaryfunc,
+ "abs(x)"),
+ UNSLOT("__nonzero__", nb_nonzero, slot_nb_nonzero, wrap_inquirypred,
+ "x != 0"),
+ UNSLOT("__invert__", nb_invert, slot_nb_invert, wrap_unaryfunc, "~x"),
+ BINSLOT("__lshift__", nb_lshift, slot_nb_lshift, "<<"),
+ RBINSLOT("__rlshift__", nb_lshift, slot_nb_lshift, "<<"),
+ BINSLOT("__rshift__", nb_rshift, slot_nb_rshift, ">>"),
+ RBINSLOT("__rrshift__", nb_rshift, slot_nb_rshift, ">>"),
+ BINSLOT("__and__", nb_and, slot_nb_and, "&"),
+ RBINSLOT("__rand__", nb_and, slot_nb_and, "&"),
+ BINSLOT("__xor__", nb_xor, slot_nb_xor, "^"),
+ RBINSLOT("__rxor__", nb_xor, slot_nb_xor, "^"),
+ BINSLOT("__or__", nb_or, slot_nb_or, "|"),
+ RBINSLOT("__ror__", nb_or, slot_nb_or, "|"),
+ NBSLOT("__coerce__", nb_coerce, slot_nb_coerce, wrap_coercefunc,
+ "x.__coerce__(y) <==> coerce(x, y)"),
+ UNSLOT("__int__", nb_int, slot_nb_int, wrap_unaryfunc,
+ "int(x)"),
+ UNSLOT("__long__", nb_long, slot_nb_long, wrap_unaryfunc,
+ "long(x)"),
+ UNSLOT("__float__", nb_float, slot_nb_float, wrap_unaryfunc,
+ "float(x)"),
+ UNSLOT("__oct__", nb_oct, slot_nb_oct, wrap_unaryfunc,
+ "oct(x)"),
+ UNSLOT("__hex__", nb_hex, slot_nb_hex, wrap_unaryfunc,
+ "hex(x)"),
+ NBSLOT("__index__", nb_index, slot_nb_index, wrap_unaryfunc,
+ "x[y:z] <==> x[y.__index__():z.__index__()]"),
+ IBSLOT("__iadd__", nb_inplace_add, slot_nb_inplace_add,
+ wrap_binaryfunc, "+"),
+ IBSLOT("__isub__", nb_inplace_subtract, slot_nb_inplace_subtract,
+ wrap_binaryfunc, "-"),
+ IBSLOT("__imul__", nb_inplace_multiply, slot_nb_inplace_multiply,
+ wrap_binaryfunc, "*"),
+ IBSLOT("__idiv__", nb_inplace_divide, slot_nb_inplace_divide,
+ wrap_binaryfunc, "/"),
+ IBSLOT("__imod__", nb_inplace_remainder, slot_nb_inplace_remainder,
+ wrap_binaryfunc, "%"),
+ IBSLOT("__ipow__", nb_inplace_power, slot_nb_inplace_power,
+ wrap_binaryfunc, "**"),
+ IBSLOT("__ilshift__", nb_inplace_lshift, slot_nb_inplace_lshift,
+ wrap_binaryfunc, "<<"),
+ IBSLOT("__irshift__", nb_inplace_rshift, slot_nb_inplace_rshift,
+ wrap_binaryfunc, ">>"),
+ IBSLOT("__iand__", nb_inplace_and, slot_nb_inplace_and,
+ wrap_binaryfunc, "&"),
+ IBSLOT("__ixor__", nb_inplace_xor, slot_nb_inplace_xor,
+ wrap_binaryfunc, "^"),
+ IBSLOT("__ior__", nb_inplace_or, slot_nb_inplace_or,
+ wrap_binaryfunc, "|"),
+ BINSLOT("__floordiv__", nb_floor_divide, slot_nb_floor_divide, "//"),
+ RBINSLOT("__rfloordiv__", nb_floor_divide, slot_nb_floor_divide, "//"),
+ BINSLOT("__truediv__", nb_true_divide, slot_nb_true_divide, "/"),
+ RBINSLOT("__rtruediv__", nb_true_divide, slot_nb_true_divide, "/"),
+ IBSLOT("__ifloordiv__", nb_inplace_floor_divide,
+ slot_nb_inplace_floor_divide, wrap_binaryfunc, "//"),
+ IBSLOT("__itruediv__", nb_inplace_true_divide,
+ slot_nb_inplace_true_divide, wrap_binaryfunc, "/"),
+
+ TPSLOT("__str__", tp_str, slot_tp_str, wrap_unaryfunc,
+ "x.__str__() <==> str(x)"),
+ TPSLOT("__str__", tp_print, NULL, NULL, ""),
+ TPSLOT("__repr__", tp_repr, slot_tp_repr, wrap_unaryfunc,
+ "x.__repr__() <==> repr(x)"),
+ TPSLOT("__repr__", tp_print, NULL, NULL, ""),
+ TPSLOT("__cmp__", tp_compare, _PyObject_SlotCompare, wrap_cmpfunc,
+ "x.__cmp__(y) <==> cmp(x,y)"),
+ TPSLOT("__hash__", tp_hash, slot_tp_hash, wrap_hashfunc,
+ "x.__hash__() <==> hash(x)"),
+ FLSLOT("__call__", tp_call, slot_tp_call, (wrapperfunc)wrap_call,
+ "x.__call__(...) <==> x(...)", PyWrapperFlag_KEYWORDS),
+ TPSLOT("__getattribute__", tp_getattro, slot_tp_getattr_hook,
+ wrap_binaryfunc, "x.__getattribute__('name') <==> x.name"),
+ TPSLOT("__getattribute__", tp_getattr, NULL, NULL, ""),
+ TPSLOT("__getattr__", tp_getattro, slot_tp_getattr_hook, NULL, ""),
+ TPSLOT("__getattr__", tp_getattr, NULL, NULL, ""),
+ TPSLOT("__setattr__", tp_setattro, slot_tp_setattro, wrap_setattr,
+ "x.__setattr__('name', value) <==> x.name = value"),
+ TPSLOT("__setattr__", tp_setattr, NULL, NULL, ""),
+ TPSLOT("__delattr__", tp_setattro, slot_tp_setattro, wrap_delattr,
+ "x.__delattr__('name') <==> del x.name"),
+ TPSLOT("__delattr__", tp_setattr, NULL, NULL, ""),
+ TPSLOT("__lt__", tp_richcompare, slot_tp_richcompare, richcmp_lt,
+ "x.__lt__(y) <==> x<y"),
+ TPSLOT("__le__", tp_richcompare, slot_tp_richcompare, richcmp_le,
+ "x.__le__(y) <==> x<=y"),
+ TPSLOT("__eq__", tp_richcompare, slot_tp_richcompare, richcmp_eq,
+ "x.__eq__(y) <==> x==y"),
+ TPSLOT("__ne__", tp_richcompare, slot_tp_richcompare, richcmp_ne,
+ "x.__ne__(y) <==> x!=y"),
+ TPSLOT("__gt__", tp_richcompare, slot_tp_richcompare, richcmp_gt,
+ "x.__gt__(y) <==> x>y"),
+ TPSLOT("__ge__", tp_richcompare, slot_tp_richcompare, richcmp_ge,
+ "x.__ge__(y) <==> x>=y"),
+ TPSLOT("__iter__", tp_iter, slot_tp_iter, wrap_unaryfunc,
+ "x.__iter__() <==> iter(x)"),
+ TPSLOT("next", tp_iternext, slot_tp_iternext, wrap_next,
+ "x.next() -> the next value, or raise StopIteration"),
+ TPSLOT("__get__", tp_descr_get, slot_tp_descr_get, wrap_descr_get,
+ "descr.__get__(obj[, type]) -> value"),
+ TPSLOT("__set__", tp_descr_set, slot_tp_descr_set, wrap_descr_set,
+ "descr.__set__(obj, value)"),
+ TPSLOT("__delete__", tp_descr_set, slot_tp_descr_set,
+ wrap_descr_delete, "descr.__delete__(obj)"),
+ FLSLOT("__init__", tp_init, slot_tp_init, (wrapperfunc)wrap_init,
+ "x.__init__(...) initializes x; "
+ "see help(type(x)) for signature",
+ PyWrapperFlag_KEYWORDS),
+ TPSLOT("__new__", tp_new, slot_tp_new, NULL, ""),
+ TPSLOT("__del__", tp_del, slot_tp_del, NULL, ""),
+ {NULL}
+};
+
+/* Given a type pointer and an offset gotten from a slotdef entry, return a
+ pointer to the actual slot. This is not quite the same as simply adding
+ the offset to the type pointer, since it takes care to indirect through the
+ proper indirection pointer (as_buffer, etc.); it returns NULL if the
+ indirection pointer is NULL. */
+static void **
+slotptr(PyTypeObject *type, int ioffset)
+{
+ char *ptr;
+ long offset = ioffset;
+
+ /* Note: this depends on the order of the members of PyHeapTypeObject! */
+ assert(offset >= 0);
+ assert((size_t)offset < offsetof(PyHeapTypeObject, as_buffer));
+ if ((size_t)offset >= offsetof(PyHeapTypeObject, as_sequence)) {
+ ptr = (char *)type->tp_as_sequence;
+ offset -= offsetof(PyHeapTypeObject, as_sequence);
+ }
+ else if ((size_t)offset >= offsetof(PyHeapTypeObject, as_mapping)) {
+ ptr = (char *)type->tp_as_mapping;
+ offset -= offsetof(PyHeapTypeObject, as_mapping);
+ }
+ else if ((size_t)offset >= offsetof(PyHeapTypeObject, as_number)) {
+ ptr = (char *)type->tp_as_number;
+ offset -= offsetof(PyHeapTypeObject, as_number);
+ }
+ else {
+ ptr = (char *)type;
+ }
+ if (ptr != NULL)
+ ptr += offset;
+ return (void **)ptr;
+}
+
+/* Length of array of slotdef pointers used to store slots with the
+ same __name__. There should be at most MAX_EQUIV-1 slotdef entries with
+ the same __name__, for any __name__. Since that's a static property, it is
+ appropriate to declare fixed-size arrays for this. */
+#define MAX_EQUIV 10
+
+/* Return a slot pointer for a given name, but ONLY if the attribute has
+ exactly one slot function. The name must be an interned string. */
+static void **
+resolve_slotdups(PyTypeObject *type, PyObject *name)
+{
+ /* XXX Maybe this could be optimized more -- but is it worth it? */
+
+ /* pname and ptrs act as a little cache */
+ static PyObject *pname;
+ static slotdef *ptrs[MAX_EQUIV];
+ slotdef *p, **pp;
+ void **res, **ptr;
+
+ if (pname != name) {
+ /* Collect all slotdefs that match name into ptrs. */
+ pname = name;
+ pp = ptrs;
+ for (p = slotdefs; p->name_strobj; p++) {
+ if (p->name_strobj == name)
+ *pp++ = p;
+ }
+ *pp = NULL;
+ }
+
+ /* Look in all matching slots of the type; if exactly one of these has
+ a filled-in slot, return its value. Otherwise return NULL. */
+ res = NULL;
+ for (pp = ptrs; *pp; pp++) {
+ ptr = slotptr(type, (*pp)->offset);
+ if (ptr == NULL || *ptr == NULL)
+ continue;
+ if (res != NULL)
+ return NULL;
+ res = ptr;
+ }
+ return res;
+}
+
+/* Common code for update_slots_callback() and fixup_slot_dispatchers(). This
+ does some incredibly complex thinking and then sticks something into the
+ slot. (It sees if the adjacent slotdefs for the same slot have conflicting
+ interests, and then stores a generic wrapper or a specific function into
+ the slot.) Return a pointer to the next slotdef with a different offset,
+ because that's convenient for fixup_slot_dispatchers(). */
+static slotdef *
+update_one_slot(PyTypeObject *type, slotdef *p)
+{
+ PyObject *descr;
+ PyWrapperDescrObject *d;
+ void *generic = NULL, *specific = NULL;
+ int use_generic = 0;
+ int offset = p->offset;
+ void **ptr = slotptr(type, offset);
+
+ if (ptr == NULL) {
+ do {
+ ++p;
+ } while (p->offset == offset);
+ return p;
+ }
+ do {
+ descr = _PyType_Lookup(type, p->name_strobj);
+ if (descr == NULL) {
+ if (ptr == (void**)&type->tp_iternext) {
+ specific = _PyObject_NextNotImplemented;
+ }
+ continue;
+ }
+ if (Py_TYPE(descr) == &PyWrapperDescr_Type) {
+ void **tptr = resolve_slotdups(type, p->name_strobj);
+ if (tptr == NULL || tptr == ptr)
+ generic = p->function;
+ d = (PyWrapperDescrObject *)descr;
+ if (d->d_base->wrapper == p->wrapper &&
+ PyType_IsSubtype(type, d->d_type))
+ {
+ if (specific == NULL ||
+ specific == d->d_wrapped)
+ specific = d->d_wrapped;
+ else
+ use_generic = 1;
+ }
+ }
+ else if (Py_TYPE(descr) == &PyCFunction_Type &&
+ PyCFunction_GET_FUNCTION(descr) ==
+ (PyCFunction)tp_new_wrapper &&
+ ptr == (void**)&type->tp_new)
+ {
+ /* The __new__ wrapper is not a wrapper descriptor,
+ so must be special-cased differently.
+ If we don't do this, creating an instance will
+ always use slot_tp_new which will look up
+ __new__ in the MRO which will call tp_new_wrapper
+ which will look through the base classes looking
+ for a static base and call its tp_new (usually
+ PyType_GenericNew), after performing various
+ sanity checks and constructing a new argument
+ list. Cut all that nonsense short -- this speeds
+ up instance creation tremendously. */
+ specific = (void *)type->tp_new;
+ /* XXX I'm not 100% sure that there isn't a hole
+ in this reasoning that requires additional
+ sanity checks. I'll buy the first person to
+ point out a bug in this reasoning a beer. */
+ }
+ else if (descr == Py_None &&
+ ptr == (void**)&type->tp_hash) {
+ /* We specifically allow __hash__ to be set to None
+ to prevent inheritance of the default
+ implementation from object.__hash__ */
+ specific = PyObject_HashNotImplemented;
+ }
+ else {
+ use_generic = 1;
+ generic = p->function;
+ }
+ } while ((++p)->offset == offset);
+ if (specific && !use_generic)
+ *ptr = specific;
+ else
+ *ptr = generic;
+ return p;
+}
+
+/* In the type, update the slots whose slotdefs are gathered in the pp array.
+ This is a callback for update_subclasses(). */
+static int
+update_slots_callback(PyTypeObject *type, void *data)
+{
+ slotdef **pp = (slotdef **)data;
+
+ for (; *pp; pp++)
+ update_one_slot(type, *pp);
+ return 0;
+}
+
+/* Comparison function for qsort() to compare slotdefs by their offset, and
+ for equal offset by their address (to force a stable sort). */
+static int
+slotdef_cmp(const void *aa, const void *bb)
+{
+ const slotdef *a = (const slotdef *)aa, *b = (const slotdef *)bb;
+ int c = a->offset - b->offset;
+ if (c != 0)
+ return c;
+ else
+ /* Cannot use a-b, as this gives off_t,
+ which may lose precision when converted to int. */
+ return (a > b) ? 1 : (a < b) ? -1 : 0;
+}
+
+/* Initialize the slotdefs table by adding interned string objects for the
+ names and sorting the entries. */
+static void
+init_slotdefs(void)
+{
+ slotdef *p;
+ static int initialized = 0;
+
+ if (initialized)
+ return;
+ for (p = slotdefs; p->name; p++) {
+ p->name_strobj = PyString_InternFromString(p->name);
+ if (!p->name_strobj)
+ Py_FatalError("Out of memory interning slotdef names");
+ }
+ qsort((void *)slotdefs, (size_t)(p-slotdefs), sizeof(slotdef),
+ slotdef_cmp);
+ initialized = 1;
+}
+
+/* Update the slots after assignment to a class (type) attribute. */
+static int
+update_slot(PyTypeObject *type, PyObject *name)
+{
+ slotdef *ptrs[MAX_EQUIV];
+ slotdef *p;
+ slotdef **pp;
+ int offset;
+
+ /* Clear the VALID_VERSION flag of 'type' and all its
+ subclasses. This could possibly be unified with the
+ update_subclasses() recursion below, but carefully:
+ they each have their own conditions on which to stop
+ recursing into subclasses. */
+ PyType_Modified(type);
+
+ init_slotdefs();
+ pp = ptrs;
+ for (p = slotdefs; p->name; p++) {
+ /* XXX assume name is interned! */
+ if (p->name_strobj == name)
+ *pp++ = p;
+ }
+ *pp = NULL;
+ for (pp = ptrs; *pp; pp++) {
+ p = *pp;
+ offset = p->offset;
+ while (p > slotdefs && (p-1)->offset == offset)
+ --p;
+ *pp = p;
+ }
+ if (ptrs[0] == NULL)
+ return 0; /* Not an attribute that affects any slots */
+ return update_subclasses(type, name,
+ update_slots_callback, (void *)ptrs);
+}
+
+/* Store the proper functions in the slot dispatches at class (type)
+ definition time, based upon which operations the class overrides in its
+ dict. */
+static void
+fixup_slot_dispatchers(PyTypeObject *type)
+{
+ slotdef *p;
+
+ init_slotdefs();
+ for (p = slotdefs; p->name; )
+ p = update_one_slot(type, p);
+}
+
+static void
+update_all_slots(PyTypeObject* type)
+{
+ slotdef *p;
+
+ init_slotdefs();
+ for (p = slotdefs; p->name; p++) {
+ /* update_slot returns int but can't actually fail */
+ update_slot(type, p->name_strobj);
+ }
+}
+
+/* recurse_down_subclasses() and update_subclasses() are mutually
+ recursive functions to call a callback for all subclasses,
+ but refraining from recursing into subclasses that define 'name'. */
+
+static int
+update_subclasses(PyTypeObject *type, PyObject *name,
+ update_callback callback, void *data)
+{
+ if (callback(type, data) < 0)
+ return -1;
+ return recurse_down_subclasses(type, name, callback, data);
+}
+
+static int
+recurse_down_subclasses(PyTypeObject *type, PyObject *name,
+ update_callback callback, void *data)
+{
+ PyTypeObject *subclass;
+ PyObject *ref, *subclasses, *dict;
+ Py_ssize_t i, n;
+
+ subclasses = type->tp_subclasses;
+ if (subclasses == NULL)
+ return 0;
+ assert(PyList_Check(subclasses));
+ n = PyList_GET_SIZE(subclasses);
+ for (i = 0; i < n; i++) {
+ ref = PyList_GET_ITEM(subclasses, i);
+ assert(PyWeakref_CheckRef(ref));
+ subclass = (PyTypeObject *)PyWeakref_GET_OBJECT(ref);
+ assert(subclass != NULL);
+ if ((PyObject *)subclass == Py_None)
+ continue;
+ assert(PyType_Check(subclass));
+ /* Avoid recursing down into unaffected classes */
+ dict = subclass->tp_dict;
+ if (dict != NULL && PyDict_Check(dict) &&
+ PyDict_GetItem(dict, name) != NULL)
+ continue;
+ if (update_subclasses(subclass, name, callback, data) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+/* This function is called by PyType_Ready() to populate the type's
+ dictionary with method descriptors for function slots. For each
+ function slot (like tp_repr) that's defined in the type, one or more
+ corresponding descriptors are added in the type's tp_dict dictionary
+ under the appropriate name (like __repr__). Some function slots
+ cause more than one descriptor to be added (for example, the nb_add
+ slot adds both __add__ and __radd__ descriptors) and some function
+ slots compete for the same descriptor (for example both sq_item and
+ mp_subscript generate a __getitem__ descriptor).
+
+ In the latter case, the first slotdef entry encountered wins. Since
+ slotdef entries are sorted by the offset of the slot in the
+ PyHeapTypeObject, this gives us some control over disambiguating
+ between competing slots: the members of PyHeapTypeObject are listed
+ from most general to least general, so the most general slot is
+ preferred. In particular, because as_mapping comes before as_sequence,
+ for a type that defines both mp_subscript and sq_item, mp_subscript
+ wins.
+
+ This only adds new descriptors and doesn't overwrite entries in
+ tp_dict that were previously defined. The descriptors contain a
+ reference to the C function they must call, so that it's safe if they
+ are copied into a subtype's __dict__ and the subtype has a different
+ C function in its slot -- calling the method defined by the
+ descriptor will call the C function that was used to create it,
+ rather than the C function present in the slot when it is called.
+ (This is important because a subtype may have a C function in the
+ slot that calls the method from the dictionary, and we want to avoid
+ infinite recursion here.) */
+
+static int
+add_operators(PyTypeObject *type)
+{
+ PyObject *dict = type->tp_dict;
+ slotdef *p;
+ PyObject *descr;
+ void **ptr;
+
+ init_slotdefs();
+ for (p = slotdefs; p->name; p++) {
+ if (p->wrapper == NULL)
+ continue;
+ ptr = slotptr(type, p->offset);
+ if (!ptr || !*ptr)
+ continue;
+ if (PyDict_GetItem(dict, p->name_strobj))
+ continue;
+ if (*ptr == PyObject_HashNotImplemented) {
+ /* Classes may prevent the inheritance of the tp_hash
+ slot by storing PyObject_HashNotImplemented in it. Make it
+ visible as a None value for the __hash__ attribute. */
+ if (PyDict_SetItem(dict, p->name_strobj, Py_None) < 0)
+ return -1;
+ }
+ else {
+ descr = PyDescr_NewWrapper(type, p, *ptr);
+ if (descr == NULL)
+ return -1;
+ if (PyDict_SetItem(dict, p->name_strobj, descr) < 0)
+ return -1;
+ Py_DECREF(descr);
+ }
+ }
+ if (type->tp_new != NULL) {
+ if (add_tp_new_wrapper(type) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+
+/* Cooperative 'super' */
+
+typedef struct {
+ PyObject_HEAD
+ PyTypeObject *type;
+ PyObject *obj;
+ PyTypeObject *obj_type;
+} superobject;
+
+static PyMemberDef super_members[] = {
+ {"__thisclass__", T_OBJECT, offsetof(superobject, type), READONLY,
+ "the class invoking super()"},
+ {"__self__", T_OBJECT, offsetof(superobject, obj), READONLY,
+ "the instance invoking super(); may be None"},
+ {"__self_class__", T_OBJECT, offsetof(superobject, obj_type), READONLY,
+ "the type of the instance invoking super(); may be None"},
+ {0}
+};
+
+static void
+super_dealloc(PyObject *self)
+{
+ superobject *su = (superobject *)self;
+
+ _PyObject_GC_UNTRACK(self);
+ Py_XDECREF(su->obj);
+ Py_XDECREF(su->type);
+ Py_XDECREF(su->obj_type);
+ Py_TYPE(self)->tp_free(self);
+}
+
+static PyObject *
+super_repr(PyObject *self)
+{
+ superobject *su = (superobject *)self;
+
+ if (su->obj_type)
+ return PyString_FromFormat(
+ "<super: <class '%s'>, <%s object>>",
+ su->type ? su->type->tp_name : "NULL",
+ su->obj_type->tp_name);
+ else
+ return PyString_FromFormat(
+ "<super: <class '%s'>, NULL>",
+ su->type ? su->type->tp_name : "NULL");
+}
+
+static PyObject *
+super_getattro(PyObject *self, PyObject *name)
+{
+ superobject *su = (superobject *)self;
+ int skip = su->obj_type == NULL;
+
+ if (!skip) {
+ /* We want __class__ to return the class of the super object
+ (i.e. super, or a subclass), not the class of su->obj. */
+ skip = (PyString_Check(name) &&
+ PyString_GET_SIZE(name) == 9 &&
+ strcmp(PyString_AS_STRING(name), "__class__") == 0);
+ }
+
+ if (!skip) {
+ PyObject *mro, *res, *tmp, *dict;
+ PyTypeObject *starttype;
+ descrgetfunc f;
+ Py_ssize_t i, n;
+
+ starttype = su->obj_type;
+ mro = starttype->tp_mro;
+
+ if (mro == NULL)
+ n = 0;
+ else {
+ assert(PyTuple_Check(mro));
+ n = PyTuple_GET_SIZE(mro);
+ }
+ for (i = 0; i < n; i++) {
+ if ((PyObject *)(su->type) == PyTuple_GET_ITEM(mro, i))
+ break;
+ }
+ i++;
+ res = NULL;
+ for (; i < n; i++) {
+ tmp = PyTuple_GET_ITEM(mro, i);
+ if (PyType_Check(tmp))
+ dict = ((PyTypeObject *)tmp)->tp_dict;
+ else if (PyClass_Check(tmp))
+ dict = ((PyClassObject *)tmp)->cl_dict;
+ else
+ continue;
+ res = PyDict_GetItem(dict, name);
+ if (res != NULL) {
+ Py_INCREF(res);
+ f = Py_TYPE(res)->tp_descr_get;
+ if (f != NULL) {
+ tmp = f(res,
+ /* Only pass 'obj' param if
+ this is instance-mode super
+ (See SF ID #743627)
+ */
+ (su->obj == (PyObject *)
+ su->obj_type
+ ? (PyObject *)NULL
+ : su->obj),
+ (PyObject *)starttype);
+ Py_DECREF(res);
+ res = tmp;
+ }
+ return res;
+ }
+ }
+ }
+ return PyObject_GenericGetAttr(self, name);
+}
+
+static PyTypeObject *
+supercheck(PyTypeObject *type, PyObject *obj)
+{
+ /* Check that a super() call makes sense. Return a type object.
+
+ obj can be a new-style class, or an instance of one:
+
+ - If it is a class, it must be a subclass of 'type'. This case is
+ used for class methods; the return value is obj.
+
+ - If it is an instance, it must be an instance of 'type'. This is
+ the normal case; the return value is obj.__class__.
+
+ But... when obj is an instance, we want to allow for the case where
+ Py_TYPE(obj) is not a subclass of type, but obj.__class__ is!
+ This will allow using super() with a proxy for obj.
+ */
+
+ /* Check for first bullet above (special case) */
+ if (PyType_Check(obj) && PyType_IsSubtype((PyTypeObject *)obj, type)) {
+ Py_INCREF(obj);
+ return (PyTypeObject *)obj;
+ }
+
+ /* Normal case */
+ if (PyType_IsSubtype(Py_TYPE(obj), type)) {
+ Py_INCREF(Py_TYPE(obj));
+ return Py_TYPE(obj);
+ }
+ else {
+ /* Try the slow way */
+ static PyObject *class_str = NULL;
+ PyObject *class_attr;
+
+ if (class_str == NULL) {
+ class_str = PyString_FromString("__class__");
+ if (class_str == NULL)
+ return NULL;
+ }
+
+ class_attr = PyObject_GetAttr(obj, class_str);
+
+ if (class_attr != NULL &&
+ PyType_Check(class_attr) &&
+ (PyTypeObject *)class_attr != Py_TYPE(obj))
+ {
+ int ok = PyType_IsSubtype(
+ (PyTypeObject *)class_attr, type);
+ if (ok)
+ return (PyTypeObject *)class_attr;
+ }
+
+ if (class_attr == NULL)
+ PyErr_Clear();
+ else
+ Py_DECREF(class_attr);
+ }
+
+ PyErr_SetString(PyExc_TypeError,
+ "super(type, obj): "
+ "obj must be an instance or subtype of type");
+ return NULL;
+}
+
+static PyObject *
+super_descr_get(PyObject *self, PyObject *obj, PyObject *type)
+{
+ superobject *su = (superobject *)self;
+ superobject *newobj;
+
+ if (obj == NULL || obj == Py_None || su->obj != NULL) {
+ /* Not binding to an object, or already bound */
+ Py_INCREF(self);
+ return self;
+ }
+ if (Py_TYPE(su) != &PySuper_Type)
+ /* If su is an instance of a (strict) subclass of super,
+ call its type */
+ return PyObject_CallFunctionObjArgs((PyObject *)Py_TYPE(su),
+ su->type, obj, NULL);
+ else {
+ /* Inline the common case */
+ PyTypeObject *obj_type = supercheck(su->type, obj);
+ if (obj_type == NULL)
+ return NULL;
+ newobj = (superobject *)PySuper_Type.tp_new(&PySuper_Type,
+ NULL, NULL);
+ if (newobj == NULL)
+ return NULL;
+ Py_INCREF(su->type);
+ Py_INCREF(obj);
+ newobj->type = su->type;
+ newobj->obj = obj;
+ newobj->obj_type = obj_type;
+ return (PyObject *)newobj;
+ }
+}
+
+static int
+super_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ superobject *su = (superobject *)self;
+ PyTypeObject *type;
+ PyObject *obj = NULL;
+ PyTypeObject *obj_type = NULL;
+
+ if (!_PyArg_NoKeywords("super", kwds))
+ return -1;
+ if (!PyArg_ParseTuple(args, "O!|O:super", &PyType_Type, &type, &obj))
+ return -1;
+ if (obj == Py_None)
+ obj = NULL;
+ if (obj != NULL) {
+ obj_type = supercheck(type, obj);
+ if (obj_type == NULL)
+ return -1;
+ Py_INCREF(obj);
+ }
+ Py_INCREF(type);
+ su->type = type;
+ su->obj = obj;
+ su->obj_type = obj_type;
+ return 0;
+}
+
+PyDoc_STRVAR(super_doc,
+"super(type) -> unbound super object\n"
+"super(type, obj) -> bound super object; requires isinstance(obj, type)\n"
+"super(type, type2) -> bound super object; requires issubclass(type2, type)\n"
+"Typical use to call a cooperative superclass method:\n"
+"class C(B):\n"
+" def meth(self, arg):\n"
+" super(C, self).meth(arg)");
+
+static int
+super_traverse(PyObject *self, visitproc visit, void *arg)
+{
+ superobject *su = (superobject *)self;
+
+ Py_VISIT(su->obj);
+ Py_VISIT(su->type);
+ Py_VISIT(su->obj_type);
+
+ return 0;
+}
+
+PyTypeObject PySuper_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ "super", /* tp_name */
+ sizeof(superobject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ super_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ super_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ super_getattro, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
+ Py_TPFLAGS_BASETYPE, /* tp_flags */
+ super_doc, /* tp_doc */
+ super_traverse, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ super_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ super_descr_get, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ super_init, /* tp_init */
+ PyType_GenericAlloc, /* tp_alloc */
+ PyType_GenericNew, /* tp_new */
+ PyObject_GC_Del, /* tp_free */
+};