Rich comparisons:

- Use PyObject_RichCompareBool() when comparing keys; this makes the
  error handling cleaner.

- There were two implementations for dictionary comparison, an old one
  (#ifdef'ed out) and a new one.  Got rid of the old one, which was
  abandoned years ago.

- In the characterize() function, part of dictionary comparison, use
  PyObject_RichCompareBool() to compare keys and values instead.  But
  continue to use PyObject_Compare() for comparing the final
  (deciding) elements.

- Align the comments in the type struct initializer.

Note: I don't implement rich comparison for dictionaries -- there
doesn't seem to be much to be gained.  (The existing comparison
already decides that shorter dicts are always smaller than longer
dicts.)
This commit is contained in:
Guido van Rossum 2001-01-18 00:39:02 +00:00
parent f77bc62e73
commit b932420cc7
1 changed files with 45 additions and 118 deletions

View File

@ -207,15 +207,15 @@ lookdict(dictobject *mp, PyObject *key, register long hash)
restore_error = 1;
PyErr_Fetch(&err_type, &err_value, &err_tb);
}
cmp = PyObject_Compare(ep->me_key, key);
if (PyErr_Occurred())
PyErr_Clear();
else if (cmp == 0) {
cmp = PyObject_RichCompareBool(ep->me_key, key, Py_EQ);
if (cmp > 0) {
if (restore_error)
PyErr_Restore(err_type, err_value,
err_tb);
return ep;
}
else if (cmp < 0)
PyErr_Clear();
}
freeslot = NULL;
}
@ -252,15 +252,15 @@ lookdict(dictobject *mp, PyObject *key, register long hash)
&err_tb);
}
}
cmp = PyObject_Compare(ep->me_key, key);
if (PyErr_Occurred())
PyErr_Clear();
else if (cmp == 0) {
cmp = PyObject_RichCompareBool(ep->me_key, key, Py_EQ);
if (cmp > 0) {
if (restore_error)
PyErr_Restore(err_type, err_value,
err_tb);
return ep;
}
else if (cmp < 0)
PyErr_Clear();
}
/* Cycle through GF(2^n)-{0} */
incr = incr << 1;
@ -912,10 +912,6 @@ PyDict_Items(PyObject *mp)
return dict_items((dictobject *)mp, (PyObject *)NULL);
}
#define NEWCMP
#ifdef NEWCMP
/* Subroutine which returns the smallest key in a for which b's value
is different or absent. The value is returned too, through the
pval argument. No reference counts are incremented. */
@ -924,20 +920,30 @@ static PyObject *
characterize(dictobject *a, dictobject *b, PyObject **pval)
{
PyObject *diff = NULL;
int i;
int i, cmp;
*pval = NULL;
for (i = 0; i < a->ma_size; i++) {
if (a->ma_table[i].me_value != NULL) {
PyObject *key = a->ma_table[i].me_key;
PyObject *aval, *bval;
/* XXX What if PyObject_Compare raises an exception? */
if (diff != NULL && PyObject_Compare(key, diff) > 0)
if (diff != NULL) {
cmp = PyObject_RichCompareBool(diff, key, Py_LT);
if (cmp < 0)
return NULL;
if (cmp > 0)
continue;
}
aval = a->ma_table[i].me_value;
bval = PyDict_GetItem((PyObject *)b, key);
/* XXX What if PyObject_Compare raises an exception? */
if (bval == NULL || PyObject_Compare(aval, bval) != 0)
if (bval == NULL)
cmp = 0;
else {
cmp = PyObject_RichCompareBool(aval, bval, Py_EQ);
if (cmp < 0)
return NULL;
}
if (cmp == 0)
{
diff = key;
*pval = aval;
@ -960,12 +966,12 @@ dict_compare(dictobject *a, dictobject *b)
return 1; /* b is shorter */
/* Same length -- check all keys */
adiff = characterize(a, b, &aval);
if (PyErr_Occurred())
if (adiff == NULL && PyErr_Occurred())
return -1;
if (adiff == NULL)
return 0; /* a is a subset with the same length */
bdiff = characterize(b, a, &bval);
if (PyErr_Occurred())
if (bdiff == NULL && PyErr_Occurred())
return -1;
/* bdiff == NULL would be impossible now */
res = PyObject_Compare(adiff, bdiff);
@ -974,86 +980,6 @@ dict_compare(dictobject *a, dictobject *b)
return res;
}
#else /* !NEWCMP */
static int
dict_compare(dictobject *a, dictobject *b)
{
PyObject *akeys, *bkeys;
int i, n, res;
if (a == b)
return 0;
if (a->ma_used == 0) {
if (b->ma_used != 0)
return -1;
else
return 0;
}
else {
if (b->ma_used == 0)
return 1;
}
akeys = dict_keys(a, (PyObject *)NULL);
bkeys = dict_keys(b, (PyObject *)NULL);
if (akeys == NULL || bkeys == NULL) {
/* Oops, out of memory -- what to do? */
/* For now, sort on address! */
Py_XDECREF(akeys);
Py_XDECREF(bkeys);
if (a < b)
return -1;
else
return 1;
}
PyList_Sort(akeys);
PyList_Sort(bkeys);
n = a->ma_used < b->ma_used ? a->ma_used : b->ma_used; /* smallest */
res = 0;
for (i = 0; i < n; i++) {
PyObject *akey, *bkey, *aval, *bval;
long ahash, bhash;
akey = PyList_GetItem(akeys, i);
bkey = PyList_GetItem(bkeys, i);
res = PyObject_Compare(akey, bkey);
if (res != 0)
break;
#ifdef CACHE_HASH
if (!PyString_Check(akey) ||
(ahash = ((PyStringObject *) akey)->ob_shash) == -1)
#endif
{
ahash = PyObject_Hash(akey);
if (ahash == -1)
PyErr_Clear(); /* Don't want errors here */
}
#ifdef CACHE_HASH
if (!PyString_Check(bkey) ||
(bhash = ((PyStringObject *) bkey)->ob_shash) == -1)
#endif
{
bhash = PyObject_Hash(bkey);
if (bhash == -1)
PyErr_Clear(); /* Don't want errors here */
}
aval = (a->ma_lookup)(a, akey, ahash) -> me_value;
bval = (b->ma_lookup)(b, bkey, bhash) -> me_value;
res = PyObject_Compare(aval, bval);
if (res != 0)
break;
}
if (res == 0) {
if (a->ma_used < b->ma_used)
res = -1;
else if (a->ma_used > b->ma_used)
res = 1;
}
Py_DECREF(akeys);
Py_DECREF(bkeys);
return res;
}
#endif /* !NEWCMP */
static PyObject *
dict_has_key(register dictobject *mp, PyObject *args)
{
@ -1298,25 +1224,26 @@ PyTypeObject PyDict_Type = {
"dictionary",
sizeof(dictobject) + PyGC_HEAD_SIZE,
0,
(destructor)dict_dealloc, /*tp_dealloc*/
(printfunc)dict_print, /*tp_print*/
(getattrfunc)dict_getattr, /*tp_getattr*/
0, /*tp_setattr*/
(cmpfunc)dict_compare, /*tp_compare*/
(reprfunc)dict_repr, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
&dict_as_mapping, /*tp_as_mapping*/
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /*tp_flags*/
0, /* tp_doc */
(traverseproc)dict_traverse, /* tp_traverse */
(inquiry)dict_tp_clear, /* tp_clear */
(destructor)dict_dealloc, /* tp_dealloc */
(printfunc)dict_print, /* tp_print */
(getattrfunc)dict_getattr, /* tp_getattr */
0, /* tp_setattr */
(cmpfunc)dict_compare, /* tp_compare */
(reprfunc)dict_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
&dict_as_mapping, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
0, /* tp_doc */
(traverseproc)dict_traverse, /* tp_traverse */
(inquiry)dict_tp_clear, /* tp_clear */
0, /* tp_richcompare */
};
/* For backward compatibility with old dictionary interface */