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

Guido van Rossum gvanrossum@users.sourceforge.net
Fri, 11 May 2001 14:51:37 -0700


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

Modified Files:
      Tag: descr-branch
	typeobject.c 
Log Message:
Another cool feature: if a subtype of a built-in type defines a class
variable __slots__ (which must be a sequence of strings), it doesn't
have a __dict__, but instead it has named slots whose names are given
by the strings in the sequence.  Setting __slots__ = [] implies the
subtype has no slots beyond those in the base class.

(I think subtypes of such subtypes must specifiy __slots__ = [] to
prevent adding a __dict__.)


Index: typeobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/typeobject.c,v
retrieving revision 2.16.8.18
retrieving revision 2.16.8.19
diff -C2 -r2.16.8.18 -r2.16.8.19
*** typeobject.c	2001/05/11 20:12:27	2.16.8.18
--- typeobject.c	2001/05/11 21:51:35	2.16.8.19
***************
*** 126,131 ****
  staticforward void override_slots(PyTypeObject *type, PyObject *dict);
  
- #define NMEMBERS 1
- 
  typedef struct {
  	PyTypeObject type;
--- 126,129 ----
***************
*** 134,139 ****
  	PyMappingMethods as_mapping;
  	PyBufferProcs as_buffer;
! 	struct memberlist members[NMEMBERS+1];
! 	char name[1];
  } etype;
  
--- 132,137 ----
  	PyMappingMethods as_mapping;
  	PyBufferProcs as_buffer;
! 	PyObject *name, *slots;
! 	struct memberlist members[1];
  } etype;
  
***************
*** 142,151 ****
  type_construct(PyTypeObject *type, PyObject *args, PyObject *kwds)
  {
! 	char *name;
! 	PyObject *bases, *dict, *x;
  	PyTypeObject *base;
  	char *dummy = NULL;
  	etype *et;
  	struct memberlist *mp;
  
  	/* Check arguments */
--- 140,149 ----
  type_construct(PyTypeObject *type, PyObject *args, PyObject *kwds)
  {
! 	PyObject *name, *bases, *dict, *x, *slots;
  	PyTypeObject *base;
  	char *dummy = NULL;
  	etype *et;
  	struct memberlist *mp;
+ 	int i, nslots, slotoffset, allocsize;
  
  	/* Check arguments */
***************
*** 155,159 ****
  		return NULL;
  	}
! 	if (!PyArg_ParseTupleAndKeywords(args, kwds, "sOO", &dummy,
  					 &name, &bases, &dict))
  		return NULL;
--- 153,157 ----
  		return NULL;
  	}
! 	if (!PyArg_ParseTupleAndKeywords(args, kwds, "SOO", &dummy,
  					 &name, &bases, &dict))
  		return NULL;
***************
*** 180,195 ****
  	}
  
  	/* Allocate memory and construct a type object in it */
! 	et = PyObject_MALLOC(sizeof(etype) + strlen(name));
  	if (et == NULL)
  		return NULL;
! 	memset(et, '\0', sizeof(etype));
  	type = &et->type;
  	PyObject_INIT(type, &PyDynamicType_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;
  
--- 178,223 ----
  	}
  
+ 	/* Check for a __slots__ sequence variable in dict, and count it */
+ 	slots = PyDict_GetItemString(dict, "__slots__");
+ 	nslots = 0;
+ 	if (slots != NULL) {
+ 		/* Make it into a tuple */
+ 		if (PyString_Check(slots))
+ 			slots = Py_BuildValue("(O)", slots);
+ 		else
+ 			slots = PySequence_Tuple(slots);
+ 		if (slots == NULL)
+ 			return NULL;
+ 		nslots = PyTuple_GET_SIZE(slots);
+ 		for (i = 0; i < nslots; i++) {
+ 			if (!PyString_Check(PyTuple_GET_ITEM(slots, i))) {
+ 				PyErr_SetString(PyExc_TypeError,
+ 				"__slots__ must be a sequence of strings");
+ 				Py_DECREF(slots);
+ 				return NULL;
+ 			}
+ 		}
+ 	}
+ 	if (slots == NULL && base->tp_dictoffset == 0 &&
+ 	    (base->tp_setattro == PyGeneric_SetAttr ||
+ 	     base->tp_setattro == NULL))
+ 		nslots = 1;
+ 
  	/* Allocate memory and construct a type object in it */
! 	allocsize = sizeof(etype) + nslots*sizeof(struct memberlist);
! 	et = PyObject_MALLOC(allocsize);
  	if (et == NULL)
  		return NULL;
! 	memset(et, '\0', allocsize);
  	type = &et->type;
  	PyObject_INIT(type, &PyDynamicType_Type);
+ 	Py_INCREF(name);
+ 	et->name = name;
+ 	et->slots = slots;
  	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 = PyString_AS_STRING(name);
  	type->tp_flags = Py_TPFLAGS_DEFAULT;
  
***************
*** 216,235 ****
  	}
  
! 	/* Add a __dict__ slot if we don't already have one,
! 	   but only if the getattro is generic */
! 	if (type->tp_dictoffset == 0 &&
! 	    type->tp_setattro == PyGeneric_SetAttr) {
! 		int dictoffset = type->tp_basicsize;
! 		if (type->tp_flags & Py_TPFLAGS_GC)
! 			dictoffset -= PyGC_HEAD_SIZE;
! 		type->tp_dictoffset = dictoffset;
  		type->tp_basicsize += sizeof(PyObject *);
- 		mp = et->members;
  		mp->name = "__dict__";
  		mp->type = T_OBJECT;
! 		mp->offset = dictoffset;
  		mp->readonly = 1;
- 		add_members(type, mp);
  	}
  
  	x = PyObject_CallMethod(type->tp_dict, "update", "O", dict);
--- 244,270 ----
  	}
  
! 	/* Add custom slots */
! 	mp = et->members;
! 	slotoffset = type->tp_basicsize;
! 	if (type->tp_flags & Py_TPFLAGS_GC)
! 		slotoffset -= PyGC_HEAD_SIZE;
! 	if (slots != NULL) {
! 		for (i = 0; i < nslots; i++, mp++) {
! 			mp->name = PyString_AS_STRING(
! 				PyTuple_GET_ITEM(slots, i));
! 			mp->type = T_OBJECT;
! 			mp->offset = slotoffset + i*sizeof(PyObject *);
! 		}
! 		type->tp_basicsize += nslots*sizeof(PyObject *);
! 	}
! 	else if (nslots) {
! 		type->tp_dictoffset = slotoffset;
  		type->tp_basicsize += sizeof(PyObject *);
  		mp->name = "__dict__";
  		mp->type = T_OBJECT;
! 		mp->offset = slotoffset;
  		mp->readonly = 1;
  	}
+ 	add_members(type, et->members);
  
  	x = PyObject_CallMethod(type->tp_dict, "update", "O", dict);
***************
*** 311,316 ****
--- 346,355 ----
  dtype_dealloc(PyTypeObject *type)
  {
+ 	etype *et = (etype *)type;
+ 
  	Py_XDECREF(type->tp_base);
  	Py_XDECREF(type->tp_dict);
+ 	Py_XDECREF(et->name);
+ 	Py_XDECREF(et->slots);
  	PyObject_DEL(type);
  }
***************
*** 348,352 ****
  	type_members,				/* tp_members */
  	type_getsets,				/* tp_getset */
! 	0,					/* tp_base */
  	0,					/* tp_dict */
  	0,					/* tp_descr_get */
--- 387,391 ----
  	type_members,				/* tp_members */
  	type_getsets,				/* tp_getset */
! 	&PyType_Type,				/* tp_base */
  	0,					/* tp_dict */
  	0,					/* tp_descr_get */