Refactoring: rename update_these_slots() into update_subclasses() and

generalize to take a callback function and a void * data argument.
This might come in handy later... :-)
This commit is contained in:
Guido van Rossum 2003-03-24 23:49:49 +00:00
parent b39903b0a0
commit 8d24ee97df
1 changed files with 68 additions and 47 deletions

View File

@ -130,6 +130,12 @@ static int add_subclass(PyTypeObject*, PyTypeObject*);
static void remove_subclass(PyTypeObject *, PyTypeObject *); static void remove_subclass(PyTypeObject *, PyTypeObject *);
static void update_all_slots(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 static int
mro_subclasses(PyTypeObject *type, PyObject* temp) mro_subclasses(PyTypeObject *type, PyObject* temp)
{ {
@ -2031,6 +2037,10 @@ type_setattro(PyTypeObject *type, PyObject *name, PyObject *value)
type->tp_name); type->tp_name);
return -1; return -1;
} }
/* XXX Example of how I expect this to be used...
if (update_subclasses(type, name, invalidate_cache, NULL) < 0)
return -1;
*/
if (PyObject_GenericSetAttr((PyObject *)type, name, value) < 0) if (PyObject_GenericSetAttr((PyObject *)type, name, value) < 0)
return -1; return -1;
return update_slot(type, name); return update_slot(type, name);
@ -4993,7 +5003,7 @@ resolve_slotdups(PyTypeObject *type, PyObject *name)
return res; return res;
} }
/* Common code for update_these_slots() and fixup_slot_dispatchers(). This /* Common code for update_slots_callback() and fixup_slot_dispatchers(). This
does some incredibly complex thinking and then sticks something into the does some incredibly complex thinking and then sticks something into the
slot. (It sees if the adjacent slotdefs for the same slot have conflicting 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 interests, and then stores a generic wrapper or a specific function into
@ -5068,51 +5078,15 @@ update_one_slot(PyTypeObject *type, slotdef *p)
return p; return p;
} }
static int recurse_down_subclasses(PyTypeObject *type, slotdef **pp, /* In the type, update the slots whose slotdefs are gathered in the pp array.
PyObject *name); This is a callback for update_subclasses(). */
/* In the type, update the slots whose slotdefs are gathered in the pp0 array,
and then do the same for all this type's subtypes. */
static int static int
update_these_slots(PyTypeObject *type, slotdef **pp0, PyObject *name) update_slots_callback(PyTypeObject *type, void *data)
{ {
slotdef **pp; slotdef **pp = (slotdef **)data;
for (pp = pp0; *pp; pp++) for (; *pp; pp++)
update_one_slot(type, *pp); update_one_slot(type, *pp);
return recurse_down_subclasses(type, pp0, name);
}
/* Update the slots whose slotdefs are gathered in the pp array in all (direct
or indirect) subclasses of type. */
static int
recurse_down_subclasses(PyTypeObject *type, slotdef **pp, PyObject *name)
{
PyTypeObject *subclass;
PyObject *ref, *subclasses, *dict;
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);
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_these_slots(subclass, pp, name) < 0)
return -1;
}
return 0; return 0;
} }
@ -5175,7 +5149,8 @@ update_slot(PyTypeObject *type, PyObject *name)
} }
if (ptrs[0] == NULL) if (ptrs[0] == NULL)
return 0; /* Not an attribute that affects any slots */ return 0; /* Not an attribute that affects any slots */
return update_these_slots(type, ptrs, name); return update_subclasses(type, name,
update_slots_callback, (void *)ptrs);
} }
/* Store the proper functions in the slot dispatches at class (type) /* Store the proper functions in the slot dispatches at class (type)
@ -5203,6 +5178,51 @@ update_all_slots(PyTypeObject* type)
} }
} }
/* 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;
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);
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 /* This function is called by PyType_Ready() to populate the type's
dictionary with method descriptors for function slots. For each dictionary with method descriptors for function slots. For each
function slot (like tp_repr) that's defined in the type, one or more function slot (like tp_repr) that's defined in the type, one or more
@ -5216,10 +5236,11 @@ update_all_slots(PyTypeObject* type)
In the latter case, the first slotdef entry encoutered wins. Since In the latter case, the first slotdef entry encoutered wins. Since
slotdef entries are sorted by the offset of the slot in the slotdef entries are sorted by the offset of the slot in the
PyHeapTypeObject, this gives us some control over disambiguating PyHeapTypeObject, this gives us some control over disambiguating
between competing slots: the members of PyHeapTypeObject are listed from most between competing slots: the members of PyHeapTypeObject are listed
general to least general, so the most general slot is preferred. In from most general to least general, so the most general slot is
particular, because as_mapping comes before as_sequence, for a type preferred. In particular, because as_mapping comes before as_sequence,
that defines both mp_subscript and sq_item, mp_subscript wins. 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 This only adds new descriptors and doesn't overwrite entries in
tp_dict that were previously defined. The descriptors contain a tp_dict that were previously defined. The descriptors contain a