Merge branch changes (coercion, rich comparisons) into trunk.
This commit is contained in:
parent
33f4d6d1db
commit
2ed6bf87c9
|
@ -560,10 +560,8 @@ complex_richcompare(PyObject *v, PyObject *w, int op)
|
|||
Py_INCREF(Py_NotImplemented);
|
||||
return Py_NotImplemented;
|
||||
}
|
||||
/* May sure both arguments use complex comparison.
|
||||
This implies PyComplex_Check(a) && PyComplex_Check(b). */
|
||||
if (v->ob_type->tp_richcompare != complex_richcompare ||
|
||||
w->ob_type->tp_richcompare != complex_richcompare) {
|
||||
/* Make sure both arguments are complex. */
|
||||
if (!(PyComplex_Check(v) && PyComplex_Check(w))) {
|
||||
Py_DECREF(v);
|
||||
Py_DECREF(w);
|
||||
Py_INCREF(Py_NotImplemented);
|
||||
|
|
|
@ -365,6 +365,14 @@ try_rich_compare(PyObject *v, PyObject *w, int op)
|
|||
richcmpfunc f;
|
||||
PyObject *res;
|
||||
|
||||
if (v->ob_type != w->ob_type &&
|
||||
PyType_IsSubtype(w->ob_type, v->ob_type) &&
|
||||
(f = RICHCOMPARE(w->ob_type)) != NULL) {
|
||||
res = (*f)(w, v, swapped_op[op]);
|
||||
if (res != Py_NotImplemented)
|
||||
return res;
|
||||
Py_DECREF(res);
|
||||
}
|
||||
if ((f = RICHCOMPARE(v->ob_type)) != NULL) {
|
||||
res = (*f)(v, w, op);
|
||||
if (res != Py_NotImplemented)
|
||||
|
|
|
@ -824,10 +824,8 @@ string_richcompare(PyStringObject *a, PyStringObject *b, int op)
|
|||
int min_len;
|
||||
PyObject *result;
|
||||
|
||||
/* May sure both arguments use string comparison.
|
||||
This implies PyString_Check(a) && PyString_Check(b). */
|
||||
if (a->ob_type->tp_richcompare != (richcmpfunc)string_richcompare ||
|
||||
b->ob_type->tp_richcompare != (richcmpfunc)string_richcompare) {
|
||||
/* Make sure both arguments are strings. */
|
||||
if (!(PyString_Check(a) && PyString_Check(b))) {
|
||||
result = Py_NotImplemented;
|
||||
goto out;
|
||||
}
|
||||
|
|
|
@ -1837,6 +1837,40 @@ BINARY(rshift, "x>>y");
|
|||
BINARY(and, "x&y");
|
||||
BINARY(xor, "x^y");
|
||||
BINARY(or, "x|y");
|
||||
|
||||
static PyObject *
|
||||
wrap_coercefunc(PyObject *self, PyObject *args, void *wrapped)
|
||||
{
|
||||
coercion func = (coercion)wrapped;
|
||||
PyObject *other, *res;
|
||||
int ok;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O", &other))
|
||||
return NULL;
|
||||
ok = func(&self, &other);
|
||||
if (ok < 0)
|
||||
return NULL;
|
||||
if (ok > 0) {
|
||||
Py_INCREF(Py_NotImplemented);
|
||||
return Py_NotImplemented;
|
||||
}
|
||||
res = PyTuple_New(2);
|
||||
if (res == NULL) {
|
||||
Py_DECREF(self);
|
||||
Py_DECREF(other);
|
||||
return NULL;
|
||||
}
|
||||
PyTuple_SET_ITEM(res, 0, self);
|
||||
PyTuple_SET_ITEM(res, 1, other);
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct wrapperbase tab_coerce[] = {
|
||||
{"__coerce__", (wrapperfunc)wrap_coercefunc,
|
||||
"x.__coerce__(y) <==> coerce(x, y)"},
|
||||
{0}
|
||||
};
|
||||
|
||||
BINARY(floordiv, "x//y");
|
||||
BINARY(truediv, "x/y # true division");
|
||||
|
||||
|
@ -2573,7 +2607,7 @@ add_operators(PyTypeObject *type)
|
|||
ADD(nb->nb_and, tab_and);
|
||||
ADD(nb->nb_xor, tab_xor);
|
||||
ADD(nb->nb_or, tab_or);
|
||||
/* We don't support coerce() -- see above comment */
|
||||
ADD(nb->nb_coerce, tab_coerce);
|
||||
ADD(nb->nb_int, tab_int);
|
||||
ADD(nb->nb_long, tab_long);
|
||||
ADD(nb->nb_float, tab_float);
|
||||
|
@ -2840,7 +2874,64 @@ SLOT1BIN(slot_nb_rshift, nb_rshift, "__rshift__", "__rrshift__")
|
|||
SLOT1BIN(slot_nb_and, nb_and, "__and__", "__rand__")
|
||||
SLOT1BIN(slot_nb_xor, nb_xor, "__xor__", "__rxor__")
|
||||
SLOT1BIN(slot_nb_or, nb_or, "__or__", "__ror__")
|
||||
/* Not coerce() */
|
||||
|
||||
static int
|
||||
slot_nb_coerce(PyObject **a, PyObject **b)
|
||||
{
|
||||
static PyObject *coerce_str;
|
||||
PyObject *self = *a, *other = *b;
|
||||
|
||||
if (self->ob_type->tp_as_number != NULL &&
|
||||
self->ob_type->tp_as_number->nb_coerce == slot_nb_coerce) {
|
||||
PyObject *r;
|
||||
r = call_maybe(
|
||||
self, "__coerce__", &coerce_str, "(O)", other);
|
||||
if (r == NULL)
|
||||
return -1;
|
||||
if (r == Py_NotImplemented) {
|
||||
Py_DECREF(r);
|
||||
return 1;
|
||||
}
|
||||
if (!PyTuple_Check(r) || PyTuple_GET_SIZE(r) != 2) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"__coerce__ didn't return a 2-tuple");
|
||||
Py_DECREF(r);
|
||||
return -1;
|
||||
}
|
||||
*a = PyTuple_GET_ITEM(r, 0);
|
||||
Py_INCREF(*a);
|
||||
*b = PyTuple_GET_ITEM(r, 1);
|
||||
Py_INCREF(*b);
|
||||
Py_DECREF(r);
|
||||
return 0;
|
||||
}
|
||||
if (other->ob_type->tp_as_number != NULL &&
|
||||
other->ob_type->tp_as_number->nb_coerce == slot_nb_coerce) {
|
||||
PyObject *r;
|
||||
r = call_maybe(
|
||||
other, "__coerce__", &coerce_str, "(O)", self);
|
||||
if (r == NULL)
|
||||
return -1;
|
||||
if (r == Py_NotImplemented) {
|
||||
Py_DECREF(r);
|
||||
return 1;
|
||||
}
|
||||
if (!PyTuple_Check(r) || PyTuple_GET_SIZE(r) != 2) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"__coerce__ didn't return a 2-tuple");
|
||||
Py_DECREF(r);
|
||||
return -1;
|
||||
}
|
||||
*a = PyTuple_GET_ITEM(r, 1);
|
||||
Py_INCREF(*a);
|
||||
*b = PyTuple_GET_ITEM(r, 0);
|
||||
Py_INCREF(*b);
|
||||
Py_DECREF(r);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
SLOT0(slot_nb_int, "__int__")
|
||||
SLOT0(slot_nb_long, "__long__")
|
||||
SLOT0(slot_nb_float, "__float__")
|
||||
|
@ -3336,7 +3427,7 @@ override_slots(PyTypeObject *type, PyObject *dict)
|
|||
NBSLOT("__and__", nb_and, slot_nb_and);
|
||||
NBSLOT("__xor__", nb_xor, slot_nb_xor);
|
||||
NBSLOT("__or__", nb_or, slot_nb_or);
|
||||
/* Not coerce() */
|
||||
NBSLOT("__coerce__", nb_coerce, slot_nb_coerce);
|
||||
NBSLOT("__int__", nb_int, slot_nb_int);
|
||||
NBSLOT("__long__", nb_long, slot_nb_long);
|
||||
NBSLOT("__float__", nb_float, slot_nb_float);
|
||||
|
|
Loading…
Reference in New Issue