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

Guido van Rossum gvanrossum@users.sourceforge.net
Tue, 05 Jun 2001 18:02:23 -0700


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

Modified Files:
      Tag: descr-branch
	typeobject.c 
Log Message:
A VERY preliminary of multiple inheritance.  Lots of stuff doesn't
work (hey, __bases__ doesn't even reflect the auxiliary base classes!)
but it allows me to write and test some simple mix-in classes.


Index: typeobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/typeobject.c,v
retrieving revision 2.16.8.30
retrieving revision 2.16.8.31
diff -C2 -r2.16.8.30 -r2.16.8.31
*** typeobject.c	2001/06/05 19:31:56	2.16.8.30
--- typeobject.c	2001/06/06 01:02:20	2.16.8.31
***************
*** 139,142 ****
--- 139,143 ----
  
  staticforward void override_slots(PyTypeObject *type, PyObject *dict);
+ staticforward PyTypeObject *solid_base(PyTypeObject *type);
  
  typedef struct {
***************
*** 150,153 ****
--- 151,167 ----
  } etype;
  
+ static int
+ issubtype(PyTypeObject *a, PyTypeObject *b)
+ {
+ 	if (b == &PyBaseObject_Type)
+ 		return 1; /* Every type is an implicit subtype of this */
+ 	while (a != NULL) {
+ 		if (a == b)
+ 			return 1;
+ 		a = a->tp_base;
+ 	}
+ 	return 0;
+ }
+ 
  /* TypeType's initializer; called when a type is subclassed */
  static int
***************
*** 159,163 ****
  	etype *et;
  	struct memberlist *mp;
! 	int i, nslots, slotoffset, allocsize;
  
  	assert(PyType_Check(self));
--- 173,177 ----
  	etype *et;
  	struct memberlist *mp;
! 	int i, n, nslots, slotoffset, allocsize;
  
  	assert(PyType_Check(self));
***************
*** 172,196 ****
  				"usage: TypeType(name, bases, dict) ");
  		return -1;
- 	}
- 	if (PyTuple_GET_SIZE(bases) > 1) {
- 		PyErr_SetString(PyExc_TypeError,
- 				"can't multiple-inherit from types (yet)");
- 		return -1;
  	}
! 	if (PyTuple_GET_SIZE(bases) < 1)
! 		base = &PyBaseObject_Type;
! 	else {
  		base = (PyTypeObject *)PyTuple_GET_ITEM(bases, 0);
! 		if (!PyType_Check((PyObject *)base)) {
! 			PyErr_SetString(PyExc_TypeError,
! 					"base type must be a type");
! 			return -1;
! 		}
! 		if (base->tp_new == NULL) {
! 			PyErr_SetString(PyExc_TypeError,
! 					"base type must have a tp_new slot");
! 			return -1;
  		}
  	}
  
  	/* Check for a __slots__ sequence variable in dict, and count it */
--- 186,226 ----
  				"usage: TypeType(name, bases, dict) ");
  		return -1;
  	}
! 	n = PyTuple_GET_SIZE(bases);
! 	if (n > 0) {
! 		PyTypeObject *winner, *candidate, *base_i;
  		base = (PyTypeObject *)PyTuple_GET_ITEM(bases, 0);
! 		winner = &PyBaseObject_Type;
! 		for (i = 0; i < n; i++) {
! 			base_i = (PyTypeObject *)PyTuple_GET_ITEM(bases, i);
! 			if (!PyType_Check((PyObject *)base_i)) {
! 				PyErr_SetString(
! 					PyExc_TypeError,
! 					"bases must be types");
! 				return -1;
! 			}
! 			candidate = solid_base(base_i);
! 			if (issubtype(winner, candidate))
! 				;
! 			else if (issubtype(candidate, winner)) {
! 				winner = candidate;
! 				base = base_i;
! 			}
! 			else {
! 				PyErr_SetString(
! 					PyExc_TypeError,
! 					"multiple bases have "
! 					"instance lay-out conflict");
! 				return -1;
! 			}
  		}
  	}
+ 	else
+ 		base = &PyBaseObject_Type;
+ 	if (base->tp_new == NULL) {
+ 		PyErr_SetString(PyExc_TypeError,
+ 				"base type must have a tp_new slot");
+ 		return -1;
+ 	}
  
  	/* Check for a __slots__ sequence variable in dict, and count it */
***************
*** 286,289 ****
--- 316,333 ----
  	add_members(type, et->members);
  
+ 	/* XXX This is close, but not quite right! */
+ 	if (n > 1) {
+ 		PyTypeObject *t;
+ 		for (i = n; --i >= 0; ) {
+ 			t = (PyTypeObject *) PyTuple_GET_ITEM(bases, i);
+ 			x = PyObject_CallMethod(type->tp_dict,
+ 						"update", "O", t->tp_dict);
+ 			if (x == NULL) {
+ 				Py_DECREF(type);
+ 				return -1;
+ 			}
+ 		}
+ 	}
+ 
  	x = PyObject_CallMethod(type->tp_dict, "update", "O", dict);
  	if (x == NULL) {
***************
*** 297,311 ****
  
  static int
! issubtype(PyTypeObject *a, PyTypeObject *b)
  {
! 	while (a != b) {
! 		a = a->tp_base;
! 		if (a == NULL)
! 			return 0;
! 	}
  	return 1;
  }
  
! #define ISSUBTYPE(a, b) issubtype(a, b)
  
  static PyObject *
--- 341,380 ----
  
  static int
! extra_ivars(PyTypeObject *type, PyTypeObject *base)
  {
! 	int t_size = type->tp_basicsize;
! 	int b_size = base->tp_basicsize;
! 
! 	/* XXX what about tp_itemsize? */
! 	assert((type->tp_flags & Py_TPFLAGS_GC) >=
! 	       (base->tp_flags & Py_TPFLAGS_GC)); /* base has GC, type not! */
! 	if (type->tp_flags & Py_TPFLAGS_GC)
! 		t_size -= PyGC_HEAD_SIZE;
! 	if (base->tp_flags & Py_TPFLAGS_GC)
! 		b_size -= PyGC_HEAD_SIZE;
! 	assert(t_size >= b_size); /* type smaller than base! */
! 	if (t_size == b_size)
! 		return 0;
! 	if (type->tp_dictoffset != 0 && base->tp_dictoffset == 0 &&
! 	    type->tp_dictoffset == b_size &&
! 	    t_size == b_size + sizeof(PyObject *))
! 		return 0; /* "Forgive" adding a __dict__ only */
  	return 1;
  }
  
! static PyTypeObject *
! solid_base(PyTypeObject *type)
! {
! 	PyTypeObject *base;
! 
! 	if (type->tp_base)
! 		base = solid_base(type->tp_base);
! 	else
! 		base = &PyBaseObject_Type;
! 	if (extra_ivars(type, base))
! 		return type;
! 	else
! 		return base;
! }
  
  static PyObject *
***************
*** 326,332 ****
  			PyObject *base_i = PyTuple_GET_ITEM(bases, i);
  			PyTypeObject *type_i = base_i->ob_type;
! 			if (ISSUBTYPE(metatype, type_i))
  				continue;
! 			if (ISSUBTYPE(type_i, metatype)) {
  				metatype = type_i;
  				continue;
--- 395,401 ----
  			PyObject *base_i = PyTuple_GET_ITEM(bases, i);
  			PyTypeObject *type_i = base_i->ob_type;
! 			if (issubtype(metatype, type_i))
  				continue;
! 			if (issubtype(type_i, metatype)) {
  				metatype = type_i;
  				continue;