summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>2001-10-11 18:33:53 (GMT)
committerGuido van Rossum <guido@python.org>2001-10-11 18:33:53 (GMT)
commit875eeaa193fd8e02d1a8b6d0d6f2768b55b0fff3 (patch)
tree815425f24c991e003a07ccd91df013ce11f2c645 /Objects
parent9e4ca10ce439845c939a9fa4264146a4cfa87fee (diff)
downloadcpython-875eeaa193fd8e02d1a8b6d0d6f2768b55b0fff3.zip
cpython-875eeaa193fd8e02d1a8b6d0d6f2768b55b0fff3.tar.gz
cpython-875eeaa193fd8e02d1a8b6d0d6f2768b55b0fff3.tar.bz2
Another step in the right direction: when a new class's attribute
corresponding to a dispatch slot (e.g. __getitem__ or __add__) is set, calculate the proper dispatch slot and propagate the change to all subclasses. Because of multiple inheritance, there's no easy way to avoid always recursing down the tree of subclasses. Who cares? (There's more to do, but this works. There's also a test for this now.)
Diffstat (limited to 'Objects')
-rw-r--r--Objects/typeobject.c149
1 files changed, 116 insertions, 33 deletions
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 1b51971..ced80ec 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -676,7 +676,7 @@ solid_base(PyTypeObject *type)
staticforward void object_dealloc(PyObject *);
staticforward int object_init(PyObject *, PyObject *, PyObject *);
-staticforward int update_slot(PyTypeObject *, PyObject *, PyObject *);
+staticforward int update_slot(PyTypeObject *, PyObject *);
staticforward void fixup_slot_dispatchers(PyTypeObject *);
static PyObject *
@@ -1107,7 +1107,7 @@ type_setattro(PyTypeObject *type, PyObject *name, PyObject *value)
if (type->tp_flags & Py_TPFLAGS_DYNAMICTYPE) {
if (PyObject_GenericSetAttr((PyObject *)type, name, value) < 0)
return -1;
- return update_slot(type, name, value);
+ return update_slot(type, name);
}
PyErr_SetString(PyExc_TypeError, "can't set static type attributes");
return -1;
@@ -3679,6 +3679,7 @@ typedef struct {
int offset;
void *function;
wrapperfunc wrapper;
+ PyObject *name_strobj;
} slotdef;
#undef TPSLOT
@@ -3797,9 +3798,7 @@ static slotdef slotdefs[] = {
slot_nb_inplace_true_divide, wrap_binaryfunc),
TPSLOT("__str__", tp_str, slot_tp_str, wrap_unaryfunc),
- TPSLOT("__str__", tp_print, NULL, NULL),
TPSLOT("__repr__", tp_repr, slot_tp_repr, wrap_unaryfunc),
- TPSLOT("__repr__", tp_print, NULL, NULL),
TPSLOT("__cmp__", tp_compare, _PyObject_SlotCompare, wrap_cmpfunc),
TPSLOT("__hash__", tp_hash, slot_tp_hash, wrap_hashfunc),
TPSLOT("__call__", tp_call, slot_tp_call, wrap_call),
@@ -3827,35 +3826,6 @@ static slotdef slotdefs[] = {
{NULL}
};
-static int
-update_slot(PyTypeObject *type, PyObject *name, PyObject *value)
-{
- char *s;
- int n;
- slotdef *p;
- void **ptr;
-
- assert(type->tp_flags & Py_TPFLAGS_HEAPTYPE);
- if (value == NULL)
- return 0; /* Can't unset a slot */
- s = PyString_AsString(name);
- n = PyString_Size(name);
- if (s == NULL || n < 0) {
- /* Shouldn't happen, but can't be bothered */
- PyErr_Clear();
- return 0;
- }
- if (!(s[0] == '_' && s[1] == '_' && s[n-1] == '_' && s[n-2] == '_'))
- return 0;
- for (p = slotdefs; p->name; p++) {
- if (!strcmp(p->name, s)) {
- ptr = (void **) ((char *)type + p->offset);
- *ptr = p->function;
- }
- }
- return 0;
-}
-
static void **
slotptr(PyTypeObject *type, int offset)
{
@@ -3883,6 +3853,119 @@ slotptr(PyTypeObject *type, int offset)
return (void **)ptr;
}
+staticforward int recurse_down_subclasses(PyTypeObject *type, int offset);
+
+static int
+update_one_slot(PyTypeObject *type, int offset)
+{
+ slotdef *p;
+ PyObject *descr;
+ PyWrapperDescrObject *d;
+ void *generic = NULL, *specific = NULL;
+ int use_generic = 0;
+ void **ptr;
+
+ for (p = slotdefs; p->name; p++) {
+ if (p->offset != offset)
+ continue;
+ descr = _PyType_Lookup(type, p->name_strobj);
+ if (descr == NULL)
+ continue;
+ ptr = slotptr(type, p->offset);
+ if (ptr == NULL)
+ continue;
+ generic = p->function;
+ if (descr->ob_type == &PyWrapperDescr_Type) {
+ 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
+ use_generic = 1;
+ if (specific && !use_generic)
+ *ptr = specific;
+ else
+ *ptr = generic;
+ }
+ if (recurse_down_subclasses(type, offset) < 0)
+ return -1;
+ return 0;
+}
+
+static int
+recurse_down_subclasses(PyTypeObject *type, int offset)
+{
+ PyTypeObject *subclass;
+ PyObject *ref, *subclasses;
+ int 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);
+ if (subclass == NULL)
+ continue;
+ assert(PyType_Check(subclass));
+ if (update_one_slot(subclass, offset) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+static void
+init_name_strobj(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("XXX ouch");
+ }
+ initialized = 1;
+}
+
+static void
+collect_offsets(PyObject *name, int offsets[])
+{
+ slotdef *p;
+
+ init_name_strobj();
+ for (p = slotdefs; p->name; p++) {
+ if (name == p->name_strobj)
+ *offsets++ = p->offset;
+ }
+ *offsets = 0;
+}
+
+static int
+update_slot(PyTypeObject *type, PyObject *name)
+{
+ int offsets[10];
+ int *ip;
+
+ collect_offsets(name, offsets);
+ for (ip = offsets; *ip; ip++) {
+ if (update_one_slot(type, *ip) < 0)
+ return -1;
+ }
+ return 0;
+}
+
static void
fixup_slot_dispatchers(PyTypeObject *type)
{