mirror of https://github.com/python/cpython
Patch #424475: Speed-up tp_compare usage, by special-casing the common
case of objects with equal types which support tp_compare. Give type objects a tp_compare function. Also add c<0 tests before a few PyErr_Occurred tests.
This commit is contained in:
parent
7bc50714fe
commit
0163d6d6ef
|
@ -22,7 +22,7 @@ class UserList:
|
|||
if isinstance(other, UserList): return other.data
|
||||
else: return other
|
||||
def __cmp__(self, other):
|
||||
raise RuntimeError, "UserList.__cmp__() is obsolete"
|
||||
return cmp(self.data, self.__cast(other))
|
||||
def __contains__(self, item): return item in self.data
|
||||
def __len__(self): return len(self.data)
|
||||
def __getitem__(self, i): return self.data[i]
|
||||
|
|
|
@ -477,16 +477,6 @@ try_3way_compare(PyObject *v, PyObject *w)
|
|||
if (PyInstance_Check(w))
|
||||
return (*w->ob_type->tp_compare)(v, w);
|
||||
|
||||
/* If the types are equal, don't bother with coercions etc. */
|
||||
if (v->ob_type == w->ob_type) {
|
||||
if ((f = v->ob_type->tp_compare) == NULL)
|
||||
return 2;
|
||||
c = (*f)(v, w);
|
||||
if (PyErr_Occurred())
|
||||
return -2;
|
||||
return c < 0 ? -1 : c > 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
/* Try coercion; if it fails, give up */
|
||||
c = PyNumber_CoerceEx(&v, &w);
|
||||
if (c < 0)
|
||||
|
@ -499,7 +489,7 @@ try_3way_compare(PyObject *v, PyObject *w)
|
|||
c = (*f)(v, w);
|
||||
Py_DECREF(v);
|
||||
Py_DECREF(w);
|
||||
if (PyErr_Occurred())
|
||||
if (c < 0 && PyErr_Occurred())
|
||||
return -2;
|
||||
return c < 0 ? -1 : c > 0 ? 1 : 0;
|
||||
}
|
||||
|
@ -509,7 +499,7 @@ try_3way_compare(PyObject *v, PyObject *w)
|
|||
c = (*f)(w, v); /* swapped! */
|
||||
Py_DECREF(v);
|
||||
Py_DECREF(w);
|
||||
if (PyErr_Occurred())
|
||||
if (c < 0 && PyErr_Occurred())
|
||||
return -2;
|
||||
return c < 0 ? 1 : c > 0 ? -1 : 0; /* negated! */
|
||||
}
|
||||
|
@ -590,12 +580,18 @@ default_3way_compare(PyObject *v, PyObject *w)
|
|||
-1 if v < w;
|
||||
0 if v == w;
|
||||
1 if v > w;
|
||||
If the object implements a tp_compare function, it returns
|
||||
whatever this function returns (whether with an exception or not).
|
||||
*/
|
||||
static int
|
||||
do_cmp(PyObject *v, PyObject *w)
|
||||
{
|
||||
int c;
|
||||
cmpfunc f;
|
||||
|
||||
if (v->ob_type == w->ob_type
|
||||
&& (f = v->ob_type->tp_compare) != NULL)
|
||||
return (*f)(v, w);
|
||||
c = try_rich_to_3way_compare(v, w);
|
||||
if (c < 2)
|
||||
return c;
|
||||
|
@ -760,16 +756,9 @@ PyObject_Compare(PyObject *v, PyObject *w)
|
|||
}
|
||||
|
||||
static PyObject *
|
||||
try_3way_to_rich_compare(PyObject *v, PyObject *w, int op)
|
||||
convert_3way_to_object(int op, int c)
|
||||
{
|
||||
int c;
|
||||
PyObject *result;
|
||||
|
||||
c = try_3way_compare(v, w);
|
||||
if (c >= 2)
|
||||
c = default_3way_compare(v, w);
|
||||
if (c <= -2)
|
||||
return NULL;
|
||||
switch (op) {
|
||||
case Py_LT: c = c < 0; break;
|
||||
case Py_LE: c = c <= 0; break;
|
||||
|
@ -782,11 +771,51 @@ try_3way_to_rich_compare(PyObject *v, PyObject *w, int op)
|
|||
Py_INCREF(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
try_3way_to_rich_compare(PyObject *v, PyObject *w, int op)
|
||||
{
|
||||
int c;
|
||||
|
||||
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 PyObject *
|
||||
do_richcmp(PyObject *v, PyObject *w, int op)
|
||||
{
|
||||
PyObject *res;
|
||||
cmpfunc f;
|
||||
|
||||
/* If the types are equal, don't bother with coercions etc.
|
||||
Instances are special-cased in try_3way_compare, since
|
||||
a result of 2 does *not* mean one value being greater
|
||||
than the other. */
|
||||
if (v->ob_type == w->ob_type
|
||||
&& (f = v->ob_type->tp_compare) != NULL
|
||||
&& !PyInstance_Check(v)) {
|
||||
int c;
|
||||
richcmpfunc f1;
|
||||
if ((f1 = RICHCOMPARE(v->ob_type)) != NULL) {
|
||||
/* If the type has richcmp, try it first.
|
||||
try_rich_compare would try it two-sided,
|
||||
which is not needed since we've a single
|
||||
type only. */
|
||||
res = (*f1)(v, w, op);
|
||||
if (res != Py_NotImplemented)
|
||||
return res;
|
||||
Py_DECREF(res);
|
||||
}
|
||||
c = (*f)(v, w);
|
||||
if (c < 0 && PyErr_Occurred())
|
||||
return NULL;
|
||||
return convert_3way_to_object(op, c);
|
||||
}
|
||||
|
||||
res = try_rich_compare(v, w, op);
|
||||
if (res != Py_NotImplemented)
|
||||
|
|
|
@ -23,6 +23,16 @@ type_getattr(PyTypeObject *t, char *name)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
type_compare(PyObject *v, PyObject *w)
|
||||
{
|
||||
/* This is called with type objects only. So we
|
||||
can just compare the addresses. */
|
||||
Py_uintptr_t vv = (Py_uintptr_t)v;
|
||||
Py_uintptr_t ww = (Py_uintptr_t)w;
|
||||
return (vv < ww) ? -1 : (vv > ww) ? 1 : 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
type_repr(PyTypeObject *v)
|
||||
{
|
||||
|
@ -41,12 +51,12 @@ PyTypeObject PyType_Type = {
|
|||
0, /*tp_print*/
|
||||
(getattrfunc)type_getattr, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
0, /*tp_compare*/
|
||||
type_compare, /*tp_compare*/
|
||||
(reprfunc)type_repr, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
0, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
0, /*tp_hash*/
|
||||
_Py_HashPointer, /*tp_hash*/
|
||||
0, /*tp_call*/
|
||||
0, /*tp_str*/
|
||||
0, /*tp_xxx1*/
|
||||
|
|
Loading…
Reference in New Issue