Changes for PEP 208. PyObject_Compare has been rewritten. Instances no

longer get special treatment.  The Py_NotImplemented type is here as well.
This commit is contained in:
Neil Schemenauer 2001-01-04 01:48:10 +00:00
parent ba872e2534
commit 5ed85ec0c0
1 changed files with 139 additions and 118 deletions

View File

@ -308,20 +308,96 @@ PyObject_Str(PyObject *v)
return res;
}
static PyObject *
#define NEW_STYLE_NUMBER(o) PyType_HasFeature((o)->ob_type, \
Py_TPFLAGS_NEWSTYLENUMBER)
static int
cmp_to_int(PyObject *result)
{
int c;
if (result == NULL)
return -1;
if (!PyInt_Check(result)) {
PyErr_SetString(PyExc_TypeError,
"comparison did not return an int");
return -1;
}
c = PyInt_AS_LONG(result);
Py_DECREF(result);
return (c < 0) ? -1 : (c > 0) ? 1 : 0;
}
static int
do_cmp(PyObject *v, PyObject *w)
{
long c;
/* __rcmp__ actually won't be called unless __cmp__ isn't defined,
because the check in cmpobject() reverses the objects first.
This is intentional -- it makes no sense to define cmp(x,y)
different than -cmp(y,x). */
if (PyInstance_Check(v) || PyInstance_Check(w))
return PyInstance_DoBinOp(v, w, "__cmp__", "__rcmp__", do_cmp);
c = PyObject_Compare(v, w);
if (c && PyErr_Occurred())
return NULL;
return PyInt_FromLong(c);
PyNumberMethods *mv, *mw;
PyObject *x;
int c;
/* new style nb_cmp gets priority */
mv = v->ob_type->tp_as_number;
if (mv != NULL && NEW_STYLE_NUMBER(v) && mv->nb_cmp) {
x = (*mv->nb_cmp)(v, w);
if (x != Py_NotImplemented)
return cmp_to_int(x);
Py_DECREF(x);
}
mw = w->ob_type->tp_as_number;
if (mw != NULL && NEW_STYLE_NUMBER(w) && mw->nb_cmp) {
x = (*mw->nb_cmp)(v, w);
if (x != Py_NotImplemented)
return cmp_to_int(x);
Py_DECREF(x);
}
/* fall back to tp_compare */
if (v->ob_type == w->ob_type) {
if (v->ob_type->tp_compare != NULL) {
return (*v->ob_type->tp_compare)(v, w);
}
else {
Py_uintptr_t iv = (Py_uintptr_t)v;
Py_uintptr_t iw = (Py_uintptr_t)w;
return (iv < iw) ? -1 : (iv > iw) ? 1 : 0;
}
}
if (PyUnicode_Check(v) || PyUnicode_Check(w)) {
c = PyUnicode_Compare(v, w);
if (c == -1 &&
PyErr_Occurred() &&
PyErr_ExceptionMatches(PyExc_TypeError))
/* TypeErrors are ignored: if Unicode coercion
fails due to one of the arguments not having
the right type, we continue as defined by the
coercion protocol (see above). Luckily,
decoding errors are reported as ValueErrors and
are not masked by this technique. */
PyErr_Clear();
else
return c;
}
/* fall back to coercion */
if (mv && mw && (!NEW_STYLE_NUMBER(v) || !NEW_STYLE_NUMBER(w))) {
/* old style operand, both operations numeric, coerce */
int err = PyNumber_CoerceEx(&v, &w);
if (err < 0)
return -1;
if (err == 0) {
if (v->ob_type->tp_compare) {
c = (*v->ob_type->tp_compare)(v, w);
}
else {
Py_uintptr_t iv = (Py_uintptr_t)v;
Py_uintptr_t iw = (Py_uintptr_t)w;
c = (iv < iw) ? -1 : (iv > iw) ? 1 : 0;
}
Py_DECREF(v);
Py_DECREF(w);
return c;
}
}
/* last resort, use type names */
c = strcmp(v->ob_type->tp_name, w->ob_type->tp_name);
return (c < 0) ? -1: (c > 0) ? 1 : 0;
}
PyObject *_PyCompareState_Key;
@ -401,128 +477,42 @@ PyObject_Compare(PyObject *v, PyObject *w)
}
if (v == w)
return 0;
if (PyInstance_Check(v) || PyInstance_Check(w)) {
PyObject *res;
int c;
if (!PyInstance_Check(v))
return -PyObject_Compare(w, v);
_PyCompareState_nesting++;
if (_PyCompareState_nesting > NESTING_LIMIT) {
PyObject *inprogress, *pair;
inprogress = get_inprogress_dict();
if (inprogress == NULL) {
_PyCompareState_nesting--;
return -1;
}
pair = make_pair(v, w);
if (PyDict_GetItem(inprogress, pair)) {
/* already comparing these objects. assume
they're equal until shown otherwise */
Py_DECREF(pair);
_PyCompareState_nesting--;
return 0;
}
if (PyDict_SetItem(inprogress, pair, pair) == -1) {
_PyCompareState_nesting--;
return -1;
}
res = do_cmp(v, w);
/* XXX DelItem shouldn't fail */
PyDict_DelItem(inprogress, pair);
Py_DECREF(pair);
} else {
res = do_cmp(v, w);
}
_PyCompareState_nesting--;
if (res == NULL)
return -1;
if (!PyInt_Check(res)) {
Py_DECREF(res);
PyErr_SetString(PyExc_TypeError,
"comparison did not return an int");
return -1;
}
c = PyInt_AsLong(res);
Py_DECREF(res);
return (c < 0) ? -1 : (c > 0) ? 1 : 0;
}
if ((vtp = v->ob_type) != (wtp = w->ob_type)) {
char *vname = vtp->tp_name;
char *wname = wtp->tp_name;
if (vtp->tp_as_number != NULL && wtp->tp_as_number != NULL) {
int err;
err = PyNumber_CoerceEx(&v, &w);
if (err < 0)
return -1;
else if (err == 0) {
int cmp;
vtp = v->ob_type;
if (vtp->tp_compare == NULL)
cmp = (v < w) ? -1 : 1;
else
cmp = (*vtp->tp_compare)(v, w);
Py_DECREF(v);
Py_DECREF(w);
return cmp;
}
}
else if (PyUnicode_Check(v) || PyUnicode_Check(w)) {
int result = PyUnicode_Compare(v, w);
if (result == -1 && PyErr_Occurred() &&
PyErr_ExceptionMatches(PyExc_TypeError))
/* TypeErrors are ignored: if Unicode coercion
fails due to one of the arguments not
having the right type, we continue as
defined by the coercion protocol (see
above). Luckily, decoding errors are
reported as ValueErrors and are not masked
by this technique. */
PyErr_Clear();
else
return result;
}
else if (vtp->tp_as_number != NULL)
vname = "";
else if (wtp->tp_as_number != NULL)
wname = "";
/* Numerical types compare smaller than all other types */
return strcmp(vname, wname);
}
if (vtp->tp_compare == NULL) {
Py_uintptr_t iv = (Py_uintptr_t)v;
Py_uintptr_t iw = (Py_uintptr_t)w;
return (iv < iw) ? -1 : 1;
}
vtp = v->ob_type;
wtp = w->ob_type;
_PyCompareState_nesting++;
if (_PyCompareState_nesting > NESTING_LIMIT
&& (vtp->tp_as_mapping
|| (vtp->tp_as_sequence && !PyString_Check(v)))) {
if (_PyCompareState_nesting > NESTING_LIMIT &&
(vtp->tp_as_mapping
|| PyInstance_Check(v)
|| (vtp->tp_as_sequence && !PyString_Check(v)))) {
/* try to detect circular data structures */
PyObject *inprogress, *pair;
inprogress = get_inprogress_dict();
if (inprogress == NULL) {
_PyCompareState_nesting--;
return -1;
result = -1;
goto exit_cmp;
}
pair = make_pair(v, w);
if (PyDict_GetItem(inprogress, pair)) {
/* already comparing these objects. assume
they're equal until shown otherwise */
Py_DECREF(pair);
_PyCompareState_nesting--;
return 0;
result = 0;
goto exit_cmp;
}
if (PyDict_SetItem(inprogress, pair, pair) == -1) {
_PyCompareState_nesting--;
return -1;
result = -1;
goto exit_cmp;
}
result = (*vtp->tp_compare)(v, w);
PyDict_DelItem(inprogress, pair); /* XXX shouldn't fail */
result = do_cmp(v, w);
/* XXX DelItem shouldn't fail */
PyDict_DelItem(inprogress, pair);
Py_DECREF(pair);
} else {
result = (*vtp->tp_compare)(v, w);
}
else {
result = do_cmp(v, w);
}
exit_cmp:
_PyCompareState_nesting--;
return result;
}
@ -917,6 +907,37 @@ PyObject _Py_NoneStruct = {
PyObject_HEAD_INIT(&PyNothing_Type)
};
/* NotImplemented is an object that can be used to signal that an
operation is not implemented for the given type combination. */
static PyObject *
NotImplemented_repr(PyObject *op)
{
return PyString_FromString("NotImplemented");
}
static PyTypeObject PyNotImplemented_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
"NotImplemented",
0,
0,
0, /*tp_dealloc*/ /*never called*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
(reprfunc)NotImplemented_repr, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
};
PyObject _Py_NotImplementedStruct = {
PyObject_HEAD_INIT(&PyNotImplemented_Type)
};
#ifdef Py_TRACE_REFS