mirror of https://github.com/python/cpython
gh-112069: Make sets thread-safe with the GIL disabled (#113800)
This makes nearly all the operations on set thread-safe in the free-threaded build, with the exception of `_PySet_NextEntry` and `setiter_iternext`. Co-authored-by: Sam Gross <colesbury@gmail.com> Co-authored-by: Erlend E. Aasland <erlend.aasland@protonmail.com>
This commit is contained in:
parent
3cdfdc07a9
commit
c951e25c24
|
@ -2,6 +2,7 @@
|
||||||
preserve
|
preserve
|
||||||
[clinic start generated code]*/
|
[clinic start generated code]*/
|
||||||
|
|
||||||
|
#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION()
|
||||||
#include "pycore_modsupport.h" // _PyArg_CheckPositional()
|
#include "pycore_modsupport.h" // _PyArg_CheckPositional()
|
||||||
|
|
||||||
PyDoc_STRVAR(set_pop__doc__,
|
PyDoc_STRVAR(set_pop__doc__,
|
||||||
|
@ -21,7 +22,13 @@ set_pop_impl(PySetObject *so);
|
||||||
static PyObject *
|
static PyObject *
|
||||||
set_pop(PySetObject *so, PyObject *Py_UNUSED(ignored))
|
set_pop(PySetObject *so, PyObject *Py_UNUSED(ignored))
|
||||||
{
|
{
|
||||||
return set_pop_impl(so);
|
PyObject *return_value = NULL;
|
||||||
|
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(so);
|
||||||
|
return_value = set_pop_impl(so);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
|
||||||
|
return return_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(set_update__doc__,
|
PyDoc_STRVAR(set_update__doc__,
|
||||||
|
@ -74,7 +81,13 @@ set_copy_impl(PySetObject *so);
|
||||||
static PyObject *
|
static PyObject *
|
||||||
set_copy(PySetObject *so, PyObject *Py_UNUSED(ignored))
|
set_copy(PySetObject *so, PyObject *Py_UNUSED(ignored))
|
||||||
{
|
{
|
||||||
return set_copy_impl(so);
|
PyObject *return_value = NULL;
|
||||||
|
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(so);
|
||||||
|
return_value = set_copy_impl(so);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
|
||||||
|
return return_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(frozenset_copy__doc__,
|
PyDoc_STRVAR(frozenset_copy__doc__,
|
||||||
|
@ -92,7 +105,13 @@ frozenset_copy_impl(PySetObject *so);
|
||||||
static PyObject *
|
static PyObject *
|
||||||
frozenset_copy(PySetObject *so, PyObject *Py_UNUSED(ignored))
|
frozenset_copy(PySetObject *so, PyObject *Py_UNUSED(ignored))
|
||||||
{
|
{
|
||||||
return frozenset_copy_impl(so);
|
PyObject *return_value = NULL;
|
||||||
|
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(so);
|
||||||
|
return_value = frozenset_copy_impl(so);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
|
||||||
|
return return_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(set_clear__doc__,
|
PyDoc_STRVAR(set_clear__doc__,
|
||||||
|
@ -110,7 +129,13 @@ set_clear_impl(PySetObject *so);
|
||||||
static PyObject *
|
static PyObject *
|
||||||
set_clear(PySetObject *so, PyObject *Py_UNUSED(ignored))
|
set_clear(PySetObject *so, PyObject *Py_UNUSED(ignored))
|
||||||
{
|
{
|
||||||
return set_clear_impl(so);
|
PyObject *return_value = NULL;
|
||||||
|
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(so);
|
||||||
|
return_value = set_clear_impl(so);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
|
||||||
|
return return_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(set_union__doc__,
|
PyDoc_STRVAR(set_union__doc__,
|
||||||
|
@ -227,6 +252,21 @@ PyDoc_STRVAR(set_isdisjoint__doc__,
|
||||||
#define SET_ISDISJOINT_METHODDEF \
|
#define SET_ISDISJOINT_METHODDEF \
|
||||||
{"isdisjoint", (PyCFunction)set_isdisjoint, METH_O, set_isdisjoint__doc__},
|
{"isdisjoint", (PyCFunction)set_isdisjoint, METH_O, set_isdisjoint__doc__},
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
set_isdisjoint_impl(PySetObject *so, PyObject *other);
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
set_isdisjoint(PySetObject *so, PyObject *other)
|
||||||
|
{
|
||||||
|
PyObject *return_value = NULL;
|
||||||
|
|
||||||
|
Py_BEGIN_CRITICAL_SECTION2(so, other);
|
||||||
|
return_value = set_isdisjoint_impl(so, other);
|
||||||
|
Py_END_CRITICAL_SECTION2();
|
||||||
|
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(set_difference_update__doc__,
|
PyDoc_STRVAR(set_difference_update__doc__,
|
||||||
"difference_update($self, /, *others)\n"
|
"difference_update($self, /, *others)\n"
|
||||||
"--\n"
|
"--\n"
|
||||||
|
@ -315,6 +355,21 @@ PyDoc_STRVAR(set_symmetric_difference__doc__,
|
||||||
#define SET_SYMMETRIC_DIFFERENCE_METHODDEF \
|
#define SET_SYMMETRIC_DIFFERENCE_METHODDEF \
|
||||||
{"symmetric_difference", (PyCFunction)set_symmetric_difference, METH_O, set_symmetric_difference__doc__},
|
{"symmetric_difference", (PyCFunction)set_symmetric_difference, METH_O, set_symmetric_difference__doc__},
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
set_symmetric_difference_impl(PySetObject *so, PyObject *other);
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
set_symmetric_difference(PySetObject *so, PyObject *other)
|
||||||
|
{
|
||||||
|
PyObject *return_value = NULL;
|
||||||
|
|
||||||
|
Py_BEGIN_CRITICAL_SECTION2(so, other);
|
||||||
|
return_value = set_symmetric_difference_impl(so, other);
|
||||||
|
Py_END_CRITICAL_SECTION2();
|
||||||
|
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(set_issubset__doc__,
|
PyDoc_STRVAR(set_issubset__doc__,
|
||||||
"issubset($self, other, /)\n"
|
"issubset($self, other, /)\n"
|
||||||
"--\n"
|
"--\n"
|
||||||
|
@ -324,6 +379,21 @@ PyDoc_STRVAR(set_issubset__doc__,
|
||||||
#define SET_ISSUBSET_METHODDEF \
|
#define SET_ISSUBSET_METHODDEF \
|
||||||
{"issubset", (PyCFunction)set_issubset, METH_O, set_issubset__doc__},
|
{"issubset", (PyCFunction)set_issubset, METH_O, set_issubset__doc__},
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
set_issubset_impl(PySetObject *so, PyObject *other);
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
set_issubset(PySetObject *so, PyObject *other)
|
||||||
|
{
|
||||||
|
PyObject *return_value = NULL;
|
||||||
|
|
||||||
|
Py_BEGIN_CRITICAL_SECTION2(so, other);
|
||||||
|
return_value = set_issubset_impl(so, other);
|
||||||
|
Py_END_CRITICAL_SECTION2();
|
||||||
|
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(set_issuperset__doc__,
|
PyDoc_STRVAR(set_issuperset__doc__,
|
||||||
"issuperset($self, other, /)\n"
|
"issuperset($self, other, /)\n"
|
||||||
"--\n"
|
"--\n"
|
||||||
|
@ -333,6 +403,21 @@ PyDoc_STRVAR(set_issuperset__doc__,
|
||||||
#define SET_ISSUPERSET_METHODDEF \
|
#define SET_ISSUPERSET_METHODDEF \
|
||||||
{"issuperset", (PyCFunction)set_issuperset, METH_O, set_issuperset__doc__},
|
{"issuperset", (PyCFunction)set_issuperset, METH_O, set_issuperset__doc__},
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
set_issuperset_impl(PySetObject *so, PyObject *other);
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
set_issuperset(PySetObject *so, PyObject *other)
|
||||||
|
{
|
||||||
|
PyObject *return_value = NULL;
|
||||||
|
|
||||||
|
Py_BEGIN_CRITICAL_SECTION2(so, other);
|
||||||
|
return_value = set_issuperset_impl(so, other);
|
||||||
|
Py_END_CRITICAL_SECTION2();
|
||||||
|
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(set_add__doc__,
|
PyDoc_STRVAR(set_add__doc__,
|
||||||
"add($self, object, /)\n"
|
"add($self, object, /)\n"
|
||||||
"--\n"
|
"--\n"
|
||||||
|
@ -344,6 +429,21 @@ PyDoc_STRVAR(set_add__doc__,
|
||||||
#define SET_ADD_METHODDEF \
|
#define SET_ADD_METHODDEF \
|
||||||
{"add", (PyCFunction)set_add, METH_O, set_add__doc__},
|
{"add", (PyCFunction)set_add, METH_O, set_add__doc__},
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
set_add_impl(PySetObject *so, PyObject *key);
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
set_add(PySetObject *so, PyObject *key)
|
||||||
|
{
|
||||||
|
PyObject *return_value = NULL;
|
||||||
|
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(so);
|
||||||
|
return_value = set_add_impl(so, key);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(set___contains____doc__,
|
PyDoc_STRVAR(set___contains____doc__,
|
||||||
"__contains__($self, object, /)\n"
|
"__contains__($self, object, /)\n"
|
||||||
"--\n"
|
"--\n"
|
||||||
|
@ -353,6 +453,21 @@ PyDoc_STRVAR(set___contains____doc__,
|
||||||
#define SET___CONTAINS___METHODDEF \
|
#define SET___CONTAINS___METHODDEF \
|
||||||
{"__contains__", (PyCFunction)set___contains__, METH_O|METH_COEXIST, set___contains____doc__},
|
{"__contains__", (PyCFunction)set___contains__, METH_O|METH_COEXIST, set___contains____doc__},
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
set___contains___impl(PySetObject *so, PyObject *key);
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
set___contains__(PySetObject *so, PyObject *key)
|
||||||
|
{
|
||||||
|
PyObject *return_value = NULL;
|
||||||
|
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(so);
|
||||||
|
return_value = set___contains___impl(so, key);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(set_remove__doc__,
|
PyDoc_STRVAR(set_remove__doc__,
|
||||||
"remove($self, object, /)\n"
|
"remove($self, object, /)\n"
|
||||||
"--\n"
|
"--\n"
|
||||||
|
@ -364,6 +479,21 @@ PyDoc_STRVAR(set_remove__doc__,
|
||||||
#define SET_REMOVE_METHODDEF \
|
#define SET_REMOVE_METHODDEF \
|
||||||
{"remove", (PyCFunction)set_remove, METH_O, set_remove__doc__},
|
{"remove", (PyCFunction)set_remove, METH_O, set_remove__doc__},
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
set_remove_impl(PySetObject *so, PyObject *key);
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
set_remove(PySetObject *so, PyObject *key)
|
||||||
|
{
|
||||||
|
PyObject *return_value = NULL;
|
||||||
|
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(so);
|
||||||
|
return_value = set_remove_impl(so, key);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(set_discard__doc__,
|
PyDoc_STRVAR(set_discard__doc__,
|
||||||
"discard($self, object, /)\n"
|
"discard($self, object, /)\n"
|
||||||
"--\n"
|
"--\n"
|
||||||
|
@ -376,6 +506,21 @@ PyDoc_STRVAR(set_discard__doc__,
|
||||||
#define SET_DISCARD_METHODDEF \
|
#define SET_DISCARD_METHODDEF \
|
||||||
{"discard", (PyCFunction)set_discard, METH_O, set_discard__doc__},
|
{"discard", (PyCFunction)set_discard, METH_O, set_discard__doc__},
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
set_discard_impl(PySetObject *so, PyObject *key);
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
set_discard(PySetObject *so, PyObject *key)
|
||||||
|
{
|
||||||
|
PyObject *return_value = NULL;
|
||||||
|
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(so);
|
||||||
|
return_value = set_discard_impl(so, key);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(set___reduce____doc__,
|
PyDoc_STRVAR(set___reduce____doc__,
|
||||||
"__reduce__($self, /)\n"
|
"__reduce__($self, /)\n"
|
||||||
"--\n"
|
"--\n"
|
||||||
|
@ -391,7 +536,13 @@ set___reduce___impl(PySetObject *so);
|
||||||
static PyObject *
|
static PyObject *
|
||||||
set___reduce__(PySetObject *so, PyObject *Py_UNUSED(ignored))
|
set___reduce__(PySetObject *so, PyObject *Py_UNUSED(ignored))
|
||||||
{
|
{
|
||||||
return set___reduce___impl(so);
|
PyObject *return_value = NULL;
|
||||||
|
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(so);
|
||||||
|
return_value = set___reduce___impl(so);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
|
||||||
|
return return_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(set___sizeof____doc__,
|
PyDoc_STRVAR(set___sizeof____doc__,
|
||||||
|
@ -409,6 +560,12 @@ set___sizeof___impl(PySetObject *so);
|
||||||
static PyObject *
|
static PyObject *
|
||||||
set___sizeof__(PySetObject *so, PyObject *Py_UNUSED(ignored))
|
set___sizeof__(PySetObject *so, PyObject *Py_UNUSED(ignored))
|
||||||
{
|
{
|
||||||
return set___sizeof___impl(so);
|
PyObject *return_value = NULL;
|
||||||
|
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(so);
|
||||||
|
return_value = set___sizeof___impl(so);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
|
||||||
|
return return_value;
|
||||||
}
|
}
|
||||||
/*[clinic end generated code: output=34a30591148da884 input=a9049054013a1b77]*/
|
/*[clinic end generated code: output=de4ee725bd29f758 input=a9049054013a1b77]*/
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include "pycore_dict.h" // _PyDict_Contains_KnownHash()
|
#include "pycore_dict.h" // _PyDict_Contains_KnownHash()
|
||||||
#include "pycore_modsupport.h" // _PyArg_NoKwnames()
|
#include "pycore_modsupport.h" // _PyArg_NoKwnames()
|
||||||
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
|
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
|
||||||
|
#include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_LOAD_SSIZE_RELAXED()
|
||||||
#include "pycore_pyerrors.h" // _PyErr_SetKeyError()
|
#include "pycore_pyerrors.h" // _PyErr_SetKeyError()
|
||||||
#include "pycore_setobject.h" // _PySet_NextEntry() definition
|
#include "pycore_setobject.h" // _PySet_NextEntry() definition
|
||||||
#include <stddef.h> // offsetof()
|
#include <stddef.h> // offsetof()
|
||||||
|
@ -130,6 +131,8 @@ set_add_entry(PySetObject *so, PyObject *key, Py_hash_t hash)
|
||||||
int probes;
|
int probes;
|
||||||
int cmp;
|
int cmp;
|
||||||
|
|
||||||
|
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
|
||||||
|
|
||||||
/* Pre-increment is necessary to prevent arbitrary code in the rich
|
/* Pre-increment is necessary to prevent arbitrary code in the rich
|
||||||
comparison from deallocating the key just before the insertion. */
|
comparison from deallocating the key just before the insertion. */
|
||||||
Py_INCREF(key);
|
Py_INCREF(key);
|
||||||
|
@ -523,7 +526,7 @@ set_dealloc(PySetObject *so)
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
set_repr(PySetObject *so)
|
set_repr_lock_held(PySetObject *so)
|
||||||
{
|
{
|
||||||
PyObject *result=NULL, *keys, *listrepr, *tmp;
|
PyObject *result=NULL, *keys, *listrepr, *tmp;
|
||||||
int status = Py_ReprEnter((PyObject*)so);
|
int status = Py_ReprEnter((PyObject*)so);
|
||||||
|
@ -567,14 +570,24 @@ done:
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Py_ssize_t
|
static PyObject *
|
||||||
set_len(PyObject *so)
|
set_repr(PySetObject *so)
|
||||||
{
|
{
|
||||||
return ((PySetObject *)so)->used;
|
PyObject *result;
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(so);
|
||||||
|
result = set_repr_lock_held(so);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Py_ssize_t
|
||||||
|
set_len(PySetObject *so)
|
||||||
|
{
|
||||||
|
return FT_ATOMIC_LOAD_SSIZE_RELAXED(so->used);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
set_merge(PySetObject *so, PyObject *otherset)
|
set_merge_lock_held(PySetObject *so, PyObject *otherset)
|
||||||
{
|
{
|
||||||
PySetObject *other;
|
PySetObject *other;
|
||||||
PyObject *key;
|
PyObject *key;
|
||||||
|
@ -584,6 +597,8 @@ set_merge(PySetObject *so, PyObject *otherset)
|
||||||
|
|
||||||
assert (PyAnySet_Check(so));
|
assert (PyAnySet_Check(so));
|
||||||
assert (PyAnySet_Check(otherset));
|
assert (PyAnySet_Check(otherset));
|
||||||
|
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
|
||||||
|
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(otherset);
|
||||||
|
|
||||||
other = (PySetObject*)otherset;
|
other = (PySetObject*)otherset;
|
||||||
if (other == so || other->used == 0)
|
if (other == so || other->used == 0)
|
||||||
|
@ -645,6 +660,7 @@ set_merge(PySetObject *so, PyObject *otherset)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@critical_section
|
||||||
set.pop
|
set.pop
|
||||||
so: setobject
|
so: setobject
|
||||||
|
|
||||||
|
@ -655,7 +671,7 @@ Raises KeyError if the set is empty.
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
set_pop_impl(PySetObject *so)
|
set_pop_impl(PySetObject *so)
|
||||||
/*[clinic end generated code: output=4d65180f1271871b input=4a3f5552e660a260]*/
|
/*[clinic end generated code: output=4d65180f1271871b input=9296c84921125060]*/
|
||||||
{
|
{
|
||||||
/* Make sure the search finger is in bounds */
|
/* Make sure the search finger is in bounds */
|
||||||
setentry *entry = so->table + (so->finger & so->mask);
|
setentry *entry = so->table + (so->finger & so->mask);
|
||||||
|
@ -889,58 +905,60 @@ PyTypeObject PySetIter_Type = {
|
||||||
static PyObject *
|
static PyObject *
|
||||||
set_iter(PySetObject *so)
|
set_iter(PySetObject *so)
|
||||||
{
|
{
|
||||||
|
Py_ssize_t size = set_len(so);
|
||||||
setiterobject *si = PyObject_GC_New(setiterobject, &PySetIter_Type);
|
setiterobject *si = PyObject_GC_New(setiterobject, &PySetIter_Type);
|
||||||
if (si == NULL)
|
if (si == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
si->si_set = (PySetObject*)Py_NewRef(so);
|
si->si_set = (PySetObject*)Py_NewRef(so);
|
||||||
si->si_used = so->used;
|
si->si_used = size;
|
||||||
si->si_pos = 0;
|
si->si_pos = 0;
|
||||||
si->len = so->used;
|
si->len = size;
|
||||||
_PyObject_GC_TRACK(si);
|
_PyObject_GC_TRACK(si);
|
||||||
return (PyObject *)si;
|
return (PyObject *)si;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
set_update_internal(PySetObject *so, PyObject *other)
|
set_update_dict_lock_held(PySetObject *so, PyObject *other)
|
||||||
{
|
{
|
||||||
PyObject *key, *it;
|
assert(PyDict_CheckExact(other));
|
||||||
|
|
||||||
if (PyAnySet_Check(other))
|
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
|
||||||
return set_merge(so, other);
|
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(other);
|
||||||
|
|
||||||
if (PyDict_CheckExact(other)) {
|
|
||||||
PyObject *value;
|
|
||||||
Py_ssize_t pos = 0;
|
|
||||||
Py_hash_t hash;
|
|
||||||
Py_ssize_t dictsize = PyDict_GET_SIZE(other);
|
|
||||||
|
|
||||||
/* Do one big resize at the start, rather than
|
/* Do one big resize at the start, rather than
|
||||||
* incrementally resizing as we insert new keys. Expect
|
* incrementally resizing as we insert new keys. Expect
|
||||||
* that there will be no (or few) overlapping keys.
|
* that there will be no (or few) overlapping keys.
|
||||||
*/
|
*/
|
||||||
if (dictsize < 0)
|
Py_ssize_t dictsize = PyDict_GET_SIZE(other);
|
||||||
return -1;
|
|
||||||
if ((so->fill + dictsize)*5 >= so->mask*3) {
|
if ((so->fill + dictsize)*5 >= so->mask*3) {
|
||||||
if (set_table_resize(so, (so->used + dictsize)*2) != 0)
|
if (set_table_resize(so, (so->used + dictsize)*2) != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
int err = 0;
|
}
|
||||||
Py_BEGIN_CRITICAL_SECTION(other);
|
|
||||||
|
Py_ssize_t pos = 0;
|
||||||
|
PyObject *key;
|
||||||
|
PyObject *value;
|
||||||
|
Py_hash_t hash;
|
||||||
while (_PyDict_Next(other, &pos, &key, &value, &hash)) {
|
while (_PyDict_Next(other, &pos, &key, &value, &hash)) {
|
||||||
if (set_add_entry(so, key, hash)) {
|
if (set_add_entry(so, key, hash)) {
|
||||||
err = -1;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exit:
|
|
||||||
Py_END_CRITICAL_SECTION();
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
it = PyObject_GetIter(other);
|
|
||||||
if (it == NULL)
|
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
set_update_iterable_lock_held(PySetObject *so, PyObject *other)
|
||||||
|
{
|
||||||
|
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
|
||||||
|
|
||||||
|
PyObject *it = PyObject_GetIter(other);
|
||||||
|
if (it == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *key;
|
||||||
while ((key = PyIter_Next(it)) != NULL) {
|
while ((key = PyIter_Next(it)) != NULL) {
|
||||||
if (set_add_key(so, key)) {
|
if (set_add_key(so, key)) {
|
||||||
Py_DECREF(it);
|
Py_DECREF(it);
|
||||||
|
@ -955,6 +973,69 @@ exit:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
set_update_lock_held(PySetObject *so, PyObject *other)
|
||||||
|
{
|
||||||
|
if (PyAnySet_Check(other)) {
|
||||||
|
return set_merge_lock_held(so, other);
|
||||||
|
}
|
||||||
|
else if (PyDict_CheckExact(other)) {
|
||||||
|
return set_update_dict_lock_held(so, other);
|
||||||
|
}
|
||||||
|
return set_update_iterable_lock_held(so, other);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set_update for a `so` that is only visible to the current thread
|
||||||
|
static int
|
||||||
|
set_update_local(PySetObject *so, PyObject *other)
|
||||||
|
{
|
||||||
|
assert(Py_REFCNT(so) == 1);
|
||||||
|
if (PyAnySet_Check(other)) {
|
||||||
|
int rv;
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(other);
|
||||||
|
rv = set_merge_lock_held(so, other);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
else if (PyDict_CheckExact(other)) {
|
||||||
|
int rv;
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(other);
|
||||||
|
rv = set_update_dict_lock_held(so, other);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
return set_update_iterable_lock_held(so, other);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
set_update_internal(PySetObject *so, PyObject *other)
|
||||||
|
{
|
||||||
|
if (PyAnySet_Check(other)) {
|
||||||
|
if (Py_Is((PyObject *)so, other)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int rv;
|
||||||
|
Py_BEGIN_CRITICAL_SECTION2(so, other);
|
||||||
|
rv = set_merge_lock_held(so, other);
|
||||||
|
Py_END_CRITICAL_SECTION2();
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
else if (PyDict_CheckExact(other)) {
|
||||||
|
int rv;
|
||||||
|
Py_BEGIN_CRITICAL_SECTION2(so, other);
|
||||||
|
rv = set_update_dict_lock_held(so, other);
|
||||||
|
Py_END_CRITICAL_SECTION2();
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int rv;
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(so);
|
||||||
|
rv = set_update_iterable_lock_held(so, other);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
set.update
|
set.update
|
||||||
so: setobject
|
so: setobject
|
||||||
|
@ -1003,7 +1084,7 @@ make_new_set(PyTypeObject *type, PyObject *iterable)
|
||||||
so->weakreflist = NULL;
|
so->weakreflist = NULL;
|
||||||
|
|
||||||
if (iterable != NULL) {
|
if (iterable != NULL) {
|
||||||
if (set_update_internal(so, iterable)) {
|
if (set_update_local(so, iterable)) {
|
||||||
Py_DECREF(so);
|
Py_DECREF(so);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1126,6 +1207,7 @@ set_swap_bodies(PySetObject *a, PySetObject *b)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@critical_section
|
||||||
set.copy
|
set.copy
|
||||||
so: setobject
|
so: setobject
|
||||||
|
|
||||||
|
@ -1134,12 +1216,22 @@ Return a shallow copy of a set.
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
set_copy_impl(PySetObject *so)
|
set_copy_impl(PySetObject *so)
|
||||||
/*[clinic end generated code: output=c9223a1e1cc6b041 input=2b80b288d47b8cf1]*/
|
/*[clinic end generated code: output=c9223a1e1cc6b041 input=c169a4fbb8209257]*/
|
||||||
{
|
{
|
||||||
return make_new_set_basetype(Py_TYPE(so), (PyObject *)so);
|
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
|
||||||
|
PyObject *copy = make_new_set_basetype(Py_TYPE(so), NULL);
|
||||||
|
if (copy == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (set_merge_lock_held((PySetObject *)copy, (PyObject *)so) < 0) {
|
||||||
|
Py_DECREF(copy);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@critical_section
|
||||||
frozenset.copy
|
frozenset.copy
|
||||||
so: setobject
|
so: setobject
|
||||||
|
|
||||||
|
@ -1148,15 +1240,16 @@ Return a shallow copy of a set.
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
frozenset_copy_impl(PySetObject *so)
|
frozenset_copy_impl(PySetObject *so)
|
||||||
/*[clinic end generated code: output=b356263526af9e70 input=3dc65577d344eff7]*/
|
/*[clinic end generated code: output=b356263526af9e70 input=fbf5bef131268dd7]*/
|
||||||
{
|
{
|
||||||
if (PyFrozenSet_CheckExact(so)) {
|
if (PyFrozenSet_CheckExact(so)) {
|
||||||
return Py_NewRef(so);
|
return Py_NewRef(so);
|
||||||
}
|
}
|
||||||
return set_copy(so, NULL);
|
return set_copy_impl(so);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@critical_section
|
||||||
set.clear
|
set.clear
|
||||||
so: setobject
|
so: setobject
|
||||||
|
|
||||||
|
@ -1165,7 +1258,7 @@ Remove all elements from this set.
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
set_clear_impl(PySetObject *so)
|
set_clear_impl(PySetObject *so)
|
||||||
/*[clinic end generated code: output=4e71d5a83904161a input=74ac19794da81a39]*/
|
/*[clinic end generated code: output=4e71d5a83904161a input=c6f831b366111950]*/
|
||||||
{
|
{
|
||||||
set_clear_internal(so);
|
set_clear_internal(so);
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
|
@ -1196,7 +1289,7 @@ set_union_impl(PySetObject *so, PyObject *args)
|
||||||
other = PyTuple_GET_ITEM(args, i);
|
other = PyTuple_GET_ITEM(args, i);
|
||||||
if ((PyObject *)so == other)
|
if ((PyObject *)so == other)
|
||||||
continue;
|
continue;
|
||||||
if (set_update_internal(result, other)) {
|
if (set_update_local(result, other)) {
|
||||||
Py_DECREF(result);
|
Py_DECREF(result);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1213,11 +1306,13 @@ set_or(PySetObject *so, PyObject *other)
|
||||||
Py_RETURN_NOTIMPLEMENTED;
|
Py_RETURN_NOTIMPLEMENTED;
|
||||||
|
|
||||||
result = (PySetObject *)set_copy(so, NULL);
|
result = (PySetObject *)set_copy(so, NULL);
|
||||||
if (result == NULL)
|
if (result == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
if ((PyObject *)so == other)
|
}
|
||||||
|
if (Py_Is((PyObject *)so, other)) {
|
||||||
return (PyObject *)result;
|
return (PyObject *)result;
|
||||||
if (set_update_internal(result, other)) {
|
}
|
||||||
|
if (set_update_local(result, other)) {
|
||||||
Py_DECREF(result);
|
Py_DECREF(result);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1230,8 +1325,9 @@ set_ior(PySetObject *so, PyObject *other)
|
||||||
if (!PyAnySet_Check(other))
|
if (!PyAnySet_Check(other))
|
||||||
Py_RETURN_NOTIMPLEMENTED;
|
Py_RETURN_NOTIMPLEMENTED;
|
||||||
|
|
||||||
if (set_update_internal(so, other))
|
if (set_update_internal(so, other)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
return Py_NewRef(so);
|
return Py_NewRef(so);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1244,7 +1340,7 @@ set_intersection(PySetObject *so, PyObject *other)
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
if ((PyObject *)so == other)
|
if ((PyObject *)so == other)
|
||||||
return set_copy(so, NULL);
|
return set_copy_impl(so);
|
||||||
|
|
||||||
result = (PySetObject *)make_new_set_basetype(Py_TYPE(so), NULL);
|
result = (PySetObject *)make_new_set_basetype(Py_TYPE(so), NULL);
|
||||||
if (result == NULL)
|
if (result == NULL)
|
||||||
|
@ -1333,13 +1429,17 @@ set_intersection_multi_impl(PySetObject *so, PyObject *args)
|
||||||
{
|
{
|
||||||
Py_ssize_t i;
|
Py_ssize_t i;
|
||||||
|
|
||||||
if (PyTuple_GET_SIZE(args) == 0)
|
if (PyTuple_GET_SIZE(args) == 0) {
|
||||||
return set_copy(so, NULL);
|
return set_copy(so, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
PyObject *result = Py_NewRef(so);
|
PyObject *result = Py_NewRef(so);
|
||||||
for (i=0 ; i<PyTuple_GET_SIZE(args) ; i++) {
|
for (i=0 ; i<PyTuple_GET_SIZE(args) ; i++) {
|
||||||
PyObject *other = PyTuple_GET_ITEM(args, i);
|
PyObject *other = PyTuple_GET_ITEM(args, i);
|
||||||
PyObject *newresult = set_intersection((PySetObject *)result, other);
|
PyObject *newresult;
|
||||||
|
Py_BEGIN_CRITICAL_SECTION2(result, other);
|
||||||
|
newresult = set_intersection((PySetObject *)result, other);
|
||||||
|
Py_END_CRITICAL_SECTION2();
|
||||||
if (newresult == NULL) {
|
if (newresult == NULL) {
|
||||||
Py_DECREF(result);
|
Py_DECREF(result);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1380,7 +1480,9 @@ set_intersection_update_multi_impl(PySetObject *so, PyObject *args)
|
||||||
tmp = set_intersection_multi_impl(so, args);
|
tmp = set_intersection_multi_impl(so, args);
|
||||||
if (tmp == NULL)
|
if (tmp == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(so);
|
||||||
set_swap_bodies(so, (PySetObject *)tmp);
|
set_swap_bodies(so, (PySetObject *)tmp);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
Py_DECREF(tmp);
|
Py_DECREF(tmp);
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
@ -1390,7 +1492,13 @@ set_and(PySetObject *so, PyObject *other)
|
||||||
{
|
{
|
||||||
if (!PyAnySet_Check(so) || !PyAnySet_Check(other))
|
if (!PyAnySet_Check(so) || !PyAnySet_Check(other))
|
||||||
Py_RETURN_NOTIMPLEMENTED;
|
Py_RETURN_NOTIMPLEMENTED;
|
||||||
return set_intersection(so, other);
|
|
||||||
|
PyObject *rv;
|
||||||
|
Py_BEGIN_CRITICAL_SECTION2(so, other);
|
||||||
|
rv = set_intersection(so, other);
|
||||||
|
Py_END_CRITICAL_SECTION2();
|
||||||
|
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -1400,7 +1508,11 @@ set_iand(PySetObject *so, PyObject *other)
|
||||||
|
|
||||||
if (!PyAnySet_Check(other))
|
if (!PyAnySet_Check(other))
|
||||||
Py_RETURN_NOTIMPLEMENTED;
|
Py_RETURN_NOTIMPLEMENTED;
|
||||||
|
|
||||||
|
Py_BEGIN_CRITICAL_SECTION2(so, other);
|
||||||
result = set_intersection_update(so, other);
|
result = set_intersection_update(so, other);
|
||||||
|
Py_END_CRITICAL_SECTION2();
|
||||||
|
|
||||||
if (result == NULL)
|
if (result == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
Py_DECREF(result);
|
Py_DECREF(result);
|
||||||
|
@ -1408,6 +1520,7 @@ set_iand(PySetObject *so, PyObject *other)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@critical_section so other
|
||||||
set.isdisjoint
|
set.isdisjoint
|
||||||
so: setobject
|
so: setobject
|
||||||
other: object
|
other: object
|
||||||
|
@ -1417,8 +1530,8 @@ Return True if two sets have a null intersection.
|
||||||
[clinic start generated code]*/
|
[clinic start generated code]*/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
set_isdisjoint(PySetObject *so, PyObject *other)
|
set_isdisjoint_impl(PySetObject *so, PyObject *other)
|
||||||
/*[clinic end generated code: output=a92bbf9a2db6a3da input=c254ddec8a2326e3]*/
|
/*[clinic end generated code: output=273493f2d57c565e input=32f8dcab5e0fc7d6]*/
|
||||||
{
|
{
|
||||||
PyObject *key, *it, *tmp;
|
PyObject *key, *it, *tmp;
|
||||||
int rv;
|
int rv;
|
||||||
|
@ -1479,6 +1592,9 @@ set_isdisjoint(PySetObject *so, PyObject *other)
|
||||||
static int
|
static int
|
||||||
set_difference_update_internal(PySetObject *so, PyObject *other)
|
set_difference_update_internal(PySetObject *so, PyObject *other)
|
||||||
{
|
{
|
||||||
|
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
|
||||||
|
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(other);
|
||||||
|
|
||||||
if ((PyObject *)so == other)
|
if ((PyObject *)so == other)
|
||||||
return set_clear_internal(so);
|
return set_clear_internal(so);
|
||||||
|
|
||||||
|
@ -1551,9 +1667,14 @@ set_difference_update_impl(PySetObject *so, PyObject *args)
|
||||||
|
|
||||||
for (i=0 ; i<PyTuple_GET_SIZE(args) ; i++) {
|
for (i=0 ; i<PyTuple_GET_SIZE(args) ; i++) {
|
||||||
PyObject *other = PyTuple_GET_ITEM(args, i);
|
PyObject *other = PyTuple_GET_ITEM(args, i);
|
||||||
if (set_difference_update_internal(so, other))
|
int rv;
|
||||||
|
Py_BEGIN_CRITICAL_SECTION2(so, other);
|
||||||
|
rv = set_difference_update_internal(so, other);
|
||||||
|
Py_END_CRITICAL_SECTION2();
|
||||||
|
if (rv) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1562,7 +1683,7 @@ set_copy_and_difference(PySetObject *so, PyObject *other)
|
||||||
{
|
{
|
||||||
PyObject *result;
|
PyObject *result;
|
||||||
|
|
||||||
result = set_copy(so, NULL);
|
result = set_copy_impl(so);
|
||||||
if (result == NULL)
|
if (result == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (set_difference_update_internal((PySetObject *) result, other) == 0)
|
if (set_difference_update_internal((PySetObject *) result, other) == 0)
|
||||||
|
@ -1663,17 +1784,24 @@ set_difference_multi_impl(PySetObject *so, PyObject *args)
|
||||||
Py_ssize_t i;
|
Py_ssize_t i;
|
||||||
PyObject *result, *other;
|
PyObject *result, *other;
|
||||||
|
|
||||||
if (PyTuple_GET_SIZE(args) == 0)
|
if (PyTuple_GET_SIZE(args) == 0) {
|
||||||
return set_copy(so, NULL);
|
return set_copy(so, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
other = PyTuple_GET_ITEM(args, 0);
|
other = PyTuple_GET_ITEM(args, 0);
|
||||||
|
Py_BEGIN_CRITICAL_SECTION2(so, other);
|
||||||
result = set_difference(so, other);
|
result = set_difference(so, other);
|
||||||
|
Py_END_CRITICAL_SECTION2();
|
||||||
if (result == NULL)
|
if (result == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
for (i=1 ; i<PyTuple_GET_SIZE(args) ; i++) {
|
for (i=1 ; i<PyTuple_GET_SIZE(args) ; i++) {
|
||||||
other = PyTuple_GET_ITEM(args, i);
|
other = PyTuple_GET_ITEM(args, i);
|
||||||
if (set_difference_update_internal((PySetObject *)result, other)) {
|
int rv;
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(other);
|
||||||
|
rv = set_difference_update_internal((PySetObject *)result, other);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
if (rv) {
|
||||||
Py_DECREF(result);
|
Py_DECREF(result);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1686,7 +1814,12 @@ set_sub(PySetObject *so, PyObject *other)
|
||||||
{
|
{
|
||||||
if (!PyAnySet_Check(so) || !PyAnySet_Check(other))
|
if (!PyAnySet_Check(so) || !PyAnySet_Check(other))
|
||||||
Py_RETURN_NOTIMPLEMENTED;
|
Py_RETURN_NOTIMPLEMENTED;
|
||||||
return set_difference(so, other);
|
|
||||||
|
PyObject *rv;
|
||||||
|
Py_BEGIN_CRITICAL_SECTION2(so, other);
|
||||||
|
rv = set_difference(so, other);
|
||||||
|
Py_END_CRITICAL_SECTION2();
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -1694,36 +1827,69 @@ set_isub(PySetObject *so, PyObject *other)
|
||||||
{
|
{
|
||||||
if (!PyAnySet_Check(other))
|
if (!PyAnySet_Check(other))
|
||||||
Py_RETURN_NOTIMPLEMENTED;
|
Py_RETURN_NOTIMPLEMENTED;
|
||||||
if (set_difference_update_internal(so, other))
|
|
||||||
|
int rv;
|
||||||
|
Py_BEGIN_CRITICAL_SECTION2(so, other);
|
||||||
|
rv = set_difference_update_internal(so, other);
|
||||||
|
Py_END_CRITICAL_SECTION2();
|
||||||
|
if (rv < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
return Py_NewRef(so);
|
return Py_NewRef(so);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static int
|
||||||
set_symmetric_difference_update_dict(PySetObject *so, PyObject *other)
|
set_symmetric_difference_update_dict(PySetObject *so, PyObject *other)
|
||||||
{
|
{
|
||||||
PyObject *key;
|
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
|
||||||
Py_ssize_t pos = 0;
|
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(other);
|
||||||
Py_hash_t hash;
|
|
||||||
PyObject *value;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
|
Py_ssize_t pos = 0;
|
||||||
|
PyObject *key, *value;
|
||||||
|
Py_hash_t hash;
|
||||||
while (_PyDict_Next(other, &pos, &key, &value, &hash)) {
|
while (_PyDict_Next(other, &pos, &key, &value, &hash)) {
|
||||||
Py_INCREF(key);
|
Py_INCREF(key);
|
||||||
rv = set_discard_entry(so, key, hash);
|
int rv = set_discard_entry(so, key, hash);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
Py_DECREF(key);
|
Py_DECREF(key);
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
if (rv == DISCARD_NOTFOUND) {
|
if (rv == DISCARD_NOTFOUND) {
|
||||||
if (set_add_entry(so, key, hash)) {
|
if (set_add_entry(so, key, hash)) {
|
||||||
Py_DECREF(key);
|
Py_DECREF(key);
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Py_DECREF(key);
|
Py_DECREF(key);
|
||||||
}
|
}
|
||||||
Py_RETURN_NONE;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
set_symmetric_difference_update_set(PySetObject *so, PySetObject *other)
|
||||||
|
{
|
||||||
|
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
|
||||||
|
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(other);
|
||||||
|
|
||||||
|
Py_ssize_t pos = 0;
|
||||||
|
setentry *entry;
|
||||||
|
while (set_next(other, &pos, &entry)) {
|
||||||
|
PyObject *key = Py_NewRef(entry->key);
|
||||||
|
Py_hash_t hash = entry->hash;
|
||||||
|
int rv = set_discard_entry(so, key, hash);
|
||||||
|
if (rv < 0) {
|
||||||
|
Py_DECREF(key);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (rv == DISCARD_NOTFOUND) {
|
||||||
|
if (set_add_entry(so, key, hash)) {
|
||||||
|
Py_DECREF(key);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Py_DECREF(key);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@ -1739,58 +1905,41 @@ static PyObject *
|
||||||
set_symmetric_difference_update(PySetObject *so, PyObject *other)
|
set_symmetric_difference_update(PySetObject *so, PyObject *other)
|
||||||
/*[clinic end generated code: output=fbb049c0806028de input=a50acf0365e1f0a5]*/
|
/*[clinic end generated code: output=fbb049c0806028de input=a50acf0365e1f0a5]*/
|
||||||
{
|
{
|
||||||
PySetObject *otherset;
|
if (Py_Is((PyObject *)so, other)) {
|
||||||
PyObject *key;
|
|
||||||
Py_ssize_t pos = 0;
|
|
||||||
Py_hash_t hash;
|
|
||||||
setentry *entry;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
if ((PyObject *)so == other)
|
|
||||||
return set_clear(so, NULL);
|
return set_clear(so, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rv;
|
||||||
if (PyDict_CheckExact(other)) {
|
if (PyDict_CheckExact(other)) {
|
||||||
PyObject *res;
|
Py_BEGIN_CRITICAL_SECTION2(so, other);
|
||||||
|
rv = set_symmetric_difference_update_dict(so, other);
|
||||||
|
Py_END_CRITICAL_SECTION2();
|
||||||
|
}
|
||||||
|
else if (PyAnySet_Check(other)) {
|
||||||
|
Py_BEGIN_CRITICAL_SECTION2(so, other);
|
||||||
|
rv = set_symmetric_difference_update_set(so, (PySetObject *)other);
|
||||||
|
Py_END_CRITICAL_SECTION2();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PySetObject *otherset = (PySetObject *)make_new_set_basetype(Py_TYPE(so), other);
|
||||||
|
if (otherset == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
Py_BEGIN_CRITICAL_SECTION(other);
|
Py_BEGIN_CRITICAL_SECTION(so);
|
||||||
res = set_symmetric_difference_update_dict(so, other);
|
rv = set_symmetric_difference_update_set(so, otherset);
|
||||||
Py_END_CRITICAL_SECTION();
|
Py_END_CRITICAL_SECTION();
|
||||||
|
|
||||||
return res;
|
Py_DECREF(otherset);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PyAnySet_Check(other)) {
|
|
||||||
otherset = (PySetObject *)Py_NewRef(other);
|
|
||||||
} else {
|
|
||||||
otherset = (PySetObject *)make_new_set_basetype(Py_TYPE(so), other);
|
|
||||||
if (otherset == NULL)
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (set_next(otherset, &pos, &entry)) {
|
|
||||||
key = entry->key;
|
|
||||||
hash = entry->hash;
|
|
||||||
Py_INCREF(key);
|
|
||||||
rv = set_discard_entry(so, key, hash);
|
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
Py_DECREF(otherset);
|
|
||||||
Py_DECREF(key);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (rv == DISCARD_NOTFOUND) {
|
|
||||||
if (set_add_entry(so, key, hash)) {
|
|
||||||
Py_DECREF(otherset);
|
|
||||||
Py_DECREF(key);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Py_DECREF(key);
|
|
||||||
}
|
|
||||||
Py_DECREF(otherset);
|
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@critical_section so other
|
||||||
set.symmetric_difference
|
set.symmetric_difference
|
||||||
so: setobject
|
so: setobject
|
||||||
other: object
|
other: object
|
||||||
|
@ -1800,22 +1949,22 @@ Return a new set with elements in either the set or other but not both.
|
||||||
[clinic start generated code]*/
|
[clinic start generated code]*/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
set_symmetric_difference(PySetObject *so, PyObject *other)
|
set_symmetric_difference_impl(PySetObject *so, PyObject *other)
|
||||||
/*[clinic end generated code: output=f95364211b88775a input=f18af370ad72ebac]*/
|
/*[clinic end generated code: output=270ee0b5d42b0797 input=624f6e7bbdf70db1]*/
|
||||||
{
|
{
|
||||||
PyObject *rv;
|
PySetObject *result = (PySetObject *)make_new_set_basetype(Py_TYPE(so), NULL);
|
||||||
PySetObject *otherset;
|
if (result == NULL) {
|
||||||
|
|
||||||
otherset = (PySetObject *)make_new_set_basetype(Py_TYPE(so), other);
|
|
||||||
if (otherset == NULL)
|
|
||||||
return NULL;
|
|
||||||
rv = set_symmetric_difference_update(otherset, (PyObject *)so);
|
|
||||||
if (rv == NULL) {
|
|
||||||
Py_DECREF(otherset);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
Py_DECREF(rv);
|
if (set_update_lock_held(result, other) < 0) {
|
||||||
return (PyObject *)otherset;
|
Py_DECREF(result);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (set_symmetric_difference_update_set(result, so) < 0) {
|
||||||
|
Py_DECREF(result);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return (PyObject *)result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -1841,6 +1990,7 @@ set_ixor(PySetObject *so, PyObject *other)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@critical_section so other
|
||||||
set.issubset
|
set.issubset
|
||||||
so: setobject
|
so: setobject
|
||||||
other: object
|
other: object
|
||||||
|
@ -1850,8 +2000,8 @@ Report whether another set contains this set.
|
||||||
[clinic start generated code]*/
|
[clinic start generated code]*/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
set_issubset(PySetObject *so, PyObject *other)
|
set_issubset_impl(PySetObject *so, PyObject *other)
|
||||||
/*[clinic end generated code: output=78aef1f377aedef1 input=37fbc579b609db0c]*/
|
/*[clinic end generated code: output=b2b59d5f314555ce input=f2a4fd0f2537758b]*/
|
||||||
{
|
{
|
||||||
setentry *entry;
|
setentry *entry;
|
||||||
Py_ssize_t pos = 0;
|
Py_ssize_t pos = 0;
|
||||||
|
@ -1885,6 +2035,7 @@ set_issubset(PySetObject *so, PyObject *other)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@critical_section so other
|
||||||
set.issuperset
|
set.issuperset
|
||||||
so: setobject
|
so: setobject
|
||||||
other: object
|
other: object
|
||||||
|
@ -1894,8 +2045,8 @@ Report whether this set contains another set.
|
||||||
[clinic start generated code]*/
|
[clinic start generated code]*/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
set_issuperset(PySetObject *so, PyObject *other)
|
set_issuperset_impl(PySetObject *so, PyObject *other)
|
||||||
/*[clinic end generated code: output=7d2b71dd714a7ec7 input=fd5dab052f2e9bb3]*/
|
/*[clinic end generated code: output=ecf00ce552c09461 input=5f2e1f262e6e4ccc]*/
|
||||||
{
|
{
|
||||||
if (PyAnySet_Check(other)) {
|
if (PyAnySet_Check(other)) {
|
||||||
return set_issubset((PySetObject *)other, (PyObject *)so);
|
return set_issubset((PySetObject *)other, (PyObject *)so);
|
||||||
|
@ -1924,6 +2075,7 @@ set_issuperset(PySetObject *so, PyObject *other)
|
||||||
Py_RETURN_TRUE;
|
Py_RETURN_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Make thread-safe in free-threaded builds
|
||||||
static PyObject *
|
static PyObject *
|
||||||
set_richcompare(PySetObject *v, PyObject *w, int op)
|
set_richcompare(PySetObject *v, PyObject *w, int op)
|
||||||
{
|
{
|
||||||
|
@ -1968,6 +2120,7 @@ set_richcompare(PySetObject *v, PyObject *w, int op)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@critical_section
|
||||||
set.add
|
set.add
|
||||||
so: setobject
|
so: setobject
|
||||||
object as key: object
|
object as key: object
|
||||||
|
@ -1979,16 +2132,16 @@ This has no effect if the element is already present.
|
||||||
[clinic start generated code]*/
|
[clinic start generated code]*/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
set_add(PySetObject *so, PyObject *key)
|
set_add_impl(PySetObject *so, PyObject *key)
|
||||||
/*[clinic end generated code: output=cd9c2d5c2069c2ba input=96f1efe029e47972]*/
|
/*[clinic end generated code: output=4cc4a937f1425c96 input=03baf62cb0e66514]*/
|
||||||
{
|
{
|
||||||
if (set_add_key(so, key))
|
if (set_add_key(so, key))
|
||||||
return NULL;
|
return NULL;
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
_PySet_Contains(PySetObject *so, PyObject *key)
|
set_contains_lock_held(PySetObject *so, PyObject *key)
|
||||||
{
|
{
|
||||||
PyObject *tmpkey;
|
PyObject *tmpkey;
|
||||||
int rv;
|
int rv;
|
||||||
|
@ -2007,7 +2160,18 @@ _PySet_Contains(PySetObject *so, PyObject *key)
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_PySet_Contains(PySetObject *so, PyObject *key)
|
||||||
|
{
|
||||||
|
int rv;
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(so);
|
||||||
|
rv = set_contains_lock_held(so, key);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@critical_section
|
||||||
@coexist
|
@coexist
|
||||||
set.__contains__
|
set.__contains__
|
||||||
so: setobject
|
so: setobject
|
||||||
|
@ -2018,18 +2182,19 @@ x.__contains__(y) <==> y in x.
|
||||||
[clinic start generated code]*/
|
[clinic start generated code]*/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
set___contains__(PySetObject *so, PyObject *key)
|
set___contains___impl(PySetObject *so, PyObject *key)
|
||||||
/*[clinic end generated code: output=b5948bc5c590d3ca input=cf4c72db704e4cf0]*/
|
/*[clinic end generated code: output=b44863d034b3c70e input=4a7d568459617f24]*/
|
||||||
{
|
{
|
||||||
long result;
|
long result;
|
||||||
|
|
||||||
result = _PySet_Contains(so, key);
|
result = set_contains_lock_held(so, key);
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
return PyBool_FromLong(result);
|
return PyBool_FromLong(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@critical_section
|
||||||
set.remove
|
set.remove
|
||||||
so: setobject
|
so: setobject
|
||||||
object as key: object
|
object as key: object
|
||||||
|
@ -2041,8 +2206,8 @@ If the element is not a member, raise a KeyError.
|
||||||
[clinic start generated code]*/
|
[clinic start generated code]*/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
set_remove(PySetObject *so, PyObject *key)
|
set_remove_impl(PySetObject *so, PyObject *key)
|
||||||
/*[clinic end generated code: output=08ae496d0cd2b8c1 input=10132515dfe8ebd7]*/
|
/*[clinic end generated code: output=0b9134a2a2200363 input=893e1cb1df98227a]*/
|
||||||
{
|
{
|
||||||
PyObject *tmpkey;
|
PyObject *tmpkey;
|
||||||
int rv;
|
int rv;
|
||||||
|
@ -2069,6 +2234,7 @@ set_remove(PySetObject *so, PyObject *key)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@critical_section
|
||||||
set.discard
|
set.discard
|
||||||
so: setobject
|
so: setobject
|
||||||
object as key: object
|
object as key: object
|
||||||
|
@ -2081,8 +2247,8 @@ an exception when an element is missing from the set.
|
||||||
[clinic start generated code]*/
|
[clinic start generated code]*/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
set_discard(PySetObject *so, PyObject *key)
|
set_discard_impl(PySetObject *so, PyObject *key)
|
||||||
/*[clinic end generated code: output=9181b60d7bb7d480 input=82a689eba94d5ad9]*/
|
/*[clinic end generated code: output=eec3b687bf32759e input=861cb7fb69b4def0]*/
|
||||||
{
|
{
|
||||||
PyObject *tmpkey;
|
PyObject *tmpkey;
|
||||||
int rv;
|
int rv;
|
||||||
|
@ -2104,6 +2270,7 @@ set_discard(PySetObject *so, PyObject *key)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@critical_section
|
||||||
set.__reduce__
|
set.__reduce__
|
||||||
so: setobject
|
so: setobject
|
||||||
|
|
||||||
|
@ -2112,7 +2279,7 @@ Return state information for pickling.
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
set___reduce___impl(PySetObject *so)
|
set___reduce___impl(PySetObject *so)
|
||||||
/*[clinic end generated code: output=9af7d0e029df87ee input=531375e87a24a449]*/
|
/*[clinic end generated code: output=9af7d0e029df87ee input=59405a4249e82f71]*/
|
||||||
{
|
{
|
||||||
PyObject *keys=NULL, *args=NULL, *result=NULL, *state=NULL;
|
PyObject *keys=NULL, *args=NULL, *result=NULL, *state=NULL;
|
||||||
|
|
||||||
|
@ -2134,6 +2301,7 @@ done:
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@critical_section
|
||||||
set.__sizeof__
|
set.__sizeof__
|
||||||
so: setobject
|
so: setobject
|
||||||
|
|
||||||
|
@ -2142,7 +2310,7 @@ S.__sizeof__() -> size of S in memory, in bytes.
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
set___sizeof___impl(PySetObject *so)
|
set___sizeof___impl(PySetObject *so)
|
||||||
/*[clinic end generated code: output=4bfa3df7bd38ed88 input=0f214fc2225319fc]*/
|
/*[clinic end generated code: output=4bfa3df7bd38ed88 input=09e1a09f168eaa23]*/
|
||||||
{
|
{
|
||||||
size_t res = _PyObject_SIZE(Py_TYPE(so));
|
size_t res = _PyObject_SIZE(Py_TYPE(so));
|
||||||
if (so->table != so->smalltable) {
|
if (so->table != so->smalltable) {
|
||||||
|
@ -2160,9 +2328,13 @@ set_init(PySetObject *self, PyObject *args, PyObject *kwds)
|
||||||
return -1;
|
return -1;
|
||||||
if (!PyArg_UnpackTuple(args, Py_TYPE(self)->tp_name, 0, 1, &iterable))
|
if (!PyArg_UnpackTuple(args, Py_TYPE(self)->tp_name, 0, 1, &iterable))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(self);
|
||||||
if (self->fill)
|
if (self->fill)
|
||||||
set_clear_internal(self);
|
set_clear_internal(self);
|
||||||
self->hash = -1;
|
self->hash = -1;
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
|
||||||
if (iterable == NULL)
|
if (iterable == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
return set_update_internal(self, iterable);
|
return set_update_internal(self, iterable);
|
||||||
|
@ -2191,7 +2363,7 @@ set_vectorcall(PyObject *type, PyObject * const*args,
|
||||||
}
|
}
|
||||||
|
|
||||||
static PySequenceMethods set_as_sequence = {
|
static PySequenceMethods set_as_sequence = {
|
||||||
set_len, /* sq_length */
|
(lenfunc)set_len, /* sq_length */
|
||||||
0, /* sq_concat */
|
0, /* sq_concat */
|
||||||
0, /* sq_repeat */
|
0, /* sq_repeat */
|
||||||
0, /* sq_item */
|
0, /* sq_item */
|
||||||
|
@ -2424,7 +2596,7 @@ PySet_Size(PyObject *anyset)
|
||||||
PyErr_BadInternalCall();
|
PyErr_BadInternalCall();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return PySet_GET_SIZE(anyset);
|
return set_len((PySetObject *)anyset);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -2434,7 +2606,8 @@ PySet_Clear(PyObject *set)
|
||||||
PyErr_BadInternalCall();
|
PyErr_BadInternalCall();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return set_clear_internal((PySetObject *)set);
|
(void)set_clear((PySetObject *)set, NULL);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -2444,7 +2617,12 @@ PySet_Contains(PyObject *anyset, PyObject *key)
|
||||||
PyErr_BadInternalCall();
|
PyErr_BadInternalCall();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return set_contains_key((PySetObject *)anyset, key);
|
|
||||||
|
int rv;
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(anyset);
|
||||||
|
rv = set_contains_key((PySetObject *)anyset, key);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -2454,7 +2632,12 @@ PySet_Discard(PyObject *set, PyObject *key)
|
||||||
PyErr_BadInternalCall();
|
PyErr_BadInternalCall();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return set_discard_key((PySetObject *)set, key);
|
|
||||||
|
int rv;
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(set);
|
||||||
|
rv = set_discard_key((PySetObject *)set, key);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -2465,9 +2648,15 @@ PySet_Add(PyObject *anyset, PyObject *key)
|
||||||
PyErr_BadInternalCall();
|
PyErr_BadInternalCall();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return set_add_key((PySetObject *)anyset, key);
|
|
||||||
|
int rv;
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(anyset);
|
||||||
|
rv = set_add_key((PySetObject *)anyset, key);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Make thread-safe in free-threaded builds
|
||||||
int
|
int
|
||||||
_PySet_NextEntry(PyObject *set, Py_ssize_t *pos, PyObject **key, Py_hash_t *hash)
|
_PySet_NextEntry(PyObject *set, Py_ssize_t *pos, PyObject **key, Py_hash_t *hash)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue