diff -r 0893b9ee44ea Objects/setobject.c --- a/Objects/setobject.c Tue Jan 20 17:21:41 2015 -0800 +++ b/Objects/setobject.c Wed Jan 21 16:30:31 2015 +0200 @@ -49,6 +49,32 @@ static PyObject _dummy_struct; #define PERTURB_SHIFT 5 static setentry * +set_find_free_slot(PySetObject *so, Py_hash_t hash) +{ + setentry *table = so->table; + setentry *entry; + size_t perturb = hash; + size_t mask = so->mask; + size_t i = (size_t)hash; /* Unsigned for defined overflow behavior. */ + size_t j; + + while (1) { + entry = &table[i & mask]; + if (entry->key == NULL || entry->key == dummy) + return entry; + + for (j = 1 ; j <= LINEAR_PROBES ; j++) { + entry = &table[(i + j) & mask]; + if (entry->key == NULL || entry->key == dummy) + return entry; + } + + perturb >>= PERTURB_SHIFT; + i = i * 5 + 1 + perturb; + } +} + +static setentry * set_lookkey(PySetObject *so, PyObject *key, Py_hash_t hash) { setentry *table = so->table; @@ -593,14 +619,16 @@ set_merge(PySetObject *so, PyObject *oth Py_hash_t hash; Py_ssize_t i; setentry *entry; + int clear, dump; assert (PyAnySet_Check(so)); assert (PyAnySet_Check(otherset)); other = (PySetObject*)otherset; if (other == so || other->used == 0) - /* a.update(a) or a.update({}); nothing to do */ + /* a.update(a) or a.update(set()); nothing to do */ return 0; + clear = so->used == 0; /* Do one big resize at the start, rather than * incrementally resizing as we insert new keys. Expect * that there will be no (or few) overlapping keys. @@ -609,16 +637,34 @@ set_merge(PySetObject *so, PyObject *oth if (set_table_resize(so, (so->used + other->used)*2) != 0) return -1; } + /* If no dummies we can just copy entries at the same indices */ + dump = other->fill == other->used && so->mask == other->mask; for (i = 0; i <= other->mask; i++) { entry = &other->table[i]; key = entry->key; hash = entry->hash; if (key != NULL && key != dummy) { - Py_INCREF(key); - if (set_insert_key(so, key, hash) == -1) { - Py_DECREF(key); - return -1; + if (clear) { + assert(!(entry->key == NULL || entry->key == dummy)); + if (dump) + entry = &so->table[i]; + else + entry = set_find_free_slot(so, hash); + assert(entry->key == NULL || entry->key == dummy); + if (entry->key == NULL) + so->fill++; + Py_INCREF(key); + entry->key = key; + entry->hash = hash; + so->used++; + } + else { + Py_INCREF(key); + if (set_insert_key(so, key, hash) == -1) { + Py_DECREF(key); + return -1; + } } } }