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

Guido van Rossum gvanrossum@users.sourceforge.net
Fri, 04 May 2001 10:09:40 -0700


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

Modified Files:
      Tag: descr-branch
	typeobject.c 
Log Message:
Basic support for single inheritance at the C level.

NOTE: This only works for base classes that support subtyping.  This
requires a tp_construct slot that takes an already-allocated object as
first argument.  I'll check in experimental support for subclassing
list and dict next.

Instructions:

Define and initialize a static type struct like normal, but leave most
slots empty.  Put the address of the base class in your tp_base slot.
Call PyType_InitDict() for your type *before creating the first
instance*.  This will copy all the slots from the base class into your
derived class.  It will also initialize your tp_dict.

To create an instance, use PyObject_CallObject() to call your type
object.  I'll check in an example module soon.


Index: typeobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/typeobject.c,v
retrieving revision 2.16.8.8
retrieving revision 2.16.8.9
diff -C2 -r2.16.8.8 -r2.16.8.9
*** typeobject.c	2001/05/01 21:04:21	2.16.8.8
--- typeobject.c	2001/05/04 17:09:38	2.16.8.9
***************
*** 14,18 ****
  type_bases(PyTypeObject *type, void *context)
  {
! 	return PyTuple_New(0);
  }
  
--- 14,21 ----
  type_bases(PyTypeObject *type, void *context)
  {
! 	if (type->tp_base == NULL)
! 		return PyTuple_New(0);
! 	else
! 		return Py_BuildValue("(O)", type->tp_base);
  }
  
***************
*** 49,52 ****
--- 52,84 ----
  
  static PyObject *
+ type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
+ {
+ 	char *dummy = NULL;
+ 	PyObject *obj, *res;
+ 
+ 	if (!PyArg_ParseTupleAndKeywords(args, kwds, "", &dummy))
+ 		return NULL;
+ 
+ 	if (type->tp_construct == NULL) {
+ 		PyErr_Format(PyExc_TypeError,
+ 			     "cannot construct '%.100s' instances",
+ 			     type->tp_name);
+ 		return NULL;
+ 	}
+ 	obj = PyObject_New(PyObject, type);
+ 	if (obj == NULL)
+ 		return NULL;
+ 	res = (type->tp_construct)(obj);
+ 	if (res != obj) {
+ 		Py_DECREF(obj);
+ 		if (res == NULL)
+ 			return NULL;
+ 	}
+ 	if (PyType_IS_GC(type))
+ 		PyObject_GC_Init(res);
+ 	return res;
+ }
+ 
+ static PyObject *
  type_getattro(PyTypeObject *type, PyObject *name)
  {
***************
*** 108,112 ****
  	0,					/* tp_as_mapping */
  	0,					/* tp_hash */
! 	0,					/* tp_call */
  	0,					/* tp_str */
  	(getattrofunc)type_getattro,		/* tp_getattro */
--- 140,144 ----
  	0,					/* tp_as_mapping */
  	0,					/* tp_hash */
! 	(ternaryfunc)type_call,			/* tp_call */
  	0,					/* tp_str */
  	(getattrofunc)type_getattro,		/* tp_getattro */
***************
*** 211,222 ****
  staticforward int add_operators(PyTypeObject *);
  
  int
  PyType_InitDict(PyTypeObject *type)
  {
  	PyObject *dict;
  
  	if (type->tp_dict != NULL)
  		return 0;
! 	dict = PyDict_New();
  	if (dict == NULL)
  		return -1;
--- 243,409 ----
  staticforward int add_operators(PyTypeObject *);
  
+ static int
+ inherit_slots(PyTypeObject *type, PyTypeObject *base)
+ {
+ #undef COPYSLOT
+ #undef COPYNUM
+ #undef COPYSEQ
+ #undef COPYMAP
+ #define COPYSLOT(SLOT) \
+ 	if (!type->SLOT) type->SLOT = base->SLOT
+ 
+ #define COPYNUM(SLOT) COPYSLOT(tp_as_number->SLOT)
+ #define COPYSEQ(SLOT) COPYSLOT(tp_as_sequence->SLOT)
+ #define COPYMAP(SLOT) COPYSLOT(tp_as_mapping->SLOT)
+ 
+ 	if (type->tp_as_number == NULL)
+ 		type->tp_as_number = base->tp_as_number;
+ 	else if (base->tp_as_number) {
+ 		COPYNUM(nb_add);
+ 		COPYNUM(nb_subtract);
+ 		COPYNUM(nb_multiply);
+ 		COPYNUM(nb_divide);
+ 		COPYNUM(nb_remainder);
+ 		COPYNUM(nb_divmod);
+ 		COPYNUM(nb_power);
+ 		COPYNUM(nb_negative);
+ 		COPYNUM(nb_positive);
+ 		COPYNUM(nb_absolute);
+ 		COPYNUM(nb_nonzero);
+ 		COPYNUM(nb_invert);
+ 		COPYNUM(nb_lshift);
+ 		COPYNUM(nb_rshift);
+ 		COPYNUM(nb_and);
+ 		COPYNUM(nb_xor);
+ 		COPYNUM(nb_or);
+ 		COPYNUM(nb_coerce);
+ 		COPYNUM(nb_int);
+ 		COPYNUM(nb_long);
+ 		COPYNUM(nb_float);
+ 		COPYNUM(nb_oct);
+ 		COPYNUM(nb_hex);
+ 		COPYNUM(nb_inplace_add);
+ 		COPYNUM(nb_inplace_subtract);
+ 		COPYNUM(nb_inplace_multiply);
+ 		COPYNUM(nb_inplace_divide);
+ 		COPYNUM(nb_inplace_remainder);
+ 		COPYNUM(nb_inplace_power);
+ 		COPYNUM(nb_inplace_lshift);
+ 		COPYNUM(nb_inplace_rshift);
+ 		COPYNUM(nb_inplace_and);
+ 		COPYNUM(nb_inplace_xor);
+ 		COPYNUM(nb_inplace_or);
+ 	}
+ 
+ 	if (type->tp_as_sequence == NULL)
+ 		type->tp_as_sequence = base->tp_as_sequence;
+ 	else if (base->tp_as_sequence) {
+ 		COPYSEQ(sq_length);
+ 		COPYSEQ(sq_concat);
+ 		COPYSEQ(sq_repeat);
+ 		COPYSEQ(sq_item);
+ 		COPYSEQ(sq_slice);
+ 		COPYSEQ(sq_ass_item);
+ 		COPYSEQ(sq_ass_slice);
+ 		COPYSEQ(sq_contains);
+ 		COPYSEQ(sq_inplace_concat);
+ 		COPYSEQ(sq_inplace_repeat);
+ 	}
+ 
+ 	if (type->tp_as_mapping == NULL)
+ 		type->tp_as_mapping = base->tp_as_mapping;
+ 	else if (base->tp_as_mapping) {
+ 		COPYMAP(mp_length);
+ 		COPYMAP(mp_subscript);
+ 		COPYMAP(mp_ass_subscript);
+ 	}
+ 
+ 	/* Special flag magic */
+ 	if (!type->tp_as_buffer && base->tp_as_buffer) {
+ 		type->tp_flags &= ~Py_TPFLAGS_HAVE_GETCHARBUFFER;
+ 		type->tp_flags |=
+ 			base->tp_flags & Py_TPFLAGS_HAVE_GETCHARBUFFER;
+ 	}
+ 	if (!type->tp_as_sequence && base->tp_as_sequence) {
+ 		type->tp_flags &= ~Py_TPFLAGS_HAVE_SEQUENCE_IN;
+ 		type->tp_flags |= base->tp_flags & Py_TPFLAGS_HAVE_SEQUENCE_IN;
+ 	}
+ 	if (!(type->tp_flags & Py_TPFLAGS_GC) &&
+ 	    (base->tp_flags & Py_TPFLAGS_GC) &&
+ 	    (type->tp_flags & Py_TPFLAGS_HAVE_RICHCOMPARE/*GC slots exist*/) &&
+ 	    (!type->tp_traverse && !type->tp_clear)) {
+ 		type->tp_flags |= Py_TPFLAGS_GC;
+ 		type->tp_basicsize += PyGC_HEAD_SIZE;
+ 		COPYSLOT(tp_traverse);
+ 		COPYSLOT(tp_clear);
+ 	}
+ 	if ((type->tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS) !=
+ 	    (base->tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS)) {
+ 		if ((!type->tp_as_number && base->tp_as_number) ||
+ 		    (!type->tp_as_sequence && base->tp_as_sequence)) {
+ 			type->tp_flags &= ~Py_TPFLAGS_HAVE_INPLACEOPS;
+ 			if (!type->tp_as_number && !type->tp_as_sequence) {
+ 				type->tp_flags |= base->tp_flags &
+ 					Py_TPFLAGS_HAVE_INPLACEOPS;
+ 			}
+ 		}
+ 		/* Wow */
+ 	}
+ 	if (!type->tp_as_number && base->tp_as_number) {
+ 		type->tp_flags &= ~Py_TPFLAGS_CHECKTYPES;
+ 		type->tp_flags |= base->tp_flags & Py_TPFLAGS_CHECKTYPES;
+ 	}
+ 
+ 	COPYSLOT(tp_name);
+ 	COPYSLOT(tp_basicsize);
+ 	COPYSLOT(tp_itemsize);
+ 	COPYSLOT(tp_dealloc);
+ 	COPYSLOT(tp_print);
+ 	COPYSLOT(tp_getattr);
+ 	COPYSLOT(tp_setattr);
+ 	COPYSLOT(tp_compare);
+ 	COPYSLOT(tp_repr);
+ 	COPYSLOT(tp_hash);
+ 	COPYSLOT(tp_call);
+ 	COPYSLOT(tp_str);
+ 	COPYSLOT(tp_getattro);
+ 	COPYSLOT(tp_setattro);
+ 	COPYSLOT(tp_as_buffer);
+ 	COPYSLOT(tp_flags);
+ 	COPYSLOT(tp_doc);
+ 	if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_RICHCOMPARE) {
+ 		COPYSLOT(tp_richcompare);
+ 	}
+ 	if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_WEAKREFS) {
+ 		COPYSLOT(tp_weaklistoffset);
+ 	}
+ 	if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_ITER) {
+ 		COPYSLOT(tp_iter);
+ 		COPYSLOT(tp_iternext);
+ 	}
+ 	if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_CLASS) {
+ 		COPYSLOT(tp_descr_get);
+ 		COPYSLOT(tp_descr_set);
+ 		COPYSLOT(tp_construct);
+ 	}
+ 
+ 	return 0;
+ }
+ 
  int
  PyType_InitDict(PyTypeObject *type)
  {
  	PyObject *dict;
+ 	PyTypeObject *base = type->tp_base;
  
  	if (type->tp_dict != NULL)
  		return 0;
! 	if (base) {
! 		if (PyType_InitDict(base) < 0)
! 			return -1;
! 		dict = PyDict_Copy(base->tp_dict);
! 	}
! 	else
! 		dict = PyDict_New();
  	if (dict == NULL)
  		return -1;
***************
*** 246,249 ****
--- 433,443 ----
  			return -1;
  	}
+ 
+ 	/* Inherit base class slots and methods */
+ 	if (base) {
+ 		if (inherit_slots(type, base) < 0)
+ 			return -1;
+ 	}
+ 
  	return 0;
  }