Skip to content

Commit

Permalink
optimize set-like iterables
Browse files Browse the repository at this point in the history
  • Loading branch information
HarryLHW committed Jul 14, 2024
1 parent c2c8a93 commit 0822d3c
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 0 deletions.
12 changes: 12 additions & 0 deletions Include/dictobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,18 @@ PyAPI_DATA(PyTypeObject) PyDictRevIterKey_Type;
PyAPI_DATA(PyTypeObject) PyDictRevIterItem_Type;
PyAPI_DATA(PyTypeObject) PyDictRevIterValue_Type;

#define PyDictIterKey_Check(op) PyObject_TypeCheck((op), &PyDictIterKey_Type)
#define PyDictIterValue_Check(op) PyObject_TypeCheck((op), &PyDictIterValue_Type)
#define PyDictIterItem_Check(op) PyObject_TypeCheck((op), &PyDictIterItem_Type)

#define PyDictRevIterKey_Check(op) PyObject_TypeCheck((op), &PyDictRevIterKey_Type)
#define PyDictRevIterItem_Check(op) PyObject_TypeCheck((op), &PyDictRevIterItem_Type)
#define PyDictRevIterValue_Check(op) PyObject_TypeCheck((op), &PyDictRevIterValue_Type)

#define PyDictViewSetIter_Check(op) \
(PyDictItems_Check(op) || PyDictIterKey_Check(op) || PyDictIterItem_Check(op) || \
PyDictRevIterKey_Check(op) || PyDictRevIterItem_Check(op))


#ifndef Py_LIMITED_API
# define Py_CPYTHON_DICTOBJECT_H
Expand Down
2 changes: 2 additions & 0 deletions Include/setobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ PyAPI_FUNC(Py_ssize_t) PySet_Size(PyObject *anyset);
(Py_IS_TYPE((ob), &PySet_Type) || \
PyType_IsSubtype(Py_TYPE(ob), &PySet_Type))

#define PySetIter_Check(ob) Py_IS_TYPE((ob), &PySetIter_Type)

#ifndef Py_LIMITED_API
# define Py_CPYTHON_SETOBJECT_H
# include "cpython/setobject.h"
Expand Down
20 changes: 20 additions & 0 deletions Objects/setobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -967,6 +967,26 @@ set_update_iterable_lock_held(PySetObject *so, PyObject *other)
}

PyObject *key;

/* If our table is empty, and other is a set-like iterable, we can use set_insert_clean() */
if (so->fill == 0) {
if (PyRange_Check(so) | PyDictViewSetIter_Check(so) || PySetIter_Check(so)) {
setentry *newtable = so->table;
size_t newmask = (size_t)so->mask;
while ((key = PyIter_Next(it)) != NULL) {
Py_hash_t hash = _PyObject_HashFast(key);
if (hash == -1) {
return -1;
}
set_insert_clean(newtable, newmask, key, hash);
}
Py_DECREF(it);
if (PyErr_Occurred())
return -1;
return 0;
}
}

while ((key = PyIter_Next(it)) != NULL) {
if (set_add_key(so, key)) {
Py_DECREF(it);
Expand Down

0 comments on commit 0822d3c

Please sign in to comment.