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

Guido van Rossum gvanrossum@users.sourceforge.net
Thu, 10 May 2001 08:33:13 -0700


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

Modified Files:
      Tag: descr-branch
	typeobject.c 
Log Message:
Add a __dict__ to instances of Python classes that inherit from
built-in types.

Still to do (at least):

- class variables should serve as defaults for instance variables
- call __init__() if defined
- don't add a __dict__ if the base type has non-generic getattro or
  setattro
- support fixed slots instead of a __dict__, as an option?
- multiple inheritance (limited to only one base class with C slots)


Index: typeobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/typeobject.c,v
retrieving revision 2.16.8.13
retrieving revision 2.16.8.14
diff -C2 -r2.16.8.13 -r2.16.8.14
*** typeobject.c	2001/05/07 23:19:24	2.16.8.13
--- typeobject.c	2001/05/10 15:33:11	2.16.8.14
***************
*** 54,57 ****
--- 54,59 ----
  type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
  {
+ 	int size;
+ 	void *mem;
  	PyObject *obj, *res;
  
***************
*** 62,68 ****
  		return NULL;
  	}
! 	obj = PyObject_New(PyObject, type);
! 	if (obj == NULL)
! 		return NULL;
  	res = (type->tp_construct)(obj, args, kwds);
  	if (res != obj) {
--- 64,80 ----
  		return NULL;
  	}
! 
! 	/* Inline PyObject_New() so we can zero the memory */
! 	size = _PyObject_SIZE(type);
! 	mem = PyObject_MALLOC(size);
! 	if (mem == NULL)
! 		return PyErr_NoMemory();
! 	memset(mem, '\0', size);
! 	if (PyType_IS_GC(type))
! 		obj = PyObject_FROM_GC(mem);
! 	else
! 		obj = (PyObject *)mem;
! 	PyObject_INIT(obj, type);
! 
  	res = (type->tp_construct)(obj, args, kwds);
  	if (res != obj) {
***************
*** 149,154 ****
--- 161,217 ----
  }
  
+ static PyObject *
+ subtype_getattro(PyObject *self, PyObject *name)
+ {
+ 	int dictoffset = self->ob_type->tp_members[0].offset;
+ 	PyObject *dict = * (PyObject **) ((char *)self + dictoffset);
+ 
+ 	if (dict != NULL) {
+ 		PyObject *res = PyObject_GetItem(dict, name);
+ 		if (res != NULL)
+ 			return res;
+ 		PyErr_Clear();
+ 	}
+ 	return PyGeneric_GetAttr(self, name);
+ }
+ 
+ static int
+ subtype_setattro(PyObject *self, PyObject *name, PyObject *value)
+ {
+ 	PyTypeObject *tp = self->ob_type;
+ 	PyObject *descr;
+ 
+ 	assert(tp->tp_dict != NULL && PyDict_Check(tp->tp_dict));
+ 	descr = PyDict_GetItem(tp->tp_dict, name);
+ 	if (descr == NULL) {
+ 		int dictoffset = self->ob_type->tp_members[0].offset;
+ 		PyObject **dictptr = (PyObject **) ((char *)self + dictoffset);
+ 		PyObject *dict = *dictptr;
+ 
+ 		if (dict == NULL) {
+ 			dict = PyDict_New();
+ 			if (dict == NULL)
+ 				return -1;
+ 			*dictptr = dict;
+ 		}
+ 		if (value == NULL) {
+ 			int res = PyObject_DelItem(dict, name);
+ 			if (res < 0 &&
+ 			    PyErr_ExceptionMatches(PyExc_KeyError))
+ 			{
+ 				PyErr_SetObject(PyExc_AttributeError, name);
+ 				return -1;
+ 			}
+ 		}
+ 		else
+ 			return PyObject_SetItem(dict, name, value);
+ 	}
+ 	return PyGeneric_SetAttr(self, name, value);
+ }
+ 
  staticforward void override_slots(PyTypeObject *type, PyObject *dict);
  
+ #define NMEMBERS 1
+ 
  typedef struct {
  	PyTypeObject type;
***************
*** 157,160 ****
--- 220,224 ----
  	PyMappingMethods as_mapping;
  	PyBufferProcs as_buffer;
+ 	struct memberlist members[NMEMBERS+1];
  	char name[1];
  } etype;
***************
*** 168,171 ****
--- 232,237 ----
  	PyTypeObject *base;
  	char *dummy = NULL;
+ 	etype *et;
+ 	struct memberlist *mp;
  
  	if (type != NULL) {
***************
*** 198,211 ****
  		return NULL;
  	}
! 	type = PyObject_MALLOC(sizeof(etype) + strlen(name));
! 	if (type == NULL)
  		return NULL;
! 	memset(type, '\0', sizeof(etype));
  	PyObject_INIT(type, &PyType_Type);
