Kaydet (Commit) 93035c44 authored tarafından Raymond Hettinger's avatar Raymond Hettinger

Issue #23119: Simplify setobject by inlining the special case for unicode equality testing.

üst bbd3aa8e
...@@ -35,7 +35,7 @@ Invariants for frozensets: ...@@ -35,7 +35,7 @@ Invariants for frozensets:
*/ */
typedef struct _setobject { typedef struct {
PyObject_HEAD PyObject_HEAD
Py_ssize_t fill; /* Number active and dummy entries*/ Py_ssize_t fill; /* Number active and dummy entries*/
...@@ -53,7 +53,6 @@ typedef struct _setobject { ...@@ -53,7 +53,6 @@ typedef struct _setobject {
* runtime null-tests. * runtime null-tests.
*/ */
setentry *table; setentry *table;
setentry *(*lookup)(struct _setobject *so, PyObject *key, Py_hash_t hash);
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];
......
...@@ -994,7 +994,7 @@ class SizeofTest(unittest.TestCase): ...@@ -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' + '2nP') s = size('3nP' + 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
......
...@@ -69,6 +69,10 @@ set_lookkey(PySetObject *so, PyObject *key, Py_hash_t hash) ...@@ -69,6 +69,10 @@ set_lookkey(PySetObject *so, PyObject *key, Py_hash_t hash)
PyObject *startkey = entry->key; PyObject *startkey = entry->key;
if (startkey == key) if (startkey == key)
return entry; return entry;
if (PyUnicode_CheckExact(startkey)
&& PyUnicode_CheckExact(key)
&& unicode_eq(startkey, key))
return entry;
Py_INCREF(startkey); Py_INCREF(startkey);
cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
Py_DECREF(startkey); Py_DECREF(startkey);
...@@ -90,6 +94,10 @@ set_lookkey(PySetObject *so, PyObject *key, Py_hash_t hash) ...@@ -90,6 +94,10 @@ set_lookkey(PySetObject *so, PyObject *key, Py_hash_t hash)
PyObject *startkey = entry->key; PyObject *startkey = entry->key;
if (startkey == key) if (startkey == key)
return entry; return entry;
if (PyUnicode_CheckExact(startkey)
&& PyUnicode_CheckExact(key)
&& unicode_eq(startkey, key))
return entry;
Py_INCREF(startkey); Py_INCREF(startkey);
cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
Py_DECREF(startkey); Py_DECREF(startkey);
...@@ -115,68 +123,6 @@ set_lookkey(PySetObject *so, PyObject *key, Py_hash_t hash) ...@@ -115,68 +123,6 @@ set_lookkey(PySetObject *so, PyObject *key, Py_hash_t hash)
return freeslot == NULL ? entry : freeslot; return freeslot == NULL ? entry : freeslot;
} }
/*
* Hacked up version of set_lookkey which can assume keys are always unicode;
* This means we can always use unicode_eq directly and not have to check to
* see if the comparison altered the table.
*/
static setentry *
set_lookkey_unicode(PySetObject *so, PyObject *key, Py_hash_t hash)
{
setentry *table = so->table;
setentry *freeslot = NULL;
setentry *entry;
size_t perturb = hash;
size_t mask = so->mask;
size_t i = (size_t)hash;
size_t j;
/* Make sure this function doesn't have to handle non-unicode keys,
including subclasses of str; e.g., one reason to subclass
strings is to override __eq__, and for speed we don't cater to
that here. */
if (!PyUnicode_CheckExact(key)) { /* unlikely */
so->lookup = set_lookkey;
return set_lookkey(so, key, hash);
}
entry = &table[i & mask];
if (entry->key == NULL)
return entry;
while (1) {
if (entry->hash == hash
&& (entry->key == key
|| (entry->key != dummy /* unlikely */
&& unicode_eq(entry->key, key)))) /* likely */
return entry;
if (entry->key == dummy && freeslot == NULL)
freeslot = entry;
for (j = 1 ; j <= LINEAR_PROBES ; j++) {
entry = &table[(i + j) & mask];
if (entry->key == NULL)
goto found_null;
if (entry->hash == hash
&& (entry->key == key
|| (entry->key != dummy /* unlikely */
&& unicode_eq(entry->key, key)))) /* likely */
return entry;
if (entry->key == dummy && freeslot == NULL)
freeslot = entry;
}
perturb >>= PERTURB_SHIFT;
i = i * 5 + 1 + perturb;
entry = &table[i & mask];
if (entry->key == NULL)
goto found_null;
}
found_null:
return freeslot == NULL ? entry : freeslot;
}
/* /*
Internal routine used by set_table_resize() to insert an item which is Internal routine used by set_table_resize() to insert an item which is
known to be absent from the set. This routine also assumes that known to be absent from the set. This routine also assumes that
...@@ -225,8 +171,7 @@ set_insert_key(PySetObject *so, PyObject *key, Py_hash_t hash) ...@@ -225,8 +171,7 @@ set_insert_key(PySetObject *so, PyObject *key, Py_hash_t hash)
{ {
setentry *entry; setentry *entry;
assert(so->lookup != NULL); entry = set_lookkey(so, key, hash);
entry = so->lookup(so, key, hash);
if (entry == NULL) if (entry == NULL)
return -1; return -1;
if (entry->key == NULL) { if (entry->key == NULL) {
...@@ -385,7 +330,7 @@ set_discard_entry(PySetObject *so, setentry *oldentry) ...@@ -385,7 +330,7 @@ set_discard_entry(PySetObject *so, setentry *oldentry)
setentry *entry; setentry *entry;
PyObject *old_key; PyObject *old_key;
entry = (so->lookup)(so, oldentry->key, oldentry->hash); entry = set_lookkey(so, oldentry->key, oldentry->hash);
if (entry == NULL) if (entry == NULL)
return -1; return -1;
if (entry->key == NULL || entry->key == dummy) if (entry->key == NULL || entry->key == dummy)
...@@ -631,7 +576,7 @@ set_contains_entry(PySetObject *so, setentry *entry) ...@@ -631,7 +576,7 @@ set_contains_entry(PySetObject *so, setentry *entry)
PyObject *key; PyObject *key;
setentry *lu_entry; setentry *lu_entry;
lu_entry = (so->lookup)(so, entry->key, entry->hash); lu_entry = set_lookkey(so, entry->key, entry->hash);
if (lu_entry == NULL) if (lu_entry == NULL)
return -1; return -1;
key = lu_entry->key; key = lu_entry->key;
...@@ -994,7 +939,6 @@ make_new_set(PyTypeObject *type, PyObject *iterable) ...@@ -994,7 +939,6 @@ make_new_set(PyTypeObject *type, PyObject *iterable)
so->used = 0; so->used = 0;
so->mask = PySet_MINSIZE - 1; so->mask = PySet_MINSIZE - 1;
so->table = so->smalltable; so->table = so->smalltable;
so->lookup = set_lookkey_unicode;
so->hash = -1; so->hash = -1;
so->finger = 0; so->finger = 0;
so->weakreflist = NULL; so->weakreflist = NULL;
...@@ -1095,7 +1039,6 @@ set_swap_bodies(PySetObject *a, PySetObject *b) ...@@ -1095,7 +1039,6 @@ set_swap_bodies(PySetObject *a, PySetObject *b)
{ {
Py_ssize_t t; Py_ssize_t t;
setentry *u; setentry *u;
setentry *(*f)(PySetObject *so, PyObject *key, Py_ssize_t hash);
setentry tab[PySet_MINSIZE]; setentry tab[PySet_MINSIZE];
Py_hash_t h; Py_hash_t h;
...@@ -1111,8 +1054,6 @@ set_swap_bodies(PySetObject *a, PySetObject *b) ...@@ -1111,8 +1054,6 @@ set_swap_bodies(PySetObject *a, PySetObject *b)
a->table = a->smalltable; a->table = a->smalltable;
b->table = u; b->table = u;
f = a->lookup; a->lookup = b->lookup; b->lookup = f;
if (a->table == a->smalltable || b->table == b->smalltable) { if (a->table == a->smalltable || b->table == b->smalltable) {
memcpy(tab, a->smalltable, sizeof(tab)); memcpy(tab, a->smalltable, sizeof(tab));
memcpy(a->smalltable, b->smalltable, sizeof(tab)); memcpy(a->smalltable, b->smalltable, sizeof(tab));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment