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

Guido van Rossum gvanrossum@users.sourceforge.net
Wed, 15 Aug 2001 16:57:05 -0700


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

Modified Files:
	typeobject.c 
Log Message:
- Another big step in the right direction.  All the overridable
  operators for which a default implementation exist now work, both in
  dynamic classes and in static classes, overridden or not.  This
  affects __repr__, __str__, __hash__, __contains__, __nonzero__,
  __cmp__, and the rich comparisons (__lt__ etc.).  For dynamic
  classes, this meant copying a lot of code from classobject!  (XXX
  There are still some holes, because the comparison code in object.c
  uses PyInstance_Check(), meaning new-style classes don't get the
  same dispensation.  This needs more thinking.)

- Add object.__hash__, object.__repr__, object.__str__.  The __str__
  dispatcher now calls the __repr__ dispatcher, as it should.

- For static classes, the tp_compare, tp_richcompare and tp_hash slots
  are now inherited together, or not at all.  (XXX I fear there are
  still some situations where you can inherit __hash__ when you
  shouldn't, but mostly it's OK now, and I think there's no way we can
  get that 100% right.)


Index: typeobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/typeobject.c,v
retrieving revision 2.32
retrieving revision 2.33
diff -C2 -d -r2.32 -r2.33
*** typeobject.c	2001/08/14 20:04:48	2.32
--- typeobject.c	2001/08/15 23:57:02	2.33
***************
*** 852,857 ****
  }
  
- #if 0
- /* XXX These should be made smarter before they can be used */
  static PyObject *
  object_repr(PyObject *self)
--- 852,855 ----
***************
*** 863,866 ****
--- 861,875 ----
  }
  
+ static PyObject *
+ object_str(PyObject *self)
+ {
+ 	unaryfunc f;
+ 
+ 	f = self->ob_type->tp_repr;
+ 	if (f == NULL)
+ 		f = object_repr;
+ 	return f(self);
+ }
+ 
  static long
  object_hash(PyObject *self)
***************
*** 868,872 ****
  	return _Py_HashPointer(self);
  }
- #endif
  
  static void
--- 877,880 ----
***************
*** 892,902 ****
  	0,					/* tp_setattr */
  	0,					/* tp_compare */
! 	0,					/* tp_repr */
  	0,					/* tp_as_number */
  	0,					/* tp_as_sequence */
  	0,					/* tp_as_mapping */
! 	0,					/* tp_hash */
  	0,					/* tp_call */
! 	0,					/* tp_str */
  	PyObject_GenericGetAttr,		/* tp_getattro */
  	PyObject_GenericSetAttr,		/* tp_setattro */
--- 900,910 ----
  	0,					/* tp_setattr */
  	0,					/* tp_compare */
! 	object_repr,				/* tp_repr */
  	0,					/* tp_as_number */
  	0,					/* tp_as_sequence */
  	0,					/* tp_as_mapping */
! 	object_hash,				/* tp_hash */
  	0,					/* tp_call */
! 	object_str,				/* tp_str */
  	PyObject_GenericGetAttr,		/* tp_getattro */
  	PyObject_GenericSetAttr,		/* tp_setattro */
***************
*** 1164,1175 ****
  	/* tp_compare see tp_richcompare */
  	COPYSLOT(tp_repr);
! 	COPYSLOT(tp_hash);
  	COPYSLOT(tp_call);
  	COPYSLOT(tp_str);
  	COPYSLOT(tp_as_buffer);
  	if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_RICHCOMPARE) {
! 		if (type->tp_compare == NULL && type->tp_richcompare == NULL) {
  			type->tp_compare = base->tp_compare;
  			type->tp_richcompare = base->tp_richcompare;
  		}
  	}
--- 1172,1187 ----
  	/* tp_compare see tp_richcompare */
  	COPYSLOT(tp_repr);
! 	/* tp_hash see tp_richcompare */
  	COPYSLOT(tp_call);
  	COPYSLOT(tp_str);
  	COPYSLOT(tp_as_buffer);
  	if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_RICHCOMPARE) {
! 		if (type->tp_compare == NULL &&
! 		    type->tp_richcompare == NULL &&
! 		    type->tp_hash == NULL)
! 		{
  			type->tp_compare = base->tp_compare;
  			type->tp_richcompare = base->tp_richcompare;
+ 			type->tp_hash = base->tp_hash;
  		}
  	}
***************
*** 2194,2205 ****
  slot_sq_contains(PyObject *self, PyObject *value)
  {
! 	PyObject *res = PyObject_CallMethod(self, "__contains__", "O", value);
! 	int r;
  
! 	if (res == NULL)
! 		return -1;
! 	r = PyInt_AsLong(res);
! 	Py_DECREF(res);
! 	return r;
  }
  
--- 2206,2230 ----
  slot_sq_contains(PyObject *self, PyObject *value)
  {
! 	PyObject *func, *res, *args;
  
! 	func = PyObject_GetAttrString(self, "__contains__");
! 
! 	if (func != NULL) {
! 		args = Py_BuildValue("(O)", value);
! 		if (args == NULL)
! 			res = NULL;
! 		else {
! 			res = PyEval_CallObject(func, args);
! 			Py_DECREF(args);
! 		}
! 		Py_DECREF(func);
! 		if (res == NULL)
! 			return -1;
! 		return PyObject_IsTrue(res);
! 	}
! 	else {
! 		PyErr_Clear();
! 		return _PySequence_IterContains(self, value);
! 	}
  }
  
***************
*** 2255,2265 ****
  slot_nb_nonzero(PyObject *self)
  {
! 	/* XXX This should cope with a missing __nonzero__ */
! 	/* XXX Should it also look for __len__? */
! 	PyObject *res = PyObject_CallMethod(self, "__nonzero__", "");
  
! 	if (res == NULL)
! 		return -1;
! 	return (int)PyInt_AsLong(res);
  }
  
--- 2280,2302 ----
  slot_nb_nonzero(PyObject *self)
  {
! 	PyObject *func, *res;
  
! 	func = PyObject_GetAttrString(self, "__nonzero__");
! 	if (func == NULL) {
! 		PyErr_Clear();
! 		func = PyObject_GetAttrString(self, "__len__");
! 	}
! 
! 	if (func != NULL) {
! 		res = PyEval_CallObject(func, NULL);
! 		Py_DECREF(func);
! 		if (res == NULL)
! 			return -1;
! 		return PyObject_IsTrue(res);
! 	}
! 	else {
! 		PyErr_Clear();
! 		return 1;
! 	}
  }
  
***************
*** 2294,2323 ****
  
  static int
  slot_tp_compare(PyObject *self, PyObject *other)
  {
! 	/* XXX Should this cope with a missing __cmp__? */
! 	PyObject *res = PyObject_CallMethod(self, "__cmp__", "O", other);
! 	long r;
  
! 	if (res == NULL)
! 		return -1;
! 	r = PyInt_AsLong(res);
! 	Py_DECREF(res);
! 	return (int)r;
  }
  
! /* XXX This should cope with a missing __repr__, and also look for __str__ */
! SLOT0(slot_tp_repr, "__repr__")
  
  static long
  slot_tp_hash(PyObject *self)
  {
! 	/* XXX This should cope with a missing __hash__ */
! 	PyObject *res = PyObject_CallMethod(self, "__hash__", "");
  	long h;
  
! 	if (res == NULL)
! 		return -1;
! 	h = PyInt_AsLong(res);
  	if (h == -1 && !PyErr_Occurred())
  		h = -2;
--- 2331,2453 ----
  
  static int
+ half_compare(PyObject *self, PyObject *other)
+ {
+ 	PyObject *func, *args, *res;
+ 	int c;
+ 
+ 	func = PyObject_GetAttrString(self, "__cmp__");
+ 	if (func == NULL) {
+ 		PyErr_Clear();
+ 	}
+ 	else {
+ 		args = Py_BuildValue("(O)", other);
+ 		if (args == NULL)
+ 			res = NULL;
+ 		else {
+ 			res = PyObject_CallObject(func, args);
+ 			Py_DECREF(args);
+ 		}
+ 		if (res != Py_NotImplemented) {
+ 			if (res == NULL)
+ 				return -2;
+ 			c = PyInt_AsLong(res);
+ 			Py_DECREF(res);
+ 			if (c == -1 && PyErr_Occurred())
+ 				return -2;
+ 			return (c < 0) ? -1 : (c > 0) ? 1 : 0;
+ 		}
+ 		Py_DECREF(res);
+ 	}
+ 	return 2;
+ }
+ 
+ static int
  slot_tp_compare(PyObject *self, PyObject *other)
  {
! 	int c;
  
! 	if (self->ob_type->tp_compare == slot_tp_compare) {
! 		c = half_compare(self, other);
! 		if (c <= 1)
! 			return c;
! 	}
! 	if (other->ob_type->tp_compare == slot_tp_compare) {
! 		c = half_compare(other, self);
! 		if (c < -1)
! 			return -2;
! 		if (c <= 1)
! 			return -c;
! 	}
! 	return (void *)self < (void *)other ? -1 :
! 		(void *)self > (void *)other ? 1 : 0;
  }
  
! static PyObject *
! slot_tp_repr(PyObject *self)
! {
! 	PyObject *func, *res;
! 
! 	func = PyObject_GetAttrString(self, "__repr__");
! 	if (func != NULL) {
! 		res = PyEval_CallObject(func, NULL);
! 		Py_DECREF(func);
! 		return res;
! 	}
! 	else {
! 		char buf[120];
! 		PyErr_Clear();
! 		sprintf(buf, "<%.80s object at %p>",
! 			self->ob_type->tp_name, self);
! 		return PyString_FromString(buf);
! 	}
! }
! 
! static PyObject *
! slot_tp_str(PyObject *self)
! {
! 	PyObject *func, *res;
! 
! 	func = PyObject_GetAttrString(self, "__str__");
! 	if (func != NULL) {
! 		res = PyEval_CallObject(func, NULL);
! 		Py_DECREF(func);
! 		return res;
! 	}
! 	else {
! 		PyErr_Clear();
! 		return slot_tp_repr(self);
! 	}
! }
  
  static long
  slot_tp_hash(PyObject *self)
  {
! 	PyObject *func, *res;
  	long h;
  
! 	func = PyObject_GetAttrString(self, "__hash__");
! 
! 	if (func != NULL) {
! 		res = PyEval_CallObject(func, NULL);
! 		Py_DECREF(func);
! 		if (res == NULL)
! 			return -1;
! 		h = PyInt_AsLong(res);
! 	}
! 	else {
! 		PyErr_Clear();
! 		func = PyObject_GetAttrString(self, "__eq__");
! 		if (func == NULL) {
! 			PyErr_Clear();
! 			func = PyObject_GetAttrString(self, "__cmp__");
! 		}
! 		if (func != NULL) {
! 			Py_DECREF(func);
! 			PyErr_SetString(PyExc_TypeError, "unhashable type");
! 			return -1;
! 		}
! 		PyErr_Clear();
! 		h = _Py_HashPointer((void *)self);
! 	}
  	if (h == -1 && !PyErr_Occurred())
  		h = -2;
***************
*** 2338,2344 ****
  }
  
- /* XXX This should cope with a missing __str__, and also look for __repr__ */
- SLOT0(slot_tp_str, "__str__")
- 
  static PyObject *
  slot_tp_getattro(PyObject *self, PyObject *name)
--- 2468,2471 ----
***************
*** 2386,2403 ****
  
  static PyObject *
  slot_tp_richcompare(PyObject *self, PyObject *other, int op)
  {
- 	/* XXX How should this cope with missing __xx__? */
- 	PyObject *meth = PyObject_GetAttrString(self, name_op[op]);
  	PyObject *res;
  
! 	if (meth == NULL)
! 		return NULL;
! 	res = PyObject_CallFunction(meth, "O", other);
! 	Py_DECREF(meth);
! 	return res;
  }
  
! SLOT0(slot_tp_iter, "__iter__")
  
  static PyObject *
--- 2513,2582 ----
  
  static PyObject *
+ half_richcompare(PyObject *self, PyObject *other, int op)
+ {
+ 	PyObject *func, *args, *res;
+ 
+ 	func = PyObject_GetAttrString(self, name_op[op]);
+ 	if (func == NULL) {
+ 		PyErr_Clear();
+ 		Py_INCREF(Py_NotImplemented);
+ 		return Py_NotImplemented;
+ 	}
+ 	args = Py_BuildValue("(O)", other);
+ 	if (args == NULL)
+ 		res = NULL;
+ 	else {
+ 		res = PyObject_CallObject(func, args);
+ 		Py_DECREF(args);
+ 	}
+ 	Py_DECREF(func);
+ 	return res;
+ }
+ 
+ /* Map rich comparison operators to their swapped version, e.g. LT --> GT */
+ static int swapped_op[] = {Py_GT, Py_GE, Py_EQ, Py_NE, Py_LT, Py_LE};
+ 
+ static PyObject *
  slot_tp_richcompare(PyObject *self, PyObject *other, int op)
  {
  	PyObject *res;
  
! 	if (self->ob_type->tp_richcompare == slot_tp_richcompare) {
! 		res = half_richcompare(self, other, op);
! 		if (res != Py_NotImplemented)
! 			return res;
! 		Py_DECREF(res);
! 	}
! 	if (other->ob_type->tp_richcompare == slot_tp_richcompare) {
! 		res = half_richcompare(other, self, swapped_op[op]);
! 		if (res != Py_NotImplemented) {
! 			return res;
! 		}
! 		Py_DECREF(res);
! 	}
! 	Py_INCREF(Py_NotImplemented);
! 	return Py_NotImplemented;
  }
  
! static PyObject *
! slot_tp_iter(PyObject *self)
! {
! 	PyObject *func, *res;
! 
! 	func = PyObject_GetAttrString(self, "__iter__");
! 	if (func != NULL) {
! 		 res = PyObject_CallObject(func, NULL);
! 		 Py_DECREF(func);
! 		 return res;
! 	}
! 	PyErr_Clear();
! 	func = PyObject_GetAttrString(self, "__getitem__");
! 	if (func == NULL) {
! 		PyErr_SetString(PyExc_TypeError, "iter() of non-sequence");
! 		return NULL;
! 	}
! 	Py_DECREF(func);
! 	return PySeqIter_New(self);
! }
  
  static PyObject *