| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 319f3a1 commit 3c0a4f5
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -51,9 +51,9 @@ struct _setobject { | |||
| 51 | 51 | */ | |
| 52 | 52 | setentry *table; | |
| 53 | 53 | setentry *(*lookup)(PySetObject *so, PyObject *key, Py_hash_t hash); | |
| 54 | + Py_hash_t hash; /* only used by frozenset objects */ | ||
| 54 | 55 | setentry smalltable[PySet_MINSIZE]; | |
| 55 | 56 | ||
| 56 | - Py_hash_t hash; /* only used by frozenset objects */ | ||
| 57 | 57 | PyObject *weakreflist; /* List of weak references */ | |
| 58 | 58 | }; | |
| 59 | 59 | #endif /* Py_LIMITED_API */ | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -68,6 +68,11 @@ chaining would be substantial (100% with typical malloc overhead). | |||
| 68 | 68 | The initial probe index is computed as hash mod the table size. Subsequent | |
| 69 | 69 | probe indices are computed as explained in Objects/dictobject.c. | |
| 70 | 70 | ||
| 71 | + To improve cache locality, each probe is done in pairs. | ||
| 72 | + After the probe is examined, an adjacent entry is then examined as well. | ||
| 73 | + The likelihood is that an adjacent entry is in the same cache line and | ||
| 74 | + can be examined more cheaply than another probe elsewhere in memory. | ||
| 75 | + | ||
| 71 | 76 | All arithmetic on hash should ignore overflow. | |
| 72 | 77 | ||
| 73 | 78 | Unlike the dictionary implementation, the lookkey functions can return | |
@@ -77,7 +82,7 @@ NULL if the rich comparison returns an error. | |||
| 77 | 82 | static setentry * | |
| 78 | 83 | set_lookkey(PySetObject *so, PyObject *key, Py_hash_t hash) | |
| 79 | 84 | { | |
| 80 | - size_t i; /* Unsigned for defined overflow behavior. */ | ||
| 85 | + size_t i, j; /* Unsigned for defined overflow behavior. */ | ||
| 81 | 86 | size_t perturb; | |
| 82 | 87 | setentry *freeslot; | |
| 83 | 88 | size_t mask = so->mask; | |
@@ -90,7 +95,6 @@ set_lookkey(PySetObject *so, PyObject *key, Py_hash_t hash) | |||
| 90 | 95 | entry = &table[i]; | |
| 91 | 96 | if (entry->key == NULL || entry->key == key) | |
| 92 | 97 | return entry; | |
| 93 | - | ||
| 94 | 98 | if (entry->hash == hash) { | |
| 95 | 99 | startkey = entry->key; | |
| 96 | 100 | Py_INCREF(startkey); | |
@@ -107,14 +111,45 @@ set_lookkey(PySetObject *so, PyObject *key, Py_hash_t hash) | |||
| 107 | 111 | return set_lookkey(so, key, hash); | |
| 108 | 112 | } | |
| 109 | 113 | } | |
| 110 | - | ||
| 111 | 114 | freeslot = (entry->key == dummy) ? entry : NULL; | |
| 112 | 115 | ||
| 113 | 116 | /* In the loop, key == dummy is by far (factor of 100s) | |
| 114 | 117 | the least likely outcome, so test for that last. */ | |
| 115 | - for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { | ||
| 118 | + j = i; | ||
| 119 | + perturb = hash; | ||
| 120 | + while (1) { | ||
| 121 | + j ^= 1; | ||
| 122 | + entry = &table[j]; | ||
| 123 | + if (entry->key == NULL) { | ||
| 124 | + if (freeslot != NULL) | ||
| 125 | + entry = freeslot; | ||
| 126 | + break; | ||
| 127 | + } | ||
| 128 | + if (entry->key == key) | ||
| 129 | + break; | ||
| 130 | + if (entry->hash == hash) { | ||
| 131 | + startkey = entry->key; | ||
| 132 | + Py_INCREF(startkey); | ||
| 133 | + cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); | ||
| 134 | + Py_DECREF(startkey); | ||
| 135 | + if (cmp < 0) | ||
| 136 | + return NULL; | ||
| 137 | + if (table == so->table && entry->key == startkey) { | ||
| 138 | + if (cmp > 0) | ||
| 139 | + break; | ||
| 140 | + } | ||
| 141 | + else { | ||
| 142 | + return set_lookkey(so, key, hash); | ||
| 143 | + } | ||
| 144 | + } | ||
| 145 | + if (entry->key == dummy && freeslot == NULL) | ||
| 146 | + freeslot = entry; | ||
| 147 | + | ||
| 116 | 148 | i = i * 5 + perturb + 1; | |
| 117 | - entry = &table[i & mask]; | ||
| 149 | + j = i & mask; | ||
| 150 | + perturb >>= PERTURB_SHIFT; | ||
| 151 | + | ||
| 152 | + entry = &table[j]; | ||
| 118 | 153 | if (entry->key == NULL) { | |
| 119 | 154 | if (freeslot != NULL) | |
| 120 | 155 | entry = freeslot; | |
@@ -134,14 +169,12 @@ set_lookkey(PySetObject *so, PyObject *key, Py_hash_t hash) | |||
| 134 | 169 | break; | |
| 135 | 170 | } | |
| 136 | 171 | else { | |
| 137 | - /* The compare did major nasty stuff to the | ||
| 138 | - * set: start over. | ||
| 139 | - */ | ||
| 140 | 172 | return set_lookkey(so, key, hash); | |
| 141 | 173 | } | |
| 142 | 174 | } | |
| 143 | 175 | if (entry->key == dummy && freeslot == NULL) | |
| 144 | 176 | freeslot = entry; | |
| 177 | + | ||
| 145 | 178 | } | |
| 146 | 179 | return entry; | |
| 147 | 180 | } | |
@@ -154,7 +187,7 @@ set_lookkey(PySetObject *so, PyObject *key, Py_hash_t hash) | |||
| 154 | 187 | static setentry * | |
| 155 | 188 | set_lookkey_unicode(PySetObject *so, PyObject *key, Py_hash_t hash) | |
| 156 | 189 | { | |
| 157 | - size_t i; /* Unsigned for defined overflow behavior. */ | ||
| 190 | + size_t i, j; /* Unsigned for defined overflow behavior. */ | ||
| 158 | 191 | size_t perturb; | |
| 159 | 192 | setentry *freeslot; | |
| 160 | 193 | size_t mask = so->mask; | |
@@ -169,6 +202,7 @@ set_lookkey_unicode(PySetObject *so, PyObject *key, Py_hash_t hash) | |||
| 169 | 202 | so->lookup = set_lookkey; | |
| 170 | 203 | return set_lookkey(so, key, hash); | |
| 171 | 204 | } | |
| 205 | + | ||
| 172 | 206 | i = (size_t)hash & mask; | |
| 173 | 207 | entry = &table[i]; | |
| 174 | 208 | if (entry->key == NULL || entry->key == key) | |
@@ -181,11 +215,37 @@ set_lookkey_unicode(PySetObject *so, PyObject *key, Py_hash_t hash) | |||
| 181 | 215 | freeslot = NULL; | |
| 182 | 216 | } | |
| 183 | 217 | ||
| 184 | - /* In the loop, key == dummy is by far (factor of 100s) the | ||
| 185 | - least likely outcome, so test for that last. */ | ||
| 186 | - for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { | ||
| 218 | + entry = &table[i ^ 1]; | ||
| 219 | + if (entry->key == NULL) | ||
| 220 | + return freeslot == NULL ? entry : freeslot; | ||
| 221 | + if (entry->key == key | ||
| 222 | + || (entry->hash == hash | ||
| 223 | + && entry->key != dummy | ||
| 224 | + && unicode_eq(entry->key, key))) | ||
| 225 | + return entry; | ||
| 226 | + if (entry->key == dummy && freeslot == NULL) | ||
| 227 | + freeslot = entry; | ||
| 228 | + | ||
| 229 | + j = i; | ||
| 230 | + perturb = hash; | ||
| 231 | + while (1) { | ||
| 232 | + j ^= 1; | ||
| 233 | + entry = &table[j]; | ||
| 234 | + if (entry->key == NULL) | ||
| 235 | + return freeslot == NULL ? entry : freeslot; | ||
| 236 | + if (entry->key == key | ||
| 237 | + || (entry->hash == hash | ||
| 238 | + && entry->key != dummy | ||
| 239 | + && unicode_eq(entry->key, key))) | ||
| 240 | + return entry; | ||
| 241 | + if (entry->key == dummy && freeslot == NULL) | ||
| 242 | + freeslot = entry; | ||
| 243 | + | ||
| 187 | 244 | i = i * 5 + perturb + 1; | |
| 188 | - entry = &table[i & mask]; | ||
| 245 | + j = i & mask; | ||
| 246 | + perturb >>= PERTURB_SHIFT; | ||
| 247 | + | ||
| 248 | + entry = &table[j]; | ||
| 189 | 249 | if (entry->key == NULL) | |
| 190 | 250 | return freeslot == NULL ? entry : freeslot; | |
| 191 | 251 | if (entry->key == key | |
@@ -244,17 +304,23 @@ is responsible for incref'ing `key`. | |||
| 244 | 304 | static void | |
| 245 | 305 | set_insert_clean(PySetObject *so, PyObject *key, Py_hash_t hash) | |
| 246 | 306 | { | |
| 247 | - size_t i; | ||
| 248 | - size_t perturb; | ||
| 249 | - size_t mask = (size_t)so->mask; | ||
| 250 | 307 | setentry *table = so->table; | |
| 251 | 308 | setentry *entry; | |
| 309 | + size_t perturb = hash; | ||
| 310 | + size_t mask = (size_t)so->mask; | ||
| 311 | + size_t i, j; | ||
| 252 | 312 | ||
| 253 | - i = (size_t)hash & mask; | ||
| 254 | - entry = &table[i]; | ||
| 255 | - for (perturb = hash; entry->key != NULL; perturb >>= PERTURB_SHIFT) { | ||
| 313 | + i = j = (size_t)hash & mask; | ||
| 314 | + while (1) { | ||
| 315 | + entry = &table[j]; | ||
| 316 | + if (entry->key == NULL) | ||
| 317 | + break; | ||
| 318 | + entry = &table[j ^ 1]; | ||
| 319 | + if (entry->key == NULL) | ||
| 320 | + break; | ||
| 256 | 321 | i = i * 5 + perturb + 1; | |
| 257 | - entry = &table[i & mask]; | ||
| 322 | + j = i & mask; | ||
| 323 | + perturb >>= PERTURB_SHIFT; | ||
| 258 | 324 | } | |
| 259 | 325 | so->fill++; | |
| 260 | 326 | entry->key = key; | |
| Back | FazBrowse Home | New Git URL |
0 commit comments