[Python-checkins] CVS: python/dist/src/Objects typeobject.c,2.93,2.94

Guido van Rossum gvanrossum@users.sourceforge.net
Mon, 08 Oct 2001 08:18:29 -0700


Update of /cvsroot/python/python/dist/src/Objects
In directory usw-pr-cvs1:/tmp/cvs-serv9030/Objects

Modified Files:
	typeobject.c 
Log Message:
Keep track of a type's subclasses (subtypes), in tp_subclasses, which
is a list of weak references to types (new-style classes).  Make this
accessible to Python as the function __subclasses__ which returns a
list of types -- we don't want Python programmers to be able to
manipulate the raw list.

In order to make this possible, I also had to add weak reference
support to type objects.

This will eventually be used together with a trap on attribute
assignment for dynamic classes for a major speed-up without losing the
dynamic properties of types: when a __foo__ method is added to a
class, the class and all its subclasses will get an appropriate tp_foo
slot function.



Index: typeobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/typeobject.c,v
retrieving revision 2.93
retrieving revision 2.94
diff -C2 -d -r2.93 -r2.94
*** typeobject.c	2001/10/07 03:54:51	2.93
--- typeobject.c	2001/10/08 15:18:27	2.94
***************
*** 1119,1122 ****
--- 1119,1123 ----
  	assert(type->tp_flags & Py_TPFLAGS_HEAPTYPE);
  	_PyObject_GC_UNTRACK(type);
+ 	PyObject_ClearWeakRefs((PyObject *)type);
  	et = (etype *)type;
  	Py_XDECREF(type->tp_base);
***************
*** 1125,1128 ****
--- 1126,1130 ----
  	Py_XDECREF(type->tp_mro);
  	Py_XDECREF(type->tp_defined);
+ 	Py_XDECREF(type->tp_subclasses);
  	Py_XDECREF(et->name);
  	Py_XDECREF(et->slots);
***************
*** 1130,1136 ****
--- 1132,1168 ----
  }
  
+ static PyObject *
+ type_subclasses(PyTypeObject *type, PyObject *args_ignored)
+ {
+ 	PyObject *list, *raw, *ref;
+ 	int i, n;
+ 
+ 	list = PyList_New(0);
+ 	if (list == NULL)
+ 		return NULL;
+ 	raw = type->tp_subclasses;
+ 	if (raw == NULL)
+ 		return list;
+ 	assert(PyList_Check(raw));
+ 	n = PyList_GET_SIZE(raw);
+ 	for (i = 0; i < n; i++) {
+ 		ref = PyList_GET_ITEM(raw, i);
+ 		assert(PyWeakref_CheckRef(res));
+ 		ref = PyWeakref_GET_OBJECT(ref);
+ 		if (ref != Py_None) {
+ 			if (PyList_Append(list, ref) < 0) {
+ 				Py_DECREF(list);
+ 				return NULL;
+ 			}
+ 		}
+ 	}
+ 	return list;
+ }
+ 
  static PyMethodDef type_methods[] = {
  	{"mro", (PyCFunction)mro_external, METH_NOARGS,
  	 "mro() -> list\nreturn a type's method resolution order"},
+ 	{"__subclasses__", (PyCFunction)type_subclasses, METH_NOARGS,
+ 	 "__subclasses__() -> list of immediate subclasses"},
  	{0}
  };
***************
*** 1163,1166 ****
--- 1195,1199 ----
  	VISIT(type->tp_bases);
  	VISIT(type->tp_base);
+ 	VISIT(type->tp_subclasses);
  	VISIT(et->slots);
  
***************
*** 1193,1196 ****
--- 1226,1230 ----
  	CLEAR(type->tp_bases);
  	CLEAR(type->tp_base);
+ 	CLEAR(type->tp_subclasses);
  	CLEAR(et->slots);
  
***************
*** 1238,1242 ****
  	(inquiry)type_clear,			/* tp_clear */
  	0,					/* tp_richcompare */
! 	0,					/* tp_weaklistoffset */
  	0,					/* tp_iter */
  	0,					/* tp_iternext */
--- 1272,1276 ----
  	(inquiry)type_clear,			/* tp_clear */
  	0,					/* tp_richcompare */
! 	offsetof(PyTypeObject, tp_weaklist),	/* tp_weaklistoffset */
  	0,					/* tp_iter */
  	0,					/* tp_iternext */
***************
*** 1742,1745 ****
--- 1776,1780 ----
  
  staticforward int add_operators(PyTypeObject *);
+ staticforward int add_subclass(PyTypeObject *base, PyTypeObject *type);
  
  int
***************
*** 1859,1862 ****
--- 1894,1906 ----
  	}
  
+ 	/* Link into each base class's list of subclasses */
+ 	bases = type->tp_bases;
+ 	n = PyTuple_GET_SIZE(bases);
+ 	for (i = 0; i < n; i++) {
+ 		base = (PyTypeObject *) PyTuple_GET_ITEM(bases, i);
+ 		if (add_subclass((PyTypeObject *)base, type) < 0)
+ 			goto error;
+ 	}
+ 
  	/* All done -- set the ready flag */
  	assert(type->tp_dict != NULL);
***************
*** 1868,1871 ****
--- 1912,1941 ----
  	type->tp_flags &= ~Py_TPFLAGS_READYING;
  	return -1;
+ }
+ 
+ static int
+ add_subclass(PyTypeObject *base, PyTypeObject *type)
+ {
+ 	int i;
+ 	PyObject *list, *ref, *new;
+ 
+ 	list = base->tp_subclasses;
+ 	if (list == NULL) {
+ 		base->tp_subclasses = list = PyList_New(0);
+ 		if (list == NULL)
+ 			return -1;
+ 	}
+ 	assert(PyList_Check(list));
+ 	new = PyWeakref_NewRef((PyObject *)type, NULL);
+ 	i = PyList_GET_SIZE(list);
+ 	while (--i >= 0) {
+ 		ref = PyList_GET_ITEM(list, i);
+ 		assert(PyWeakref_CheckRef(ref));
+ 		if (PyWeakref_GET_OBJECT(ref) == Py_None)
+ 			return PyList_SetItem(list, i, new);
+ 	}
+ 	i = PyList_Append(list, new);
+ 	Py_DECREF(new);
+ 	return i;
  }