Issue 23261: Clean-up the hack to store the set.pop() search finger in a hash field instead of the setobject.

This commit is contained in:
Raymond Hettinger 2015-01-18 13:12:42 -08:00
parent a556af77a7
commit 1202a4733e
3 changed files with 15 additions and 25 deletions

View File

@ -14,9 +14,7 @@ extern "C" {
2. Active: key != NULL and key != dummy 2. Active: key != NULL and key != dummy
3. Dummy: key == dummy 3. Dummy: key == dummy
Note: .pop() abuses the hash field of an Unused or Dummy slot to The hash field of Unused or Dummy slots have no meaning.
hold a search finger. The hash field of Unused or Dummy slots has
no meaning otherwise.
*/ */
#define PySet_MINSIZE 8 #define PySet_MINSIZE 8
@ -59,6 +57,7 @@ typedef struct _setobject {
Py_hash_t hash; /* Only used by frozenset objects */ Py_hash_t hash; /* Only used by frozenset objects */
setentry smalltable[PySet_MINSIZE]; setentry smalltable[PySet_MINSIZE];
Py_ssize_t finger; /* Search finger for pop() */
PyObject *weakreflist; /* List of weak references */ PyObject *weakreflist; /* List of weak references */
} PySetObject; } PySetObject;

View File

@ -994,7 +994,7 @@ class SizeofTest(unittest.TestCase):
# frozenset # frozenset
PySet_MINSIZE = 8 PySet_MINSIZE = 8
samples = [[], range(10), range(50)] samples = [[], range(10), range(50)]
s = size('3n2P' + PySet_MINSIZE*'nP' + 'nP') s = size('3n2P' + PySet_MINSIZE*'nP' + '2nP')
for sample in samples: for sample in samples:
minused = len(sample) minused = len(sample)
if minused == 0: tmp = 1 if minused == 0: tmp = 1

View File

@ -668,32 +668,22 @@ set_pop(PySetObject *so)
return NULL; return NULL;
} }
/* Set entry to "the first" unused or dummy set entry. We abuse i = so->finger;
* the hash field of slot 0 to hold a search finger: /* This may be a legit search finger, or it may be a once legit
* If slot 0 has a value, use slot 0. * search finger that's out of bounds now (due to wrapping or
* Else slot 0 is being used to hold a search finger, * resizing). We simply make sure it's in bounds now.
* and we use its hash value as the first index to look.
*/ */
entry = &so->table[0]; if (i > so->mask)
if (entry->key == NULL || entry->key == dummy) { i = 0;
i = entry->hash; while ((entry = &so->table[i])->key == NULL || entry->key==dummy) {
/* The hash field may be a real hash value, or it may be a i++;
* legit search finger, or it may be a once-legit search if (i > so->mask)
* finger that's out of bounds now because it wrapped around i = 0;
* or the table shrunk -- simply make sure it's in bounds now.
*/
if (i > so->mask || i < 1)
i = 1; /* skip slot 0 */
while ((entry = &so->table[i])->key == NULL || entry->key==dummy) {
i++;
if (i > so->mask)
i = 1;
}
} }
key = entry->key; key = entry->key;
entry->key = dummy; entry->key = dummy;
so->used--; so->used--;
so->table[0].hash = i + 1; /* next place to start */ so->finger = i + 1; /* next place to start */
return key; return key;
} }
@ -1012,6 +1002,7 @@ make_new_set(PyTypeObject *type, PyObject *iterable)
so->table = so->smalltable; so->table = so->smalltable;
so->lookup = set_lookkey_unicode; so->lookup = set_lookkey_unicode;
so->hash = -1; so->hash = -1;
so->finger = 0;
so->weakreflist = NULL; so->weakreflist = NULL;
if (iterable != NULL) { if (iterable != NULL) {