mirror of https://github.com/python/cpython
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:
parent
b39903b0a0
commit
8d24ee97df
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue