Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Speed up calls to ``frozenset()`` by using the :pep:`590` ``vectorcall``
calling convention. Patch by Dong-hee Na.
74 changes: 56 additions & 18 deletions Objects/setobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -1063,36 +1063,73 @@ make_new_set_basetype(PyTypeObject *type, PyObject *iterable)
/* The empty frozenset is a singleton */
static PyObject *emptyfrozenset = NULL;

static PyObject *
make_new_frozenset(PyTypeObject *type, PyObject *iterable)
{
if (iterable != NULL) {
/* frozenset(f) is idempotent */
if (PyFrozenSet_CheckExact(iterable)) {
Py_INCREF(iterable);
return iterable;
}
PyObject *res = make_new_set((PyTypeObject *)type, iterable);
if (res == NULL || PySet_GET_SIZE(res)) {
return res;
}
Py_DECREF(res);
}

// The empty frozenset is a singleton
if (emptyfrozenset == NULL) {
emptyfrozenset = make_new_set((PyTypeObject *)type, NULL);
}
Py_XINCREF(emptyfrozenset);
return emptyfrozenset;
}

static PyObject *
frozenset_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *iterable = NULL, *result;
PyObject *iterable = NULL;

if (type == &PyFrozenSet_Type && !_PyArg_NoKeywords("frozenset", kwds))
if (type == &PyFrozenSet_Type && !_PyArg_NoKeywords("frozenset", kwds)) {
return NULL;
}

if (!PyArg_UnpackTuple(args, type->tp_name, 0, 1, &iterable))
if (!PyArg_UnpackTuple(args, type->tp_name, 0, 1, &iterable)) {
return NULL;
}

if (type != &PyFrozenSet_Type)
if (type != &PyFrozenSet_Type) {
return make_new_set(type, iterable);
}

if (iterable != NULL) {
/* frozenset(f) is idempotent */
if (PyFrozenSet_CheckExact(iterable)) {
Py_INCREF(iterable);
return iterable;
}
result = make_new_set(type, iterable);
if (result == NULL || PySet_GET_SIZE(result))
return result;
Py_DECREF(result);
return make_new_frozenset(type, iterable);
}
/* The empty frozenset is a singleton */
if (emptyfrozenset == NULL)
emptyfrozenset = make_new_set(type, NULL);
Py_XINCREF(emptyfrozenset);
return emptyfrozenset;
return make_new_frozenset(type, NULL);
}

static PyObject *
frozenset_vectorcall(PyObject *type, PyObject * const*args,
size_t nargsf, PyObject *kwnames)
{
assert(PyType_Check(type));

if (!_PyArg_NoKwnames("frozenset", kwnames)) {
return NULL;
}

Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
if (!_PyArg_CheckPositional("frozenset", nargs, 0, 1)) {
return NULL;
}

if (nargs) {
return make_new_frozenset((PyTypeObject *)type, args[0]);
}

return make_new_frozenset((PyTypeObject *)type, NULL);
}

static PyObject *
Expand Down Expand Up @@ -2283,6 +2320,7 @@ PyTypeObject PyFrozenSet_Type = {
PyType_GenericAlloc, /* tp_alloc */
frozenset_new, /* tp_new */
PyObject_GC_Del, /* tp_free */
.tp_vectorcall = frozenset_vectorcall,
};


Expand Down