Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b932420

Browse files
committed
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.)
1 parent f77bc62 commit b932420

1 file changed

Lines changed: 45 additions & 118 deletions

File tree

Objects/dictobject.c

Lines changed: 45 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -207,15 +207,15 @@ lookdict(dictobject *mp, PyObject *key, register long hash)
207207
restore_error = 1;
208208
PyErr_Fetch(&err_type, &err_value, &err_tb);
209209
}
210-
cmp = PyObject_Compare(ep->me_key, key);
211-
if (PyErr_Occurred())
212-
PyErr_Clear();
213-
else if (cmp == 0) {
210+
cmp = PyObject_RichCompareBool(ep->me_key, key, Py_EQ);
211+
if (cmp > 0) {
214212
if (restore_error)
215213
PyErr_Restore(err_type, err_value,
216214
err_tb);
217215
return ep;
218216
}
217+
else if (cmp < 0)
218+
PyErr_Clear();
219219
}
220220
freeslot = NULL;
221221
}
@@ -252,15 +252,15 @@ lookdict(dictobject *mp, PyObject *key, register long hash)
252252
&err_tb);
253253
}
254254
}
255-
cmp = PyObject_Compare(ep->me_key, key);
256-
if (PyErr_Occurred())
257-
PyErr_Clear();
258-
else if (cmp == 0) {
255+
cmp = PyObject_RichCompareBool(ep->me_key, key, Py_EQ);
256+
if (cmp > 0) {
259257
if (restore_error)
260258
PyErr_Restore(err_type, err_value,
261259
err_tb);
262260
return ep;
263261
}
262+
else if (cmp < 0)
263+
PyErr_Clear();
264264
}
265265
/* Cycle through GF(2^n)-{0} */
266266
incr = incr << 1;
@@ -912,10 +912,6 @@ PyDict_Items(PyObject *mp)
912912
return dict_items((dictobject *)mp, (PyObject *)NULL);
913913
}
914914

915-
#define NEWCMP
916-
917-
#ifdef NEWCMP
918-
919915
/* Subroutine which returns the smallest key in a for which b's value
920916
is different or absent. The value is returned too, through the
921917
pval argument. No reference counts are incremented. */
@@ -924,20 +920,30 @@ static PyObject *
924920
characterize(dictobject *a, dictobject *b, PyObject **pval)
925921
{
926922
PyObject *diff = NULL;
927-
int i;
923+
int i, cmp;
928924

929925
*pval = NULL;
930926
for (i = 0; i < a->ma_size; i++) {
931927
if (a->ma_table[i].me_value != NULL) {
932928
PyObject *key = a->ma_table[i].me_key;
933929
PyObject *aval, *bval;
934-
/* XXX What if PyObject_Compare raises an exception? */
935-
if (diff != NULL && PyObject_Compare(key, diff) > 0)
930+
if (diff != NULL) {
931+
cmp = PyObject_RichCompareBool(diff, key, Py_LT);
932+
if (cmp < 0)
933+
return NULL;
934+
if (cmp > 0)
936935
continue;
936+
}
937937
aval = a->ma_table[i].me_value;
938938
bval = PyDict_GetItem((PyObject *)b, key);
939-
/* XXX What if PyObject_Compare raises an exception? */
940-
if (bval == NULL || PyObject_Compare(aval, bval) != 0)
939+
if (bval == NULL)
940+
cmp = 0;
941+
else {
942+
cmp = PyObject_RichCompareBool(aval, bval, Py_EQ);
943+
if (cmp < 0)
944+
return NULL;
945+
}
946+
if (cmp == 0)
941947
{
942948
diff = key;
943949
*pval = aval;
@@ -960,12 +966,12 @@ dict_compare(dictobject *a, dictobject *b)
960966
return 1; /* b is shorter */
961967
/* Same length -- check all keys */
962968
adiff = characterize(a, b, &aval);
963-
if (PyErr_Occurred())
969+
if (adiff == NULL && PyErr_Occurred())
964970
return -1;
965971
if (adiff == NULL)
966972
return 0; /* a is a subset with the same length */
967973
bdiff = characterize(b, a, &bval);
968-
if (PyErr_Occurred())
974+
if (bdiff == NULL && PyErr_Occurred())
969975
return -1;
970976
/* bdiff == NULL would be impossible now */
971977
res = PyObject_Compare(adiff, bdiff);
@@ -974,86 +980,6 @@ dict_compare(dictobject *a, dictobject *b)
974980
return res;
975981
}
976982

977-
#else /* !NEWCMP */
978-
979-
static int
980-
dict_compare(dictobject *a, dictobject *b)
981-
{
982-
PyObject *akeys, *bkeys;
983-
int i, n, res;
984-
if (a == b)
985-
return 0;
986-
if (a->ma_used == 0) {
987-
if (b->ma_used != 0)
988-
return -1;
989-
else
990-
return 0;
991-
}
992-
else {
993-
if (b->ma_used == 0)
994-
return 1;
995-
}
996-
akeys = dict_keys(a, (PyObject *)NULL);
997-
bkeys = dict_keys(b, (PyObject *)NULL);
998-
if (akeys == NULL || bkeys == NULL) {
999-
/* Oops, out of memory -- what to do? */
1000-
/* For now, sort on address! */
1001-
Py_XDECREF(akeys);
1002-
Py_XDECREF(bkeys);
1003-
if (a < b)
1004-
return -1;
1005-
else
1006-
return 1;
1007-
}
1008-
PyList_Sort(akeys);
1009-
PyList_Sort(bkeys);
1010-
n = a->ma_used < b->ma_used ? a->ma_used : b->ma_used; /* smallest */
1011-
res = 0;
1012-
for (i = 0; i < n; i++) {
1013-
PyObject *akey, *bkey, *aval, *bval;
1014-
long ahash, bhash;
1015-
akey = PyList_GetItem(akeys, i);
1016-
bkey = PyList_GetItem(bkeys, i);
1017-
res = PyObject_Compare(akey, bkey);
1018-
if (res != 0)
1019-
break;
1020-
#ifdef CACHE_HASH
1021-
if (!PyString_Check(akey) ||
1022-
(ahash = ((PyStringObject *) akey)->ob_shash) == -1)
1023-
#endif
1024-
{
1025-
ahash = PyObject_Hash(akey);
1026-
if (ahash == -1)
1027-
PyErr_Clear(); /* Don't want errors here */
1028-
}
1029-
#ifdef CACHE_HASH
1030-
if (!PyString_Check(bkey) ||
1031-
(bhash = ((PyStringObject *) bkey)->ob_shash) == -1)
1032-
#endif
1033-
{
1034-
bhash = PyObject_Hash(bkey);
1035-
if (bhash == -1)
1036-
PyErr_Clear(); /* Don't want errors here */
1037-
}
1038-
aval = (a->ma_lookup)(a, akey, ahash) -> me_value;
1039-
bval = (b->ma_lookup)(b, bkey, bhash) -> me_value;
1040-
res = PyObject_Compare(aval, bval);
1041-
if (res != 0)
1042-
break;
1043-
}
1044-
if (res == 0) {
1045-
if (a->ma_used < b->ma_used)
1046-
res = -1;
1047-
else if (a->ma_used > b->ma_used)
1048-
res = 1;
1049-
}
1050-
Py_DECREF(akeys);
1051-
Py_DECREF(bkeys);
1052-
return res;
1053-
}
1054-
1055-
#endif /* !NEWCMP */
1056-
1057983
static PyObject *
1058984
dict_has_key(register dictobject *mp, PyObject *args)
1059985
{
@@ -1298,25 +1224,26 @@ PyTypeObject PyDict_Type = {
12981224
"dictionary",
12991225
sizeof(dictobject) + PyGC_HEAD_SIZE,
13001226
0,
1301-
(destructor)dict_dealloc, /*tp_dealloc*/
1302-
(printfunc)dict_print, /*tp_print*/
1303-
(getattrfunc)dict_getattr, /*tp_getattr*/
1304-
0, /*tp_setattr*/
1305-
(cmpfunc)dict_compare, /*tp_compare*/
1306-
(reprfunc)dict_repr, /*tp_repr*/
1307-
0, /*tp_as_number*/
1308-
0, /*tp_as_sequence*/
1309-
&dict_as_mapping, /*tp_as_mapping*/
1310-
0, /* tp_hash */
1311-
0, /* tp_call */
1312-
0, /* tp_str */
1313-
0, /* tp_getattro */
1314-
0, /* tp_setattro */
1315-
0, /* tp_as_buffer */
1316-
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /*tp_flags*/
1317-
0, /* tp_doc */
1318-
(traverseproc)dict_traverse, /* tp_traverse */
1319-
(inquiry)dict_tp_clear, /* tp_clear */
1227+
(destructor)dict_dealloc, /* tp_dealloc */
1228+
(printfunc)dict_print, /* tp_print */
1229+
(getattrfunc)dict_getattr, /* tp_getattr */
1230+
0, /* tp_setattr */
1231+
(cmpfunc)dict_compare, /* tp_compare */
1232+
(reprfunc)dict_repr, /* tp_repr */
1233+
0, /* tp_as_number */
1234+
0, /* tp_as_sequence */
1235+
&dict_as_mapping, /* tp_as_mapping */
1236+
0, /* tp_hash */
1237+
0, /* tp_call */
1238+
0, /* tp_str */
1239+
0, /* tp_getattro */
1240+
0, /* tp_setattro */
1241+
0, /* tp_as_buffer */
1242+
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
1243+
0, /* tp_doc */
1244+
(traverseproc)dict_traverse, /* tp_traverse */
1245+
(inquiry)dict_tp_clear, /* tp_clear */
1246+
0, /* tp_richcompare */
13201247
};
13211248

13221249
/* For backward compatibility with old dictionary interface */

0 commit comments

Comments
 (0)