Improve code clarity for the set lookup logic (GH-20028)

This commit is contained in:
Raymond Hettinger 2020-05-10 14:53:29 -07:00 committed by GitHub
parent 2fbc57af85
commit 2cc9b8486d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -57,77 +57,43 @@ set_lookkey(PySetObject *so, PyObject *key, Py_hash_t hash)
{ {
setentry *table; setentry *table;
setentry *entry; setentry *entry;
size_t perturb; size_t perturb = hash;
size_t mask = so->mask; size_t mask = so->mask;
size_t i = (size_t)hash & mask; /* Unsigned for defined overflow behavior */ size_t i = (size_t)hash & mask; /* Unsigned for defined overflow behavior */
size_t j; int probes;
int cmp; int cmp;
entry = &so->table[i];
if (entry->key == NULL)
return entry;
perturb = hash;
while (1) { while (1) {
if (entry->hash == hash) { entry = &so->table[i];
PyObject *startkey = entry->key; probes = (i + LINEAR_PROBES <= mask) ? LINEAR_PROBES: 0;
/* startkey cannot be a dummy because the dummy hash field is -1 */ do {
assert(startkey != dummy); if (entry->hash == 0 && entry->key == NULL)
if (startkey == key)
return entry; return entry;
if (PyUnicode_CheckExact(startkey) if (entry->hash == hash) {
&& PyUnicode_CheckExact(key) PyObject *startkey = entry->key;
&& _PyUnicode_EQ(startkey, key)) assert(startkey != dummy);
return entry; if (startkey == key)
table = so->table;
Py_INCREF(startkey);
cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
Py_DECREF(startkey);
if (cmp < 0) /* unlikely */
return NULL;
if (table != so->table || entry->key != startkey) /* unlikely */
return set_lookkey(so, key, hash);
if (cmp > 0) /* likely */
return entry;
mask = so->mask; /* help avoid a register spill */
}
if (i + LINEAR_PROBES <= mask) {
for (j = 0 ; j < LINEAR_PROBES ; j++) {
entry++;
if (entry->hash == 0 && entry->key == NULL)
return entry; return entry;
if (entry->hash == hash) { if (PyUnicode_CheckExact(startkey)
PyObject *startkey = entry->key; && PyUnicode_CheckExact(key)
assert(startkey != dummy); && _PyUnicode_EQ(startkey, key))
if (startkey == key) return entry;
return entry; table = so->table;
if (PyUnicode_CheckExact(startkey) Py_INCREF(startkey);
&& PyUnicode_CheckExact(key) cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
&& _PyUnicode_EQ(startkey, key)) Py_DECREF(startkey);
return entry; if (cmp < 0)
table = so->table; return NULL;
Py_INCREF(startkey); if (table != so->table || entry->key != startkey)
cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); return set_lookkey(so, key, hash);
Py_DECREF(startkey); if (cmp > 0)
if (cmp < 0) return entry;
return NULL; mask = so->mask;
if (table != so->table || entry->key != startkey)
return set_lookkey(so, key, hash);
if (cmp > 0)
return entry;
mask = so->mask;
}
} }
} entry++;
} while (probes--);
perturb >>= PERTURB_SHIFT; perturb >>= PERTURB_SHIFT;
i = (i * 5 + 1 + perturb) & mask; i = (i * 5 + 1 + perturb) & mask;
entry = &so->table[i];
if (entry->key == NULL)
return entry;
} }
} }
@ -141,7 +107,7 @@ set_add_entry(PySetObject *so, PyObject *key, Py_hash_t hash)
size_t perturb; size_t perturb;
size_t mask; size_t mask;
size_t i; /* Unsigned for defined overflow behavior */ size_t i; /* Unsigned for defined overflow behavior */
size_t j; int probes;
int cmp; int cmp;
/* Pre-increment is necessary to prevent arbitrary code in the rich /* Pre-increment is necessary to prevent arbitrary code in the rich
@ -152,75 +118,39 @@ set_add_entry(PySetObject *so, PyObject *key, Py_hash_t hash)
mask = so->mask; mask = so->mask;
i = (size_t)hash & mask; i = (size_t)hash & mask;
entry = &so->table[i];
if (entry->key == NULL)
goto found_unused;
perturb = hash; perturb = hash;
while (1) { while (1) {
if (entry->hash == hash) { entry = &so->table[i];
PyObject *startkey = entry->key; probes = (i + LINEAR_PROBES <= mask) ? LINEAR_PROBES: 0;
/* startkey cannot be a dummy because the dummy hash field is -1 */ do {
assert(startkey != dummy); if (entry->hash == 0 && entry->key == NULL)
if (startkey == key) goto found_unused;
goto found_active; if (entry->hash == hash) {
if (PyUnicode_CheckExact(startkey) PyObject *startkey = entry->key;
&& PyUnicode_CheckExact(key) assert(startkey != dummy);
&& _PyUnicode_EQ(startkey, key)) if (startkey == key)
goto found_active; goto found_active;
table = so->table; if (PyUnicode_CheckExact(startkey)
Py_INCREF(startkey); && PyUnicode_CheckExact(key)
cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); && _PyUnicode_EQ(startkey, key))
Py_DECREF(startkey); goto found_active;
if (cmp > 0) /* likely */ table = so->table;
goto found_active; Py_INCREF(startkey);
if (cmp < 0) cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
goto comparison_error; Py_DECREF(startkey);
/* Continuing the search from the current entry only makes if (cmp > 0)
sense if the table and entry are unchanged; otherwise, goto found_active;
we have to restart from the beginning */ if (cmp < 0)
if (table != so->table || entry->key != startkey) goto comparison_error;
goto restart; if (table != so->table || entry->key != startkey)
mask = so->mask; /* help avoid a register spill */ goto restart;
} mask = so->mask;
if (i + LINEAR_PROBES <= mask) {
for (j = 0 ; j < LINEAR_PROBES ; j++) {
entry++;
if (entry->hash == 0 && entry->key == NULL)
goto found_unused;
if (entry->hash == hash) {
PyObject *startkey = entry->key;
assert(startkey != dummy);
if (startkey == key)
goto found_active;
if (PyUnicode_CheckExact(startkey)
&& PyUnicode_CheckExact(key)
&& _PyUnicode_EQ(startkey, key))
goto found_active;
table = so->table;
Py_INCREF(startkey);
cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
Py_DECREF(startkey);
if (cmp > 0)
goto found_active;
if (cmp < 0)
goto comparison_error;
if (table != so->table || entry->key != startkey)
goto restart;
mask = so->mask;
}
} }
} entry++;
} while (probes--);
perturb >>= PERTURB_SHIFT; perturb >>= PERTURB_SHIFT;
i = (i * 5 + 1 + perturb) & mask; i = (i * 5 + 1 + perturb) & mask;
entry = &so->table[i];
if (entry->key == NULL)
goto found_unused;
} }
found_unused: found_unused: