]> granicus.if.org Git - python/commitdiff
Weak reference support, closing SF bug #451773.
authorGuido van Rossum <guido@python.org>
Fri, 17 Aug 2001 20:32:36 +0000 (20:32 +0000)
committerGuido van Rossum <guido@python.org>
Fri, 17 Aug 2001 20:32:36 +0000 (20:32 +0000)
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?)

Objects/typeobject.c

index 29cb2031c0fefc9e94d08c7c9eb392d9bb4d542b..c49275bc792d7a1ca58871a381cd6cb6a56af622 100644 (file)
@@ -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;