@@ -65,10 +65,11 @@ chaining would be substantial (100% with typical malloc overhead).
6565The initial probe index is computed as hash mod the table size. Subsequent
6666probe indices are computed as explained in Objects/dictobject.c.
6767
68- To improve cache locality, each probe is done in pairs.
69- After the probe is examined, an adjacent entry is then examined as well.
70- The likelihood is that an adjacent entry is in the same cache line and
71- can be examined more cheaply than another probe elsewhere in memory.
68+ To improve cache locality, each probe inspects nearby entries before
69+ moving on to probes elsewhere in memory. Depending on alignment and the
70+ size of a cache line, the nearby entries are cheaper to inspect than
71+ other probes elsewhere in memory. This probe strategy reduces the cost
72+ of hash collisions.
7273
7374All arithmetic on hash should ignore overflow.
7475
@@ -130,6 +131,26 @@ set_lookkey(PySetObject *so, PyObject *key, Py_hash_t hash)
130131 if (entry -> key == dummy && freeslot == NULL )
131132 freeslot = entry ;
132133
134+ entry = & table [j ^ 2 ];
135+ if (entry -> key == NULL )
136+ break ;
137+ if (entry -> key == key )
138+ return entry ;
139+ if (entry -> hash == hash && entry -> key != dummy ) {
140+ PyObject * startkey = entry -> key ;
141+ Py_INCREF (startkey );
142+ cmp = PyObject_RichCompareBool (startkey , key , Py_EQ );
143+ Py_DECREF (startkey );
144+ if (cmp < 0 )
145+ return NULL ;
146+ if (table != so -> table || entry -> key != startkey )
147+ return set_lookkey (so , key , hash );
148+ if (cmp > 0 )
149+ return entry ;
150+ }
151+ if (entry -> key == dummy && freeslot == NULL )
152+ freeslot = entry ;
153+
133154 i = i * 5 + perturb + 1 ;
134155 j = i & mask ;
135156 perturb >>= PERTURB_SHIFT ;
@@ -190,6 +211,17 @@ set_lookkey_unicode(PySetObject *so, PyObject *key, Py_hash_t hash)
190211 if (entry -> key == dummy && freeslot == NULL )
191212 freeslot = entry ;
192213
214+ entry = & table [j ^ 2 ];
215+ if (entry -> key == NULL )
216+ break ;
217+ if (entry -> key == key
218+ || (entry -> hash == hash
219+ && entry -> key != dummy
220+ && unicode_eq (entry -> key , key )))
221+ return entry ;
222+ if (entry -> key == dummy && freeslot == NULL )
223+ freeslot = entry ;
224+
193225 i = i * 5 + perturb + 1 ;
194226 j = i & mask ;
195227 perturb >>= PERTURB_SHIFT ;
@@ -256,6 +288,9 @@ set_insert_clean(PySetObject *so, PyObject *key, Py_hash_t hash)
256288 if (entry -> key == NULL )
257289 break ;
258290 entry = & table [j ^ 1 ];
291+ if (entry -> key == NULL )
292+ break ;
293+ entry = & table [j ^ 2 ];
259294 if (entry -> key == NULL )
260295 break ;
261296 i = i * 5 + perturb + 1 ;
0 commit comments