diff options
Diffstat (limited to 'Objects/object.c')
-rw-r--r-- | Objects/object.c | 552 |
1 files changed, 177 insertions, 375 deletions
diff --git a/Objects/object.c b/Objects/object.c index 80111b4..9bcf08b 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -252,14 +252,6 @@ _PyObject_NewVar(PyTypeObject *tp, Py_ssize_t nitems) return PyObject_INIT_VAR(op, tp, nitems); } -/* for binary compatibility with 2.2 */ -#undef _PyObject_Del -void -_PyObject_Del(PyObject *op) -{ - PyObject_FREE(op); -} - /* Implementation of PyObject_Print with recursion checking */ static int internal_print(PyObject *op, FILE *fp, int flags, int nesting) @@ -513,431 +505,200 @@ PyObject_Unicode(PyObject *v) #endif -/* Helper to warn about deprecated tp_compare return values. Return: - -2 for an exception; - -1 if v < w; - 0 if v == w; - 1 if v > w. - (This function cannot return 2.) -*/ -static int -adjust_tp_compare(int c) -{ - if (PyErr_Occurred()) { - if (c != -1 && c != -2) { - PyObject *t, *v, *tb; - PyErr_Fetch(&t, &v, &tb); - if (PyErr_Warn(PyExc_RuntimeWarning, - "tp_compare didn't return -1 or -2 " - "for exception") < 0) { - Py_XDECREF(t); - Py_XDECREF(v); - Py_XDECREF(tb); - } - else - PyErr_Restore(t, v, tb); - } - return -2; - } - else if (c < -1 || c > 1) { - if (PyErr_Warn(PyExc_RuntimeWarning, - "tp_compare didn't return -1, 0 or 1") < 0) - return -2; - else - return c < -1 ? -1 : 1; - } - else { - assert(c >= -1 && c <= 1); - return c; - } -} +/* The new comparison philosophy is: we completely separate three-way + comparison from rich comparison. That is, PyObject_Compare() and + PyObject_Cmp() *just* use the tp_compare slot. And PyObject_RichCompare() + and PyObject_RichCompareBool() *just* use the tp_richcompare slot. + + See (*) below for practical amendments. + IOW, only cmp() uses tp_compare; the comparison operators (==, !=, <=, <, + >=, >) only use tp_richcompare. Note that list.sort() only uses <. -/* Macro to get the tp_richcompare field of a type if defined */ -#define RICHCOMPARE(t) ((t)->tp_richcompare) + (And yes, eventually we'll rip out cmp() and tp_compare.) -/* Map rich comparison operators to their swapped version, e.g. LT --> GT */ -int _Py_SwappedOp[] = {Py_GT, Py_GE, Py_EQ, Py_NE, Py_LT, Py_LE}; + The calling conventions are different: tp_compare only gets called with two + objects of the appropriate type; tp_richcompare gets called with a first + argument of the appropriate type and a second object of an arbitrary type. + We never do any kind of coercion. -/* Try a genuine rich comparison, returning an object. Return: - NULL for exception; - NotImplemented if this particular rich comparison is not implemented or - undefined; - some object not equal to NotImplemented if it is implemented - (this latter object may not be a Boolean). -*/ -static PyObject * -try_rich_compare(PyObject *v, PyObject *w, int op) -{ - richcmpfunc f; - PyObject *res; + The return conventions are also different. - 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, _Py_SwappedOp[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) - return res; - Py_DECREF(res); - } - if ((f = RICHCOMPARE(w->ob_type)) != NULL) { - return (*f)(w, v, _Py_SwappedOp[op]); - } - res = Py_NotImplemented; - Py_INCREF(res); - return res; -} + The tp_compare slot should return a C int, as follows: -/* Try a genuine rich comparison, returning an int. Return: - -1 for exception (including the case where try_rich_compare() returns an - object that's not a Boolean); - 0 if the outcome is false; - 1 if the outcome is true; - 2 if this particular rich comparison is not implemented or undefined. -*/ -static int -try_rich_compare_bool(PyObject *v, PyObject *w, int op) -{ - PyObject *res; - int ok; + -1 if a < b or if an exception occurred + 0 if a == b + +1 if a > b - if (RICHCOMPARE(v->ob_type) == NULL && RICHCOMPARE(w->ob_type) == NULL) - return 2; /* Shortcut, avoid INCREF+DECREF */ - res = try_rich_compare(v, w, op); - if (res == NULL) - return -1; - if (res == Py_NotImplemented) { - Py_DECREF(res); - return 2; - } - ok = PyObject_IsTrue(res); - Py_DECREF(res); - return ok; -} + No other return values are allowed. PyObject_Compare() has the same + calling convention. -/* Try rich comparisons to determine a 3-way comparison. Return: - -2 for an exception; - -1 if v < w; - 0 if v == w; - 1 if v > w; - 2 if this particular rich comparison is not implemented or undefined. -*/ -static int -try_rich_to_3way_compare(PyObject *v, PyObject *w) -{ - static struct { int op; int outcome; } tries[3] = { - /* Try this operator, and if it is true, use this outcome: */ - {Py_EQ, 0}, - {Py_LT, -1}, - {Py_GT, 1}, - }; - int i; - - if (RICHCOMPARE(v->ob_type) == NULL && RICHCOMPARE(w->ob_type) == NULL) - return 2; /* Shortcut */ - - for (i = 0; i < 3; i++) { - switch (try_rich_compare_bool(v, w, tries[i].op)) { - case -1: - return -2; - case 1: - return tries[i].outcome; - } - } + The tp_richcompare slot should return an object, as follows: - return 2; -} + NULL if an exception occurred + NotImplemented if the requested comparison is not implemented + any other false value if the requested comparison is false + any other true value if the requested comparison is true -/* Try a 3-way comparison, returning an int. Return: - -2 for an exception; - -1 if v < w; - 0 if v == w; - 1 if v > w; - 2 if this particular 3-way comparison is not implemented or undefined. -*/ -static int -try_3way_compare(PyObject *v, PyObject *w) -{ - int c; - cmpfunc f; + The PyObject_RichCompare[Bool]() wrappers raise TypeError when they get + NotImplemented. - /* Comparisons involving instances are given to instance_compare, - which has the same return conventions as this function. */ - - f = v->ob_type->tp_compare; - - /* If both have the same (non-NULL) tp_compare, use it. */ - if (f != NULL && f == w->ob_type->tp_compare) { - c = (*f)(v, w); - return adjust_tp_compare(c); - } - - /* If either tp_compare is _PyObject_SlotCompare, that's safe. */ - if (f == _PyObject_SlotCompare || - w->ob_type->tp_compare == _PyObject_SlotCompare) - return _PyObject_SlotCompare(v, w); - - /* If we're here, v and w, - a) are not instances; - b) have different types or a type without tp_compare; and - c) don't have a user-defined tp_compare. - tp_compare implementations in C assume that both arguments - have their type, so we give up if the coercion fails. - */ - c = PyNumber_CoerceEx(&v, &w); - if (c < 0) - return -2; - if (c > 0) - return 2; - f = v->ob_type->tp_compare; - if (f != NULL && f == w->ob_type->tp_compare) { - c = (*f)(v, w); - Py_DECREF(v); - Py_DECREF(w); - return adjust_tp_compare(c); - } + (*) Practical amendments: - /* No comparison defined */ - Py_DECREF(v); - Py_DECREF(w); - return 2; -} + - If rich comparison returns NotImplemented, == and != are decided by + comparing the object pointer (i.e. falling back to the base object + implementation). + + - If three-way comparison is not implemented, it falls back on rich + comparison (but not the other way around!). -/* Final fallback 3-way comparison, returning an int. Return: - -2 if an error occurred; - -1 if v < w; - 0 if v == w; - 1 if v > w. */ -static int -default_3way_compare(PyObject *v, PyObject *w) -{ - int c; - const char *vname, *wname; - if (v->ob_type == w->ob_type) { - /* When comparing these pointers, they must be cast to - * integer types (i.e. Py_uintptr_t, our spelling of C9X's - * uintptr_t). ANSI specifies that pointer compares other - * than == and != to non-related structures are undefined. - */ - Py_uintptr_t vv = (Py_uintptr_t)v; - Py_uintptr_t ww = (Py_uintptr_t)w; - return (vv < ww) ? -1 : (vv > ww) ? 1 : 0; - } +/* Forward */ +static PyObject *do_richcompare(PyObject *v, PyObject *w, int op); - /* None is smaller than anything */ - if (v == Py_None) - return -1; - if (w == Py_None) - return 1; - - /* different type: compare type names; numbers are smaller */ - if (PyNumber_Check(v)) - vname = ""; - else - vname = v->ob_type->tp_name; - if (PyNumber_Check(w)) - wname = ""; - else - wname = w->ob_type->tp_name; - c = strcmp(vname, wname); - if (c < 0) - return -1; - if (c > 0) - return 1; - /* Same type name, or (more likely) incomparable numeric types */ - return ((Py_uintptr_t)(v->ob_type) < ( - Py_uintptr_t)(w->ob_type)) ? -1 : 1; -} - -/* Do a 3-way comparison, by hook or by crook. Return: - -2 for an exception (but see below); - -1 if v < w; - 0 if v == w; - 1 if v > w; - BUT: if the object implements a tp_compare function, it returns - whatever this function returns (whether with an exception or not). -*/ +/* Perform a three-way comparison, raising TypeError if three-way comparison + is not supported. */ static int -do_cmp(PyObject *v, PyObject *w) +do_compare(PyObject *v, PyObject *w) { - int c; cmpfunc f; + int ok; - if (v->ob_type == w->ob_type - && (f = v->ob_type->tp_compare) != NULL) { - c = (*f)(v, w); - return adjust_tp_compare(c); - } - /* We only get here if one of the following is true: - a) v and w have different types - b) v and w have the same type, which doesn't have tp_compare - c) v and w are instances, and either __cmp__ is not defined or - __cmp__ returns NotImplemented - */ - c = try_rich_to_3way_compare(v, w); - if (c < 2) - return c; - c = try_3way_compare(v, w); - if (c < 2) - return c; - return default_3way_compare(v, w); -} - -/* Compare v to w. Return - -1 if v < w or exception (PyErr_Occurred() true in latter case). - 0 if v == w. - 1 if v > w. - XXX The docs (C API manual) say the return value is undefined in case - XXX of error. -*/ + if (v->ob_type == w->ob_type && + (f = v->ob_type->tp_compare) != NULL) { + return (*f)(v, w); + } + + /* Now try three-way compare before giving up. This is intentionally + elaborate; if you have a it will raise TypeError if it detects two + objects that aren't ordered with respect to each other. */ + ok = PyObject_RichCompareBool(v, w, Py_LT); + if (ok < 0) + return -1; /* Error */ + if (ok) + return -1; /* Less than */ + ok = PyObject_RichCompareBool(v, w, Py_GT); + if (ok < 0) + return -1; /* Error */ + if (ok) + return 1; /* Greater than */ + ok = PyObject_RichCompareBool(v, w, Py_EQ); + if (ok < 0) + return -1; /* Error */ + if (ok) + return 0; /* Equal */ + + /* Give up */ + PyErr_Format(PyExc_TypeError, + "unorderable types: '%.100s' <> '%.100s'", + v->ob_type->tp_name, + w->ob_type->tp_name); + return -1; +} + +/* Perform a three-way comparison. This wraps do_compare() with a check for + NULL arguments and a recursion check. */ int PyObject_Compare(PyObject *v, PyObject *w) { - int result; + int res; if (v == NULL || w == NULL) { - PyErr_BadInternalCall(); + if (!PyErr_Occurred()) + PyErr_BadInternalCall(); return -1; } - if (v == w) - return 0; if (Py_EnterRecursiveCall(" in cmp")) return -1; - result = do_cmp(v, w); + res = do_compare(v, w); Py_LeaveRecursiveCall(); - return result < 0 ? -1 : result; + return res < 0 ? -1 : res; } -/* Return (new reference to) Py_True or Py_False. */ -static PyObject * -convert_3way_to_object(int op, int c) -{ - PyObject *result; - switch (op) { - case Py_LT: c = c < 0; break; - case Py_LE: c = c <= 0; break; - case Py_EQ: c = c == 0; break; - case Py_NE: c = c != 0; break; - case Py_GT: c = c > 0; break; - case Py_GE: c = c >= 0; break; - } - result = c ? Py_True : Py_False; - Py_INCREF(result); - return result; -} - -/* We want a rich comparison but don't have one. Try a 3-way cmp instead. - Return - NULL if error - Py_True if v op w - Py_False if not (v op w) -*/ -static PyObject * -try_3way_to_rich_compare(PyObject *v, PyObject *w, int op) -{ - int c; +/* Map rich comparison operators to their swapped version, e.g. LT <--> GT */ +int _Py_SwappedOp[] = {Py_GT, Py_GE, Py_EQ, Py_NE, Py_LT, Py_LE}; - c = try_3way_compare(v, w); - if (c >= 2) - c = default_3way_compare(v, w); - if (c <= -2) - return NULL; - return convert_3way_to_object(op, c); -} +static char *opstrings[] = {">", ">=", "==", "!=", "<", "<="}; -/* Do rich comparison on v and w. Return - NULL if error - Else a new reference to an object other than Py_NotImplemented, usually(?): - Py_True if v op w - Py_False if not (v op w) -*/ +/* Perform a rich comparison, raising TypeError when the requested comparison + operator is not supported. */ static PyObject * -do_richcmp(PyObject *v, PyObject *w, int op) +do_richcompare(PyObject *v, PyObject *w, int op) { + richcmpfunc f; PyObject *res; - res = try_rich_compare(v, w, op); - if (res != Py_NotImplemented) - return res; - Py_DECREF(res); - - return try_3way_to_rich_compare(v, w, op); + if (v->ob_type != w->ob_type && + PyType_IsSubtype(w->ob_type, v->ob_type) && + (f = w->ob_type->tp_richcompare) != NULL) { + res = (*f)(w, v, _Py_SwappedOp[op]); + if (res != Py_NotImplemented) + return res; + Py_DECREF(res); + } + if ((f = v->ob_type->tp_richcompare) != NULL) { + res = (*f)(v, w, op); + if (res != Py_NotImplemented) + return res; + Py_DECREF(res); + } + if ((f = w->ob_type->tp_richcompare) != NULL) { + res = (*f)(w, v, _Py_SwappedOp[op]); + if (res != Py_NotImplemented) + return res; + Py_DECREF(res); + } + /* If neither object implements it, provide a sensible default + for == and !=, but raise an exception for ordering. */ + switch (op) { + case Py_EQ: + res = (v == w) ? Py_True : Py_False; + break; + case Py_NE: + res = (v != w) ? Py_True : Py_False; + break; + default: + PyErr_Format(PyExc_TypeError, + "unorderable types: %.100s() %s %.100s()", + v->ob_type->tp_name, + opstrings[op], + w->ob_type->tp_name); + return NULL; + } + Py_INCREF(res); + return res; } -/* Return: - NULL for exception; - some object not equal to NotImplemented if it is implemented - (this latter object may not be a Boolean). -*/ +/* Perform a rich comparison with object result. This wraps do_richcompare() + with a check for NULL arguments and a recursion check. */ + PyObject * PyObject_RichCompare(PyObject *v, PyObject *w, int op) { PyObject *res; assert(Py_LT <= op && op <= Py_GE); - if (Py_EnterRecursiveCall(" in cmp")) + if (v == NULL || w == NULL) { + if (!PyErr_Occurred()) + PyErr_BadInternalCall(); return NULL; - - /* If the types are equal, and not old-style instances, try to - get out cheap (don't bother with coercions etc.). */ - if (v->ob_type == w->ob_type) { - cmpfunc fcmp; - richcmpfunc frich = RICHCOMPARE(v->ob_type); - /* If the type has richcmp, try it first. try_rich_compare - tries it two-sided, which is not needed since we've a - single type only. */ - if (frich != NULL) { - res = (*frich)(v, w, op); - if (res != Py_NotImplemented) - goto Done; - Py_DECREF(res); - } - /* No richcmp, or this particular richmp not implemented. - Try 3-way cmp. */ - fcmp = v->ob_type->tp_compare; - if (fcmp != NULL) { - int c = (*fcmp)(v, w); - c = adjust_tp_compare(c); - if (c == -2) { - res = NULL; - goto Done; - } - res = convert_3way_to_object(op, c); - goto Done; - } } - - /* Fast path not taken, or couldn't deliver a useful result. */ - res = do_richcmp(v, w, op); -Done: + if (Py_EnterRecursiveCall(" in cmp")) + return NULL; + res = do_richcompare(v, w, op); Py_LeaveRecursiveCall(); return res; } -/* Return -1 if error; 1 if v op w; 0 if not (v op w). */ +/* Perform a rich comparison with integer result. This wraps + PyObject_RichCompare(), returning -1 for error, 0 for false, 1 for true. */ int PyObject_RichCompareBool(PyObject *v, PyObject *w, int op) { PyObject *res; int ok; - /* Quick result when objects are the same. - Guarantees that identity implies equality. */ - if (v == w) { - if (op == Py_EQ) - return 1; - else if (op == Py_NE) - return 0; - } - res = PyObject_RichCompare(v, w, op); if (res == NULL) return -1; @@ -949,6 +710,44 @@ PyObject_RichCompareBool(PyObject *v, PyObject *w, int op) return ok; } +/* Turn the result of a three-way comparison into the result expected by a + rich comparison. */ +PyObject * +Py_CmpToRich(int op, int cmp) +{ + PyObject *res; + int ok; + + if (PyErr_Occurred()) + return NULL; + switch (op) { + case Py_LT: + ok = cmp < 0; + break; + case Py_LE: + ok = cmp <= 0; + break; + case Py_EQ: + ok = cmp == 0; + break; + case Py_NE: + ok = cmp != 0; + break; + case Py_GT: + ok = cmp > 0; + break; + case Py_GE: + ok = cmp >= 0; + break; + default: + PyErr_BadArgument(); + return NULL; + } + res = ok ? Py_True : Py_False; + Py_INCREF(res); + return res; +} + /* Set of hash utility functions to help maintaining the invariant that if a==b then hash(a)==hash(b) @@ -1832,6 +1631,9 @@ _Py_ReadyTypes(void) if (PyType_Ready(&PyNotImplemented_Type) < 0) Py_FatalError("Can't initialize type(NotImplemented)"); + + if (PyType_Ready(&PyCode_Type) < 0) + Py_FatalError("Can't initialize 'code'"); } |