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

Guido van Rossum gvanrossum@users.sourceforge.net
Mon, 24 Sep 2001 20:43:44 -0700


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

Modified Files:
	typeobject.c 
Log Message:
Make __class__ assignment possible, when the object structures are the
same.  I hope the test for structural equivalence is stringent enough.
It only allows the assignment if the old and new types:

- have the same basic size
- have the same item size
- have the same dict offset
- have the same weaklist offset
- have the same GC flag bit
- have a common base that is the same except for maybe the dict and
  weaklist (which may have been added separately at the same offsets
  in both types)



Index: typeobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/typeobject.c,v
retrieving revision 2.71
retrieving revision 2.72
diff -C2 -d -r2.71 -r2.72
*** typeobject.c	2001/09/24 18:47:39	2.71
--- typeobject.c	2001/09/25 03:43:42	2.72
***************
*** 1193,1198 ****
  }
  
! static PyMemberDef object_members[] = {
! 	{"__class__", T_OBJECT, offsetof(PyObject, ob_type), READONLY},
  	{0}
  };
--- 1193,1277 ----
  }
  
! static PyObject *
! object_get_class(PyObject *self, void *closure)
! {
! 	Py_INCREF(self->ob_type);
! 	return (PyObject *)(self->ob_type);
! }
! 
! static int
! equiv_structs(PyTypeObject *a, PyTypeObject *b)
! {
! 	return a == b ||
! 	       (a != NULL &&
! 		b != NULL &&
! 		a->tp_basicsize == b->tp_basicsize &&
! 		a->tp_itemsize == b->tp_itemsize &&
! 		a->tp_dictoffset == b->tp_dictoffset &&
! 		a->tp_weaklistoffset == b->tp_weaklistoffset &&
! 		((a->tp_flags & Py_TPFLAGS_HAVE_GC) ==
! 		 (b->tp_flags & Py_TPFLAGS_HAVE_GC)));
! }
! 
! static int
! same_slots_added(PyTypeObject *a, PyTypeObject *b)
! {
! 	PyTypeObject *base = a->tp_base;
! 	int size;
! 
! 	if (base != b->tp_base)
! 		return 0;
! 	if (equiv_structs(a, base) && equiv_structs(b, base))
! 		return 1;
! 	size = base->tp_basicsize;
! 	if (a->tp_dictoffset == size && b->tp_dictoffset == size)
! 		size += sizeof(PyObject *);
! 	if (a->tp_weaklistoffset == size && b->tp_weaklistoffset == size)
! 		size += sizeof(PyObject *);
! 	return size == a->tp_basicsize && size == b->tp_basicsize;
! }
! 
! static int
! object_set_class(PyObject *self, PyObject *value, void *closure)
! {
! 	PyTypeObject *old = self->ob_type;
! 	PyTypeObject *new, *newbase, *oldbase;
! 
! 	if (!PyType_Check(value)) {
! 		PyErr_Format(PyExc_TypeError,
! 		  "__class__ must be set to new-style class, not '%s' object",
! 		  value->ob_type->tp_name);
! 		return -1;
! 	}
! 	new = (PyTypeObject *)value;
! 	newbase = new;
! 	oldbase = old;
! 	while (equiv_structs(newbase, newbase->tp_base))
! 		newbase = newbase->tp_base;
! 	while (equiv_structs(oldbase, oldbase->tp_base))
! 		oldbase = oldbase->tp_base;
! 	if (newbase != oldbase &&
! 	    (newbase->tp_base != oldbase->tp_base ||
! 	     !same_slots_added(newbase, oldbase))) {
! 		PyErr_Format(PyExc_TypeError,
! 			     "__class__ assignment: "
! 			     "'%s' object layout differs from '%s'",
! 			     new->tp_name, 
! 			     old->tp_name);
! 		return -1;
! 	}
! 	if (new->tp_flags & Py_TPFLAGS_HEAPTYPE) {
! 		Py_INCREF(new);
! 	}
! 	self->ob_type = new;
! 	if (old->tp_flags & Py_TPFLAGS_HEAPTYPE) {
! 		Py_DECREF(old);
! 	}
! 	return 0;
! }
! 
! static PyGetSetDef object_getsets[] = {
! 	{"__class__", object_get_class, object_set_class,
! 	 "the object's class"},
  	{0}
  };
***************
*** 1228,1233 ****
  	0,					/* tp_iternext */
  	0,					/* tp_methods */
! 	object_members,				/* tp_members */
! 	0,					/* tp_getset */
  	0,					/* tp_base */
  	0,					/* tp_dict */
--- 1307,1312 ----
  	0,					/* tp_iternext */
  	0,					/* tp_methods */
! 	0,					/* tp_members */
! 	object_getsets,				/* tp_getset */
  	0,					/* tp_base */
  	0,					/* tp_dict */