[Python-checkins] python/dist/src/Objects object.c, 2.218, 2.219 weakrefobject.c, 1.16, 1.17

fdrake at users.sourceforge.net fdrake at users.sourceforge.net
Fri Jul 2 14:57:47 EDT 2004


Update of /cvsroot/python/python/dist/src/Objects
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8493/Objects

Modified Files:
	object.c weakrefobject.c 
Log Message:
Make weak references subclassable:

- weakref.ref and weakref.ReferenceType will become aliases for each
  other

- weakref.ref will be a modern, new-style class with proper __new__
  and __init__ methods

- weakref.WeakValueDictionary will have a lighter memory footprint,
  using a new weakref.ref subclass to associate the key with the
  value, allowing us to have only a single object of overhead for each
  dictionary entry (currently, there are 3 objects of overhead per
  entry: a weakref to the value, a weakref to the dictionary, and a
  function object used as a weakref callback; the weakref to the
  dictionary could be avoided without this change)

- a new macro, PyWeakref_CheckRefExact(), will be added

- PyWeakref_CheckRef() will check for subclasses of weakref.ref

This closes SF patch #983019.


Index: object.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/object.c,v
retrieving revision 2.218
retrieving revision 2.219
diff -C2 -d -r2.218 -r2.219
*** object.c	2 Jul 2004 06:41:06 -0000	2.218
--- object.c	2 Jul 2004 18:57:44 -0000	2.219
***************
*** 1803,1806 ****
--- 1803,1809 ----
  		Py_FatalError("Can't initialize 'type'");
  
+ 	if (PyType_Ready(&_PyWeakref_RefType) < 0)
+ 		Py_FatalError("Can't initialize 'weakref'");
+ 
  	if (PyType_Ready(&PyBool_Type) < 0)
  		Py_FatalError("Can't initialize 'bool'");

Index: weakrefobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/weakrefobject.c,v
retrieving revision 1.16
retrieving revision 1.17
diff -C2 -d -r1.16 -r1.17
*** weakrefobject.c	4 Feb 2004 23:14:14 -0000	1.16
--- weakrefobject.c	2 Jul 2004 18:57:45 -0000	1.17
***************
*** 20,23 ****
--- 20,32 ----
  
  
+ static void
+ init_weakref(PyWeakReference *self, PyObject *ob, PyObject *callback)
+ {
+     self->hash = -1;
+     self->wr_object = ob;
+     Py_XINCREF(callback);
+     self->wr_callback = callback;
+ }
+ 
  static PyWeakReference *
  new_weakref(PyObject *ob, PyObject *callback)
***************
*** 27,34 ****
      result = PyObject_GC_New(PyWeakReference, &_PyWeakref_RefType);
      if (result) {
!         result->hash = -1;
!         result->wr_object = ob;
!         Py_XINCREF(callback);
!         result->wr_callback = callback;
          PyObject_GC_Track(result);
      }
--- 36,40 ----
      result = PyObject_GC_New(PyWeakReference, &_PyWeakref_RefType);
      if (result) {
!         init_weakref(result, ob, callback);
          PyObject_GC_Track(result);
      }
***************
*** 93,101 ****
  
  static void
! weakref_dealloc(PyWeakReference *self)
  {
!     PyObject_GC_UnTrack((PyObject *)self);
!     clear_weakref(self);
!     PyObject_GC_Del(self);
  }
  
--- 99,107 ----
  
  static void
! weakref_dealloc(PyObject *self)
  {
!     PyObject_GC_UnTrack(self);
!     clear_weakref((PyWeakReference *) self);
!     self->ob_type->tp_free(self);
  }
  
***************
*** 194,197 ****
--- 200,331 ----
  }
  
+ /* Given the head of an object's list of weak references, extract the
+  * two callback-less refs (ref and proxy).  Used to determine if the
+  * shared references exist and to determine the back link for newly
+  * inserted references.
+  */
+ static void
+ get_basic_refs(PyWeakReference *head,
+                PyWeakReference **refp, PyWeakReference **proxyp)
+ {
+     *refp = NULL;
+     *proxyp = NULL;
+ 
+     if (head != NULL && head->wr_callback == NULL) {
+         /* We need to be careful that the "basic refs" aren't
+            subclasses of the main types.  That complicates this a
+            little. */
+         if (PyWeakref_CheckRefExact(head)) {
+             *refp = head;
+             head = head->wr_next;
+         }
+         if (head != NULL
+             && head->wr_callback == NULL
+             && PyWeakref_CheckProxy(head)) {
+             *proxyp = head;
+             /* head = head->wr_next; */
+         }
+     }
+ }
+ 
+ /* Insert 'newref' in the list after 'prev'.  Both must be non-NULL. */
+ static void
+ insert_after(PyWeakReference *newref, PyWeakReference *prev)
+ {
+     newref->wr_prev = prev;
+     newref->wr_next = prev->wr_next;
+     if (prev->wr_next != NULL)
+         prev->wr_next->wr_prev = newref;
+     prev->wr_next = newref;
+ }
+ 
+ /* Insert 'newref' at the head of the list; 'list' points to the variable
+  * that stores the head.
+  */
+ static void
+ insert_head(PyWeakReference *newref, PyWeakReference **list)
+ {
+     PyWeakReference *next = *list;
+ 
+     newref->wr_prev = NULL;
+     newref->wr_next = next;
+     if (next != NULL)
+         next->wr_prev = newref;
+     *list = newref;
+ }
+ 
+ static int
+ parse_weakref_init_args(char *funcname, PyObject *args, PyObject *kwargs,
+                         PyObject **obp, PyObject **callbackp)
+ {
+     /* XXX Should check that kwargs == NULL or is empty. */
+     return PyArg_UnpackTuple(args, funcname, 1, 2, obp, callbackp);
+ }
+ 
+ static PyObject *
+ weakref___new__(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+ {
+     PyWeakReference *self = NULL;
+     PyObject *ob, *callback = NULL;
+ 
+     if (parse_weakref_init_args("__new__", args, kwargs, &ob, &callback)) {
+         PyWeakReference *ref, *proxy;
+         PyWeakReference **list;
+ 
+         if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) {
+             PyErr_Format(PyExc_TypeError,
+                          "cannot create weak reference to '%s' object",
+                          ob->ob_type->tp_name);
+             return NULL;
+         }
+         if (callback == Py_None)
+             callback = NULL;
+         list = GET_WEAKREFS_LISTPTR(ob);
+         get_basic_refs(*list, &ref, &proxy);
+         if (callback == NULL && type == &_PyWeakref_RefType) {
+             if (ref != NULL) {
+                 /* We can re-use an existing reference. */
+                 Py_INCREF(ref);
+                 return (PyObject *)ref;
+             }
+         }
+         /* We have to create a new reference. */
+         /* Note: the tp_alloc() can trigger cyclic GC, so the weakref
+            list on ob can be mutated.  This means that the ref and
+            proxy pointers we got back earlier may have been collected,
+            so we need to compute these values again before we use
+            them. */
+         self = (PyWeakReference *) (type->tp_alloc(type, 0));
+         if (self != NULL) {
+             init_weakref(self, ob, callback);
+             if (callback == NULL && type == &_PyWeakref_RefType) {
+                 insert_head(self, list);
+             }
+             else {
+                 PyWeakReference *prev;
+ 
+                 get_basic_refs(*list, &ref, &proxy);
+                 prev = (proxy == NULL) ? ref : proxy;
+                 if (prev == NULL)
+                     insert_head(self, list);
+                 else
+                     insert_after(self, prev);
+             }
+         }
+     }
+     return (PyObject *)self;
+ }
+ 
+ static int
+ weakref___init__(PyObject *self, PyObject *args, PyObject *kwargs)
+ {
+     PyObject *tmp;
+ 
+     if (parse_weakref_init_args("__init__", args, kwargs, &tmp, &tmp))
+         return 0;
+     else
+         return 1;
+ }
+ 
  
  PyTypeObject
***************
*** 202,206 ****
      sizeof(PyWeakReference),
      0,
!     (destructor)weakref_dealloc,/*tp_dealloc*/
      0,	                        /*tp_print*/
      0,                          /*tp_getattr*/
--- 336,340 ----
      sizeof(PyWeakReference),
      0,
!     weakref_dealloc,            /*tp_dealloc*/
      0,	                        /*tp_print*/
      0,                          /*tp_getattr*/
***************
*** 211,215 ****
      0,                          /*tp_as_sequence*/
      0,                          /*tp_as_mapping*/
!     (hashfunc)weakref_hash,      /*tp_hash*/
      (ternaryfunc)weakref_call,  /*tp_call*/
      0,                          /*tp_str*/
--- 345,349 ----
      0,                          /*tp_as_sequence*/
      0,                          /*tp_as_mapping*/
!     (hashfunc)weakref_hash,     /*tp_hash*/
      (ternaryfunc)weakref_call,  /*tp_call*/
      0,                          /*tp_str*/
***************
*** 217,226 ****
      0,                          /*tp_setattro*/
      0,                          /*tp_as_buffer*/
!     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_RICHCOMPARE,
      0,                          /*tp_doc*/
      (traverseproc)gc_traverse,  /*tp_traverse*/
      (inquiry)gc_clear,          /*tp_clear*/
      (richcmpfunc)weakref_richcompare,	/*tp_richcompare*/
!     0,				/*tp_weaklistoffset*/
  };
  
--- 351,375 ----
      0,                          /*tp_setattro*/
      0,                          /*tp_as_buffer*/
!     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_RICHCOMPARE
!         | Py_TPFLAGS_BASETYPE,  /*tp_flags*/
      0,                          /*tp_doc*/
      (traverseproc)gc_traverse,  /*tp_traverse*/
      (inquiry)gc_clear,          /*tp_clear*/
      (richcmpfunc)weakref_richcompare,	/*tp_richcompare*/
!     0,                          /*tp_weaklistoffset*/
!     0,                          /*tp_iter*/
!     0,                          /*tp_iternext*/
!     0,                          /*tp_methods*/
!     0,                          /*tp_members*/
!     0,                          /*tp_getset*/
!     0,                          /*tp_base*/
!     0,                          /*tp_dict*/
!     0,                          /*tp_descr_get*/
!     0,                          /*tp_descr_set*/
!     0,                          /*tp_dictoffset*/
!     (initproc)weakref___init__, /*tp_init*/
!     PyType_GenericAlloc,        /*tp_alloc*/
!     weakref___new__,            /*tp_new*/
!     PyObject_GC_Del,            /*tp_free*/
  };
  
***************
*** 364,367 ****
--- 513,525 ----
  }
  
+ static void
+ proxy_dealloc(PyWeakReference *self)
+ {
+     if (self->wr_callback != NULL)
+         PyObject_GC_UnTrack((PyObject *)self);
+     clear_weakref(self);
+     PyObject_GC_Del(self);
+ }
+ 
  /* sequence slots */
  
***************
*** 497,501 ****
      0,
      /* methods */
!     (destructor)weakref_dealloc,        /* tp_dealloc */
      0,				        /* tp_print */
      0,				        /* tp_getattr */
--- 655,659 ----
      0,
      /* methods */
!     (destructor)proxy_dealloc,          /* tp_dealloc */
      0,				        /* tp_print */
      0,				        /* tp_getattr */
***************
*** 532,536 ****
      0,
      /* methods */
!     (destructor)weakref_dealloc,        /* tp_dealloc */
      0,				        /* tp_print */
      0,				        /* tp_getattr */
--- 690,694 ----
      0,
      /* methods */
!     (destructor)proxy_dealloc,          /* tp_dealloc */
      0,				        /* tp_print */
      0,				        /* tp_getattr */
***************
*** 559,612 ****
  
  
- /* Given the head of an object's list of weak references, extract the
-  * two callback-less refs (ref and proxy).  Used to determine if the
-  * shared references exist and to determine the back link for newly
-  * inserted references.
-  */
- static void
- get_basic_refs(PyWeakReference *head,
-                PyWeakReference **refp, PyWeakReference **proxyp)
- {
-     *refp = NULL;
-     *proxyp = NULL;
- 
-     if (head != NULL && head->wr_callback == NULL) {
-         if (head->ob_type == &_PyWeakref_RefType) {
-             *refp = head;
-             head = head->wr_next;
-         }
-         if (head != NULL && head->wr_callback == NULL) {
-             *proxyp = head;
-             head = head->wr_next;
-         }
-     }
- }
- 
- /* Insert 'newref' in the list after 'prev'.  Both must be non-NULL. */
- static void
- insert_after(PyWeakReference *newref, PyWeakReference *prev)
- {
-     newref->wr_prev = prev;
-     newref->wr_next = prev->wr_next;
-     if (prev->wr_next != NULL)
-         prev->wr_next->wr_prev = newref;
-     prev->wr_next = newref;
- }
- 
- /* Insert 'newref' at the head of the list; 'list' points to the variable
-  * that stores the head.
-  */
- static void
- insert_head(PyWeakReference *newref, PyWeakReference **list)
- {
-     PyWeakReference *next = *list;
- 
-     newref->wr_prev = NULL;
-     newref->wr_next = next;
-     if (next != NULL)
-         next->wr_prev = newref;
-     *list = newref;
- }
- 
  
  PyObject *
--- 717,720 ----
***************
*** 770,775 ****
              current->wr_callback = NULL;
              clear_weakref(current);
!             handle_callback(current, callback);
!             Py_DECREF(callback);
          }
          else {
--- 878,885 ----
              current->wr_callback = NULL;
              clear_weakref(current);
!             if (callback != NULL) {
!                 handle_callback(current, callback);
!                 Py_DECREF(callback);
!             }
          }
          else {
***************
*** 788,795 ****
              }
              for (i = 0; i < count; ++i) {
-                 PyObject *current = PyTuple_GET_ITEM(tuple, i * 2);
                  PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
  
!                 handle_callback((PyWeakReference *)current, callback);
              }
              Py_DECREF(tuple);
--- 898,907 ----
              }
              for (i = 0; i < count; ++i) {
                  PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
  
!                 if (callback != NULL) {
!                     PyObject *current = PyTuple_GET_ITEM(tuple, i * 2);
!                     handle_callback((PyWeakReference *)current, callback);
!                 }
              }
              Py_DECREF(tuple);




More information about the Python-checkins mailing list