* Improve a variable name: entry0 --> table.

* Give set_lookkey_string() a fast alternate path when no dummy entries
  are present.
* Have set_swap_bodies() reset the hash field to -1 whenever either of
  bodies is not a frozenset.  Maintains the invariant of regular sets
  always having -1 in the hash field; otherwise, any mutation would make
  the hash value invalid.
* Use an entry pointer to simplify the code in frozenset_hash().
This commit is contained in:
Raymond Hettinger 2005-08-05 17:19:54 +00:00
parent a9d9936d10
commit a580c47c6d

View file

@ -46,7 +46,7 @@ set_lookkey(PySetObject *so, PyObject *key, register long hash)
register unsigned int perturb; register unsigned int perturb;
register setentry *freeslot; register setentry *freeslot;
register unsigned int mask = so->mask; register unsigned int mask = so->mask;
setentry *entry0 = 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 checked_error;
@ -55,7 +55,7 @@ set_lookkey(PySetObject *so, PyObject *key, register long hash)
PyObject *startkey; PyObject *startkey;
i = hash & mask; i = hash & mask;
entry = &entry0[i]; entry = &table[i];
if (entry->key == NULL || entry->key == key) if (entry->key == NULL || entry->key == key)
return entry; return entry;
@ -74,7 +74,7 @@ set_lookkey(PySetObject *so, PyObject *key, register long hash)
cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
if (cmp < 0) if (cmp < 0)
PyErr_Clear(); PyErr_Clear();
if (entry0 == so->table && entry->key == startkey) { if (table == so->table && entry->key == startkey) {
if (cmp > 0) if (cmp > 0)
goto Done; goto Done;
} }
@ -93,7 +93,7 @@ set_lookkey(PySetObject *so, PyObject *key, register long hash)
least likely outcome, so test for that last. */ least likely outcome, so test for that last. */
for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { for (perturb = hash; ; perturb >>= PERTURB_SHIFT) {
i = (i << 2) + i + perturb + 1; i = (i << 2) + i + perturb + 1;
entry = &entry0[i & mask]; entry = &table[i & mask];
if (entry->key == NULL) { if (entry->key == NULL) {
if (freeslot != NULL) if (freeslot != NULL)
entry = freeslot; entry = freeslot;
@ -114,7 +114,7 @@ set_lookkey(PySetObject *so, PyObject *key, register long hash)
cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
if (cmp < 0) if (cmp < 0)
PyErr_Clear(); PyErr_Clear();
if (entry0 == so->table && entry->key == startkey) { if (table == so->table && entry->key == startkey) {
if (cmp > 0) if (cmp > 0)
break; break;
} }
@ -153,7 +153,7 @@ set_lookkey_string(PySetObject *so, PyObject *key, register long hash)
register unsigned int perturb; register unsigned int perturb;
register setentry *freeslot; register setentry *freeslot;
register unsigned int mask = so->mask; register unsigned int mask = so->mask;
setentry *entry0 = so->table; setentry *table = so->table;
register setentry *entry; register setentry *entry;
/* Make sure this function doesn't have to handle non-string keys, /* Make sure this function doesn't have to handle non-string keys,
@ -165,31 +165,47 @@ set_lookkey_string(PySetObject *so, PyObject *key, register long hash)
return set_lookkey(so, key, hash); return set_lookkey(so, key, hash);
} }
i = hash & mask; i = hash & mask;
entry = &entry0[i]; entry = &table[i];
if (entry->key == NULL || entry->key == key) if (entry->key == NULL || entry->key == key)
return entry; return entry;
if (entry->key == dummy) if (so->fill != so->used) {
freeslot = entry; if (entry->key == dummy)
else { freeslot = entry;
else {
if (entry->hash == hash && _PyString_Eq(entry->key, key))
return entry;
freeslot = NULL;
}
/* In the loop, key == dummy is by far (factor of 100s) the
least likely outcome, so test for that last. */
for (perturb = hash; ; perturb >>= PERTURB_SHIFT) {
i = (i << 2) + i + perturb + 1;
entry = &table[i & mask];
if (entry->key == NULL)
return freeslot == NULL ? entry : freeslot;
if (entry->key == key
|| (entry->hash == hash
&& entry->key != dummy
&& _PyString_Eq(entry->key, key)))
return entry;
if (entry->key == dummy && freeslot == NULL)
freeslot = entry;
}
} else {
/* Simplified loop that can assume are no dummy entries */
if (entry->hash == hash && _PyString_Eq(entry->key, key)) if (entry->hash == hash && _PyString_Eq(entry->key, key))
return entry; return entry;
freeslot = NULL; for (perturb = hash; ; perturb >>= PERTURB_SHIFT) {
} i = (i << 2) + i + perturb + 1;
entry = &table[i & mask];
/* In the loop, key == dummy is by far (factor of 100s) the if (entry->key == NULL)
least likely outcome, so test for that last. */ return entry;
for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { if (entry->key == key
i = (i << 2) + i + perturb + 1; || (entry->hash == hash
entry = &entry0[i & mask]; && _PyString_Eq(entry->key, key)))
if (entry->key == NULL) return entry;
return freeslot == NULL ? entry : freeslot; }
if (entry->key == key
|| (entry->hash == hash
&& entry->key != dummy
&& _PyString_Eq(entry->key, key)))
return entry;
if (entry->key == dummy && freeslot == NULL)
freeslot = entry;
} }
} }
@ -377,10 +393,8 @@ set_clear_internal(PySetObject *so)
setentry small_copy[PySet_MINSIZE]; setentry small_copy[PySet_MINSIZE];
#ifdef Py_DEBUG #ifdef Py_DEBUG
int i, n; int i, n;
#endif
assert (PyAnySet_Check(so)); assert (PyAnySet_Check(so));
#ifdef Py_DEBUG
n = so->mask + 1; n = so->mask + 1;
i = 0; i = 0;
#endif #endif
@ -841,7 +855,13 @@ set_swap_bodies(PySetObject *a, PySetObject *b)
memcpy(b->smalltable, tab, sizeof(tab)); memcpy(b->smalltable, tab, sizeof(tab));
} }
h = a->hash; a->hash = b->hash; b->hash = h; if (PyType_IsSubtype(a->ob_type, &PyFrozenSet_Type) &&
PyType_IsSubtype(b->ob_type, &PyFrozenSet_Type)) {
h = a->hash; a->hash = b->hash; b->hash = h;
} else {
a->hash = -1;
b->hash = -1;
}
} }
static int static int
@ -1301,19 +1321,18 @@ static long
frozenset_hash(PyObject *self) frozenset_hash(PyObject *self)
{ {
PySetObject *so = (PySetObject *)self; PySetObject *so = (PySetObject *)self;
long hash = 1927868237L; long h, hash = 1927868237L;
int i, j; setentry *entry;
int i;
if (so->hash != -1) if (so->hash != -1)
return so->hash; return so->hash;
hash *= set_len(self) + 1; hash *= set_len(self) + 1;
for (i=0, j=so->used ; j ; j--, i++) { entry = &so->table[0];
setentry *entry; for (i=so->used ; i ; entry++, i--) {
long h; while (entry->key == NULL || entry->key==dummy)
entry++;
while ((entry = &so->table[i])->key == NULL || entry->key==dummy)
i++;
/* Work to increase the bit dispersion for closely spaced hash /* Work to increase the bit dispersion for closely spaced hash
values. The is important because some use cases have many values. The is important because some use cases have many
combinations of a small number of elements with nearby combinations of a small number of elements with nearby