! 	type->tp_as_number = & (((etype *)type)->as_number);
! 	type->tp_as_sequence = & (((etype *)type)->as_sequence);
! 	type->tp_as_mapping = & (((etype *)type)->as_mapping);
! 	type->tp_as_buffer = & (((etype *)type)->as_buffer);
! 	type->tp_name = strcpy(((etype *)type)->name, name);
  	type->tp_flags = Py_TPFLAGS_DEFAULT;
  	Py_INCREF(base);
--- 264,278 ----
  		return NULL;
  	}
! 	et = PyObject_MALLOC(sizeof(etype) + strlen(name));
! 	if (et == NULL)
  		return NULL;
! 	memset(et, '\0', sizeof(etype));
! 	type = &et->type;
  	PyObject_INIT(type, &PyType_Type);
! 	type->tp_as_number = &et->as_number;
! 	type->tp_as_sequence = &et->as_sequence;
! 	type->tp_as_mapping = &et->as_mapping;
! 	type->tp_as_buffer = &et->as_buffer;
! 	type->tp_name = strcpy(et->name, name);
  	type->tp_flags = Py_TPFLAGS_DEFAULT;
  	Py_INCREF(base);
***************
*** 215,222 ****
--- 282,309 ----
  	if (base->tp_dealloc)
  		type->tp_dealloc = subtype_dealloc;
+ 	if (base->tp_getattro == NULL ||
+ 	    base->tp_getattro == PyGeneric_GetAttr) {
+ 		type->tp_getattro = subtype_getattro;
+ 		type->tp_getattr = NULL;
+ 	}
+ 	if (base->tp_setattro == NULL ||
+ 	    base->tp_setattro == PyGeneric_SetAttr) {
+ 		type->tp_setattro = subtype_setattro;
+ 		type->tp_setattr = NULL;
+ 	}
+ 
+ 	type->tp_members = mp = et->members;
+ 	mp->name = "__dict__";
+ 	mp->type = T_OBJECT;
+ 	mp->offset = base->tp_basicsize - ((base->tp_flags & Py_TPFLAGS_GC)
+ 					   ? PyGC_HEAD_SIZE : 0);
+ 	mp->readonly = 1;
+ 	assert(mp+1 <= &et->members[NMEMBERS]);
+ 
  	if (PyType_InitDict(type) < 0) {
  		Py_DECREF(type);
  		return NULL;
  	}
+ 	type->tp_basicsize += sizeof(PyObject *); /* for __dict__ */
  	x = PyObject_CallMethod(type->tp_dict, "update", "O", dict);
  	if (x == NULL) {
***************
*** 429,432 ****
--- 516,521 ----
  inherit_slots(PyTypeObject *type, PyTypeObject *base)
  {
+ 	int oldsize, newsize;
+ 
  #undef COPYSLOT
  #undef COPYNUM
***************
*** 530,534 ****
  
  	COPYSLOT(tp_name);
! 	COPYSLOT(tp_basicsize);
  	if (!(type->tp_flags & Py_TPFLAGS_GC) &&
  	    (base->tp_flags & Py_TPFLAGS_GC) &&
--- 619,632 ----
  
  	COPYSLOT(tp_name);
! 
! 	/* Copying basicsize is connected to the GC flags */
! 	oldsize = base->tp_basicsize;
! 	if (base->tp_flags & Py_TPFLAGS_GC)
! 		oldsize -= PyGC_HEAD_SIZE;
! 	newsize = type->tp_basicsize;
! 	if (newsize && (type->tp_flags & Py_TPFLAGS_GC))
! 		newsize -= PyGC_HEAD_SIZE;
! 	if (!newsize)
! 		newsize = oldsize;
  	if (!(type->tp_flags & Py_TPFLAGS_GC) &&
  	    (base->tp_flags & Py_TPFLAGS_GC) &&
***************
*** 536,543 ****
  	    (!type->tp_traverse && !type->tp_clear)) {
  		type->tp_flags |= Py_TPFLAGS_GC;
- 		type->tp_basicsize += PyGC_HEAD_SIZE;
  		COPYSLOT(tp_traverse);
  		COPYSLOT(tp_clear);
  	}
  	COPYSLOT(tp_itemsize);
  	COPYSLOT(tp_dealloc);
--- 634,644 ----
  	    (!type->tp_traverse && !type->tp_clear)) {
  		type->tp_flags |= Py_TPFLAGS_GC;
  		COPYSLOT(tp_traverse);
  		COPYSLOT(tp_clear);
  	}
+ 	if (type->tp_flags & Py_TPFLAGS_GC)
+ 		newsize += PyGC_HEAD_SIZE;
+ 	type->tp_basicsize = newsize;
+ 
  	COPYSLOT(tp_itemsize);
  	COPYSLOT(tp_dealloc);
***************
*** 1227,1230 ****
--- 1328,1333 ----
  }
  
+ /* XXX the numerical slots should call the reverse operators too;
+    but how do they know their type? */
  SLOT1(nb_add, add, PyObject *, O);
  SLOT1(nb_subtract, sub, PyObject *, O);