* Bring lookkey() and lookkey_string() closer to dict version.

* Use set_next() for looping in issubset() and frozenset_hash().
* Re-order the presentation of cmp and hash functions.
This commit is contained in:
Raymond Hettinger 2005-08-13 08:28:03 +00:00
parent 00148226df
commit ed6c1ef8c3

View file

@ -61,6 +61,7 @@ set_lookkey(PySetObject *so, PyObject *key, register long hash)
setentry *table = so->table; setentry *table = so->table;
register setentry *entry; register setentry *entry;
register int restore_error; register int restore_error;
register int checked_error;
register int cmp; register int cmp;
PyObject *err_type, *err_value, *err_tb; PyObject *err_type, *err_value, *err_tb;
PyObject *startkey; PyObject *startkey;
@ -70,11 +71,13 @@ set_lookkey(PySetObject *so, PyObject *key, register long hash)
if (entry->key == NULL || entry->key == key) if (entry->key == NULL || entry->key == key)
return entry; return entry;
restore_error = 0; restore_error = checked_error = 0;
if (entry->key == dummy) if (entry->key == dummy)
freeslot = entry; freeslot = entry;
else { else {
if (entry->hash == hash) { if (entry->hash == hash) {
/* error can't have been checked yet */
checked_error = 1;
if (_PyErr_OCCURRED()) { if (_PyErr_OCCURRED()) {
restore_error = 1; restore_error = 1;
PyErr_Fetch(&err_type, &err_value, &err_tb); PyErr_Fetch(&err_type, &err_value, &err_tb);
@ -111,11 +114,14 @@ set_lookkey(PySetObject *so, PyObject *key, register long hash)
if (entry->key == key) if (entry->key == key)
break; break;
if (entry->hash == hash && entry->key != dummy) { if (entry->hash == hash && entry->key != dummy) {
if (!checked_error) {
checked_error = 1;
if (_PyErr_OCCURRED()) { if (_PyErr_OCCURRED()) {
restore_error = 1; restore_error = 1;
PyErr_Fetch(&err_type, &err_value, PyErr_Fetch(&err_type, &err_value,
&err_tb); &err_tb);
} }
}
startkey = entry->key; startkey = entry->key;
cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
if (cmp < 0) if (cmp < 0)
@ -174,7 +180,6 @@ set_lookkey_string(PySetObject *so, PyObject *key, register long hash)
entry = &table[i]; entry = &table[i];
if (entry->key == NULL || entry->key == key) if (entry->key == NULL || entry->key == key)
return entry; return entry;
if (so->fill != so->used) {
if (entry->key == dummy) if (entry->key == dummy)
freeslot = entry; freeslot = entry;
else { else {
@ -198,21 +203,6 @@ set_lookkey_string(PySetObject *so, PyObject *key, register long hash)
if (entry->key == dummy && freeslot == NULL) if (entry->key == dummy && freeslot == NULL)
freeslot = entry; freeslot = entry;
} }
} else {
/* Simplified loop when there are no dummy entries. */
if (entry->hash == hash && _PyString_Eq(entry->key, key))
return entry;
for (perturb = hash; ; perturb >>= PERTURB_SHIFT) {
i = (i << 2) + i + perturb + 1;
entry = &table[i & mask];
if (entry->key == NULL)
return entry;
if (entry->key == key
|| (entry->hash == hash
&& _PyString_Eq(entry->key, key)))
return entry;
}
}
} }
/* /*
@ -1369,11 +1359,11 @@ set_ixor(PySetObject *so, PyObject *other)
static PyObject * static PyObject *
set_issubset(PySetObject *so, PyObject *other) set_issubset(PySetObject *so, PyObject *other)
{ {
PyObject *tmp, *result; setentry *entry;
register setentry *entry; int pos = 0;
register int i;
if (!PyAnySet_Check(other)) { if (!PyAnySet_Check(other)) {
PyObject *tmp, *result;
tmp = make_new_set(&PySet_Type, other); tmp = make_new_set(&PySet_Type, other);
if (tmp == NULL) if (tmp == NULL)
return NULL; return NULL;
@ -1384,10 +1374,7 @@ set_issubset(PySetObject *so, PyObject *other)
if (set_len((PyObject *)so) > set_len(other)) if (set_len((PyObject *)so) > set_len(other))
Py_RETURN_FALSE; Py_RETURN_FALSE;
entry = &so->table[0]; while (set_next(so, &pos, &entry)) {
for (i=so->used ; i ; entry++, i--) {
while (entry->key == NULL || entry->key==dummy)
entry++;
if (!set_contains_entry((PySetObject *)other, entry)) if (!set_contains_entry((PySetObject *)other, entry))
Py_RETURN_FALSE; Py_RETURN_FALSE;
} }
@ -1414,51 +1401,6 @@ set_issuperset(PySetObject *so, PyObject *other)
PyDoc_STRVAR(issuperset_doc, "Report whether this set contains another set."); PyDoc_STRVAR(issuperset_doc, "Report whether this set contains another set.");
static long
set_nohash(PyObject *self)
{
PyErr_SetString(PyExc_TypeError, "set objects are unhashable");
return -1;
}
static int
set_nocmp(PyObject *self)
{
PyErr_SetString(PyExc_TypeError, "cannot compare sets using cmp()");
return -1;
}
static long
frozenset_hash(PyObject *self)
{
PySetObject *so = (PySetObject *)self;
long h, hash = 1927868237L;
setentry *entry;
int i;
if (so->hash != -1)
return so->hash;
hash *= set_len(self) + 1;
entry = &so->table[0];
for (i=so->used ; i ; entry++, i--) {
while (entry->key == NULL || entry->key==dummy)
entry++;
/* Work to increase the bit dispersion for closely spaced hash
values. The is important because some use cases have many
combinations of a small number of elements with nearby
hashes so that many distinct combinations collapse to only
a handful of distinct hash values. */
h = entry->hash;
hash ^= (h ^ (h << 16) ^ 89869747L) * 3644798167u;
}
hash = hash * 69069L + 907133923L;
if (hash == -1)
hash = 590923713L;
so->hash = hash;
return hash;
}
static PyObject * static PyObject *
set_richcompare(PySetObject *v, PyObject *w, int op) set_richcompare(PySetObject *v, PyObject *w, int op)
{ {
@ -1502,6 +1444,48 @@ set_richcompare(PySetObject *v, PyObject *w, int op)
return Py_NotImplemented; return Py_NotImplemented;
} }
static int
set_nocmp(PyObject *self)
{
PyErr_SetString(PyExc_TypeError, "cannot compare sets using cmp()");
return -1;
}
static long
frozenset_hash(PyObject *self)
{
PySetObject *so = (PySetObject *)self;
long h, hash = 1927868237L;
setentry *entry;
int pos = 0;
if (so->hash != -1)
return so->hash;
hash *= set_len(self) + 1;
while (set_next(so, &pos, &entry)) {
/* Work to increase the bit dispersion for closely spaced hash
values. The is important because some use cases have many
combinations of a small number of elements with nearby
hashes so that many distinct combinations collapse to only
a handful of distinct hash values. */
h = entry->hash;
hash ^= (h ^ (h << 16) ^ 89869747L) * 3644798167u;
}
hash = hash * 69069L + 907133923L;
if (hash == -1)
hash = 590923713L;
so->hash = hash;
return hash;
}
static long
set_nohash(PyObject *self)
{
PyErr_SetString(PyExc_TypeError, "set objects are unhashable");
return -1;
}
static PyObject * static PyObject *
set_repr(PySetObject *so) set_repr(PySetObject *so)
{ {