summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>2001-08-17 20:32:36 (GMT)
committerGuido van Rossum <guido@python.org>2001-08-17 20:32:36 (GMT)
commit9676b22cd70ba83b8f03c5d2191892236d9dbd0d (patch)
treedb65cc51c7685ef3cdcb74f97f2d52366bc29588 /Objects
parentdbfe5e85076aaced56313fbc61642426619e4913 (diff)
downloadcpython-9676b22cd70ba83b8f03c5d2191892236d9dbd0d.zip
cpython-9676b22cd70ba83b8f03c5d2191892236d9dbd0d.tar.gz
cpython-9676b22cd70ba83b8f03c5d2191892236d9dbd0d.tar.bz2
Weak reference support, closing SF bug #451773.
Classes that don't use __slots__ have a __weakref__ member added in the same way as __dict__ is added (i.e. only if the base didn't already have one). Classes using __slots__ can enable weak referenceability by adding '__weakref__' to the __slots__ list. Renamed the __weaklistoffset__ class member to __weakrefoffset__ -- it's not always a list, it seems. (Is tp_weaklistoffset a historical misnomer, or do I misunderstand this?)
Diffstat (limited to 'Objects')
-rw-r--r--Objects/typeobject.c72
1 files changed, 51 insertions, 21 deletions
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 29cb203..c49275b 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -9,7 +9,7 @@ static struct memberlist type_members[] = {
{"__itemsize__", T_INT, offsetof(PyTypeObject, tp_itemsize), READONLY},
{"__flags__", T_LONG, offsetof(PyTypeObject, tp_flags), READONLY},
{"__doc__", T_STRING, offsetof(PyTypeObject, tp_doc), READONLY},
- {"__weaklistoffset__", T_LONG,
+ {"__weakrefoffset__", T_LONG,
offsetof(PyTypeObject, tp_weaklistoffset), READONLY},
{"__base__", T_OBJECT, offsetof(PyTypeObject, tp_base), READONLY},
{"__dictoffset__", T_LONG,
@@ -201,6 +201,7 @@ static void
subtype_dealloc(PyObject *self)
{
int dictoffset = self->ob_type->tp_dictoffset;
+ int weaklistoffset = self->ob_type->tp_weaklistoffset;
PyTypeObject *type, *base;
destructor f;
@@ -224,6 +225,10 @@ subtype_dealloc(PyObject *self)
}
}
+ /* If we added weaklist, we clear it */
+ if (weaklistoffset && !base->tp_weaklistoffset)
+ PyObject_ClearWeakRefs(self);
+
/* Finalize GC if the base doesn't do GC and we do */
if (PyType_IS_GC(type) && !PyType_IS_GC(base))
PyObject_GC_Fini(self);
@@ -455,22 +460,23 @@ best_base(PyObject *bases)
static int
extra_ivars(PyTypeObject *type, PyTypeObject *base)
{
- int t_size = PyType_BASICSIZE(type);
- int b_size = PyType_BASICSIZE(base);
+ size_t t_size = PyType_BASICSIZE(type);
+ size_t b_size = PyType_BASICSIZE(base);
- assert(t_size >= b_size); /* type smaller than base! */
+ 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 (t_size == b_size)
- return 0;
- if (type->tp_dictoffset != 0 && base->tp_dictoffset == 0 &&
- type->tp_dictoffset == b_size &&
- (size_t)t_size == b_size + sizeof(PyObject *))
- return 0; /* "Forgive" adding a __dict__ only */
- return 1;
+ if (type->tp_weaklistoffset && base->tp_weaklistoffset == 0 &&
+ type->tp_weaklistoffset + sizeof(PyObject *) == t_size)
+ t_size -= sizeof(PyObject *);
+ if (type->tp_dictoffset && base->tp_dictoffset == 0 &&
+ type->tp_dictoffset + sizeof(PyObject *) == t_size)
+ t_size -= sizeof(PyObject *);
+
+ return t_size != b_size;
}
static PyTypeObject *
@@ -500,7 +506,7 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
PyTypeObject *type, *base, *tmptype, *winner;
etype *et;
struct memberlist *mp;
- int i, nbases, nslots, slotoffset, dynamic;
+ int i, nbases, nslots, slotoffset, dynamic, add_dict, add_weak;
/* Special case: type(x) should return x->ob_type */
if (metatype == &PyType_Type &&
@@ -613,6 +619,8 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
/* Check for a __slots__ sequence variable in dict, and count it */
slots = PyDict_GetItemString(dict, "__slots__");
nslots = 0;
+ add_dict = 0;
+ add_weak = 0;
if (slots != NULL) {
/* Make it into a tuple */
if (PyString_Check(slots))
@@ -629,12 +637,19 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
Py_DECREF(slots);
return NULL;
}
+ /* XXX Check against null bytes in name */
}
}
if (slots == NULL && base->tp_dictoffset == 0 &&
(base->tp_setattro == PyObject_GenericSetAttr ||
- base->tp_setattro == NULL))
- nslots = 1;
+ base->tp_setattro == NULL)) {
+ nslots++;
+ add_dict++;
+ }
+ if (slots == NULL && base->tp_weaklistoffset == 0) {
+ nslots++;
+ add_weak++;
+ }
/* XXX From here until type is safely allocated,
"return NULL" may leak slots! */
@@ -716,16 +731,31 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
PyTuple_GET_ITEM(slots, i));
mp->type = T_OBJECT;
mp->offset = slotoffset;
+ if (base->tp_weaklistoffset == 0 &&
+ strcmp(mp->name, "__weakref__") == 0)
+ type->tp_weaklistoffset = slotoffset;
slotoffset += sizeof(PyObject *);
}
}
- else if (nslots) {
- type->tp_dictoffset = slotoffset;
- mp->name = "__dict__";
- mp->type = T_OBJECT;
- mp->offset = slotoffset;
- mp->readonly = 1;
- slotoffset += sizeof(PyObject *);
+ else {
+ if (add_dict) {
+ type->tp_dictoffset = slotoffset;
+ mp->name = "__dict__";
+ mp->type = T_OBJECT;
+ mp->offset = slotoffset;
+ mp->readonly = 1;
+ mp++;
+ slotoffset += sizeof(PyObject *);
+ }
+ if (add_weak) {
+ type->tp_weaklistoffset = slotoffset;
+ mp->name = "__weakref__";
+ mp->type = T_OBJECT;
+ mp->offset = slotoffset;
+ mp->readonly = 1;
+ mp++;
+ slotoffset += sizeof(PyObject *);
+ }
}
type->tp_basicsize = slotoffset;
type->tp_members = et->members;