Index: Include/dictobject.h =================================================================== --- Include/dictobject.h (revision 82889) +++ Include/dictobject.h (working copy) @@ -32,9 +32,9 @@ (cannot have me_key set to NULL), else the probe sequence in case of collision would have no way to know they were once active. -Note: .popitem() abuses the me_hash field of an Unused or Dummy slot to -hold a search finger. The me_hash field of Unused or Dummy slots has no -meaning otherwise. +Note: .popitem() uses the me_cache.index field of an Unused or Dummy slot to +hold a search finger. The me_cache.hash field of Unused or Dummy slots has no +meaning. */ /* PyDict_MINSIZE is the minimum size of a dictionary. This many slots are @@ -48,11 +48,11 @@ #define PyDict_MINSIZE 8 typedef struct { - /* Cached hash code of me_key. Note that hash codes are C longs. - * We have to use Py_ssize_t instead because dict_popitem() abuses - * me_hash to hold a search finger. - */ - Py_ssize_t me_hash; + /* Cached hash code of me_key or a search finger for dict_popitem() */ + union { + Py_ssize_t index; + long hash; + } me_cache; PyObject *me_key; PyObject *me_value; } PyDictEntry; Index: Include/setobject.h =================================================================== --- Include/setobject.h (revision 82889) +++ Include/setobject.h (working copy) @@ -14,15 +14,18 @@ 2. Active: key != NULL and key != dummy 3. Dummy: key == dummy -Note: .pop() abuses the hash field of an Unused or Dummy slot to -hold a search finger. The hash field of Unused or Dummy slots has -no meaning otherwise. +Note: .pop() uses the cache.index field of an Unused or Dummy slot to +hold a search finger. The cache.hash field of Unused or Dummy slots has +no meaning. */ #define PySet_MINSIZE 8 typedef struct { - long hash; /* cached hash code for the entry key */ + union { + long hash; /* cached hash code for the entry key */ + Py_ssize_t index; + } cache; PyObject *key; } setentry; Index: Objects/dictobject.c =================================================================== --- Objects/dictobject.c (revision 82889) +++ Objects/dictobject.c (working copy) @@ -337,7 +337,7 @@ if (ep->me_key == dummy) freeslot = ep; else { - if (ep->me_hash == hash) { + if (ep->me_cache.hash == hash) { startkey = ep->me_key; Py_INCREF(startkey); cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); @@ -369,7 +369,7 @@ return freeslot == NULL ? ep : freeslot; if (ep->me_key == key) return ep; - if (ep->me_hash == hash && ep->me_key != dummy) { + if (ep->me_cache.hash == hash && ep->me_key != dummy) { startkey = ep->me_key; Py_INCREF(startkey); cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); @@ -434,7 +434,7 @@ if (ep->me_key == dummy) freeslot = ep; else { - if (ep->me_hash == hash && unicode_eq(ep->me_key, key)) + if (ep->me_cache.hash == hash && unicode_eq(ep->me_key, key)) return ep; freeslot = NULL; } @@ -447,7 +447,7 @@ if (ep->me_key == NULL) return freeslot == NULL ? ep : freeslot; if (ep->me_key == key - || (ep->me_hash == hash + || (ep->me_cache.hash == hash && ep->me_key != dummy && unicode_eq(ep->me_key, key))) return ep; @@ -555,7 +555,7 @@ Py_DECREF(dummy); } ep->me_key = key; - ep->me_hash = (Py_ssize_t)hash; + ep->me_cache.hash = hash; ep->me_value = value; mp->ma_used++; } @@ -590,7 +590,7 @@ assert(ep->me_value == NULL); mp->ma_fill++; ep->me_key = key; - ep->me_hash = (Py_ssize_t)hash; + ep->me_cache.hash = hash; ep->me_value = value; mp->ma_used++; } @@ -667,7 +667,7 @@ for (ep = oldtable; i > 0; ep++) { if (ep->me_value != NULL) { /* active entry */ --i; - insertdict_clean(mp, ep->me_key, (long)ep->me_hash, + insertdict_clean(mp, ep->me_key, ep->me_cache.hash, ep->me_value); } else if (ep->me_key != NULL) { /* dummy entry */ @@ -1006,7 +1006,7 @@ *ppos = i+1; if (i > mask) return 0; - *phash = (long)(ep[i].me_hash); + *phash = ep[i].me_cache.hash; if (pkey) *pkey = ep[i].me_key; if (pvalue) @@ -1549,7 +1549,7 @@ Py_INCREF(entry->me_key); Py_INCREF(entry->me_value); if (insertdict(mp, entry->me_key, - (long)entry->me_hash, + entry->me_cache.hash, entry->me_value) != 0) return -1; } @@ -1894,7 +1894,7 @@ */ ep = &mp->ma_table[0]; if (ep->me_value == NULL) { - i = ep->me_hash; + i = ep->me_cache.index; /* The hash field may be a real hash value, or it may be a * legit search finger, or it may be a once-legit search * finger that's out of bounds now because it wrapped around @@ -1915,7 +1915,7 @@ ep->me_value = NULL; mp->ma_used--; assert(mp->ma_table[0].me_value == NULL); - mp->ma_table[0].me_hash = i + 1; /* next place to start */ + mp->ma_table[0].me_cache.index = i + 1; /* next place to start */ return res; } Index: Objects/setobject.c =================================================================== --- Objects/setobject.c (revision 82889) +++ Objects/setobject.c (working copy) @@ -94,7 +94,7 @@ if (entry->key == dummy) freeslot = entry; else { - if (entry->hash == hash) { + if (entry->cache.hash == hash) { startkey = entry->key; Py_INCREF(startkey); cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); @@ -127,7 +127,7 @@ } if (entry->key == key) break; - if (entry->hash == hash && entry->key != dummy) { + if (entry->cache.hash == hash && entry->key != dummy) { startkey = entry->key; Py_INCREF(startkey); cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); @@ -181,7 +181,7 @@ if (entry->key == dummy) freeslot = entry; else { - if (entry->hash == hash && unicode_eq(entry->key, key)) + if (entry->cache.hash == hash && unicode_eq(entry->key, key)) return entry; freeslot = NULL; } @@ -194,7 +194,7 @@ if (entry->key == NULL) return freeslot == NULL ? entry : freeslot; if (entry->key == key - || (entry->hash == hash + || (entry->cache.hash == hash && entry->key != dummy && unicode_eq(entry->key, key))) return entry; @@ -224,12 +224,12 @@ /* UNUSED */ so->fill++; entry->key = key; - entry->hash = hash; + entry->cache.hash = hash; so->used++; } else if (entry->key == dummy) { /* DUMMY */ entry->key = key; - entry->hash = hash; + entry->cache.hash = hash; so->used++; Py_DECREF(dummy); } else { @@ -264,7 +264,7 @@ } so->fill++; entry->key = key; - entry->hash = hash; + entry->cache.hash = hash; so->used++; } @@ -349,7 +349,7 @@ } else { /* ACTIVE */ --i; - set_insert_clean(so, entry->key, entry->hash); + set_insert_clean(so, entry->key, entry->cache.hash); } } @@ -368,7 +368,7 @@ assert(so->fill <= so->mask); /* at least one empty slot */ n_used = so->used; Py_INCREF(entry->key); - if (set_insert_key(so, entry->key, entry->hash) == -1) { + if (set_insert_key(so, entry->key, entry->cache.hash) == -1) { Py_DECREF(entry->key); return -1; } @@ -409,7 +409,7 @@ { register setentry *entry; PyObject *old_key; - entry = (so->lookup)(so, oldentry->key, oldentry->hash); + entry = (so->lookup)(so, oldentry->key, oldentry->cache.hash); if (entry == NULL) return -1; if (entry->key == NULL || entry->key == dummy) @@ -660,7 +660,7 @@ if (entry->key != NULL && entry->key != dummy) { Py_INCREF(entry->key); - if (set_insert_key(so, entry->key, entry->hash) == -1) { + if (set_insert_key(so, entry->key, entry->cache.hash) == -1) { Py_DECREF(entry->key); return -1; } @@ -694,7 +694,7 @@ PyObject *key; setentry *lu_entry; - lu_entry = (so->lookup)(so, entry->key, entry->hash); + lu_entry = (so->lookup)(so, entry->key, entry->cache.hash); if (lu_entry == NULL) return -1; key = lu_entry->key; @@ -722,7 +722,7 @@ */ entry = &so->table[0]; if (entry->key == NULL || entry->key == dummy) { - i = entry->hash; + i = entry->cache.index; /* The hash field may be a real hash value, or it may be a * legit search finger, or it may be a once-legit search * finger that's out of bounds now because it wrapped around @@ -740,7 +740,7 @@ Py_INCREF(dummy); entry->key = dummy; so->used--; - so->table[0].hash = i + 1; /* next place to start */ + so->table[0].cache.index = i + 1; /* next place to start */ return key; } @@ -776,7 +776,7 @@ 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; + h = entry->cache.hash; hash ^= (h ^ (h << 16) ^ 89869747L) * 3644798167u; } hash = hash * 69069L + 907133923L; @@ -939,7 +939,7 @@ while (_PyDict_Next(other, &pos, &key, &value, &hash)) { setentry an_entry; - an_entry.hash = hash; + an_entry.cache.hash = hash; an_entry.key = key; if (set_add_entry(so, &an_entry) == -1) return -1; @@ -1290,7 +1290,7 @@ Py_DECREF(key); return NULL; } - entry.hash = hash; + entry.cache.hash = hash; entry.key = key; rv = set_contains_entry(so, &entry); if (rv == -1) { @@ -1446,7 +1446,7 @@ Py_DECREF(it); return NULL; } - entry.hash = hash; + entry.cache.hash = hash; entry.key = key; rv = set_contains_entry(so, &entry); Py_DECREF(key); @@ -1545,9 +1545,9 @@ if (PyDict_CheckExact(other)) { while (set_next(so, &pos, &entry)) { setentry entrycopy; - entrycopy.hash = entry->hash; + entrycopy.cache.hash = entry->cache.hash; entrycopy.key = entry->key; - if (!_PyDict_Contains(other, entry->key, entry->hash)) { + if (!_PyDict_Contains(other, entry->key, entry->cache.hash)) { if (set_add_entry((PySetObject *)result, &entrycopy) == -1) { Py_DECREF(result); return NULL; @@ -1642,7 +1642,7 @@ while (_PyDict_Next(other, &pos, &key, &value, &hash)) { setentry an_entry; - an_entry.hash = hash; + an_entry.cache.hash = hash; an_entry.key = key; rv = set_discard_entry(so, &an_entry); if (rv == -1) @@ -2315,7 +2315,7 @@ if (set_next((PySetObject *)set, pos, &entry) == 0) return 0; *key = entry->key; - *hash = entry->hash; + *hash = entry->cache.hash; return 1; }