mirror of
https://github.com/python/cpython.git
synced 2025-12-08 06:10:17 +00:00
Merge remote-tracking branch 'origin/main' into HEAD
This commit is contained in:
commit
8d57aca95a
1284 changed files with 27792 additions and 11927 deletions
|
|
@ -1469,14 +1469,14 @@ bytearray_removesuffix_impl(PyByteArrayObject *self, Py_buffer *suffix)
|
|||
/*[clinic input]
|
||||
bytearray.resize
|
||||
size: Py_ssize_t
|
||||
New size to resize to..
|
||||
New size to resize to.
|
||||
/
|
||||
Resize the internal buffer of bytearray to len.
|
||||
[clinic start generated code]*/
|
||||
|
||||
static PyObject *
|
||||
bytearray_resize_impl(PyByteArrayObject *self, Py_ssize_t size)
|
||||
/*[clinic end generated code: output=f73524922990b2d9 input=75fd4d17c4aa47d3]*/
|
||||
/*[clinic end generated code: output=f73524922990b2d9 input=6c9a260ca7f72071]*/
|
||||
{
|
||||
Py_ssize_t start_size = PyByteArray_GET_SIZE(self);
|
||||
int result = PyByteArray_Resize((PyObject *)self, size);
|
||||
|
|
|
|||
|
|
@ -3171,7 +3171,7 @@ PyBytes_Concat(PyObject **pv, PyObject *w)
|
|||
return;
|
||||
}
|
||||
|
||||
if (Py_REFCNT(*pv) == 1 && PyBytes_CheckExact(*pv)) {
|
||||
if (_PyObject_IsUniquelyReferenced(*pv) && PyBytes_CheckExact(*pv)) {
|
||||
/* Only one reference, so we can resize in place */
|
||||
Py_ssize_t oldsize;
|
||||
Py_buffer wb;
|
||||
|
|
@ -3256,7 +3256,7 @@ _PyBytes_Resize(PyObject **pv, Py_ssize_t newsize)
|
|||
Py_DECREF(v);
|
||||
return 0;
|
||||
}
|
||||
if (Py_REFCNT(v) != 1) {
|
||||
if (!_PyObject_IsUniquelyReferenced(v)) {
|
||||
if (oldsize < newsize) {
|
||||
*pv = _PyBytes_FromSize(newsize, 0);
|
||||
if (*pv) {
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ _PyObject_MakeTpCall(PyThreadState *tstate, PyObject *callable,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *argstuple = _PyTuple_FromArray(args, nargs);
|
||||
PyObject *argstuple = PyTuple_FromArray(args, nargs);
|
||||
if (argstuple == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
4
Objects/clinic/bytearrayobject.c.h
generated
4
Objects/clinic/bytearrayobject.c.h
generated
|
|
@ -599,7 +599,7 @@ PyDoc_STRVAR(bytearray_resize__doc__,
|
|||
"Resize the internal buffer of bytearray to len.\n"
|
||||
"\n"
|
||||
" size\n"
|
||||
" New size to resize to..");
|
||||
" New size to resize to.");
|
||||
|
||||
#define BYTEARRAY_RESIZE_METHODDEF \
|
||||
{"resize", (PyCFunction)bytearray_resize, METH_O, bytearray_resize__doc__},
|
||||
|
|
@ -1796,4 +1796,4 @@ bytearray_sizeof(PyObject *self, PyObject *Py_UNUSED(ignored))
|
|||
{
|
||||
return bytearray_sizeof_impl((PyByteArrayObject *)self);
|
||||
}
|
||||
/*[clinic end generated code: output=be6d28193bc96a2c input=a9049054013a1b77]*/
|
||||
/*[clinic end generated code: output=fdfe41139c91e409 input=a9049054013a1b77]*/
|
||||
|
|
|
|||
106
Objects/clinic/odictobject.c.h
generated
106
Objects/clinic/odictobject.c.h
generated
|
|
@ -6,6 +6,7 @@ preserve
|
|||
# include "pycore_gc.h" // PyGC_Head
|
||||
# include "pycore_runtime.h" // _Py_ID()
|
||||
#endif
|
||||
#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION()
|
||||
#include "pycore_modsupport.h" // _PyArg_UnpackKeywords()
|
||||
|
||||
PyDoc_STRVAR(OrderedDict_fromkeys__doc__,
|
||||
|
|
@ -73,6 +74,53 @@ exit:
|
|||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(OrderedDict___sizeof____doc__,
|
||||
"__sizeof__($self, /)\n"
|
||||
"--\n"
|
||||
"\n");
|
||||
|
||||
#define ORDEREDDICT___SIZEOF___METHODDEF \
|
||||
{"__sizeof__", (PyCFunction)OrderedDict___sizeof__, METH_NOARGS, OrderedDict___sizeof____doc__},
|
||||
|
||||
static Py_ssize_t
|
||||
OrderedDict___sizeof___impl(PyODictObject *self);
|
||||
|
||||
static PyObject *
|
||||
OrderedDict___sizeof__(PyObject *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
Py_ssize_t _return_value;
|
||||
|
||||
Py_BEGIN_CRITICAL_SECTION(self);
|
||||
_return_value = OrderedDict___sizeof___impl((PyODictObject *)self);
|
||||
Py_END_CRITICAL_SECTION();
|
||||
if ((_return_value == -1) && PyErr_Occurred()) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = PyLong_FromSsize_t(_return_value);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(OrderedDict___reduce____doc__,
|
||||
"__reduce__($self, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Return state information for pickling");
|
||||
|
||||
#define ORDEREDDICT___REDUCE___METHODDEF \
|
||||
{"__reduce__", (PyCFunction)OrderedDict___reduce__, METH_NOARGS, OrderedDict___reduce____doc__},
|
||||
|
||||
static PyObject *
|
||||
OrderedDict___reduce___impl(PyODictObject *od);
|
||||
|
||||
static PyObject *
|
||||
OrderedDict___reduce__(PyObject *od, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
return OrderedDict___reduce___impl((PyODictObject *)od);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(OrderedDict_setdefault__doc__,
|
||||
"setdefault($self, /, key, default=None)\n"
|
||||
"--\n"
|
||||
|
|
@ -135,7 +183,9 @@ OrderedDict_setdefault(PyObject *self, PyObject *const *args, Py_ssize_t nargs,
|
|||
}
|
||||
default_value = args[1];
|
||||
skip_optional_pos:
|
||||
Py_BEGIN_CRITICAL_SECTION(self);
|
||||
return_value = OrderedDict_setdefault_impl((PyODictObject *)self, key, default_value);
|
||||
Py_END_CRITICAL_SECTION();
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
|
|
@ -204,7 +254,9 @@ OrderedDict_pop(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObjec
|
|||
}
|
||||
default_value = args[1];
|
||||
skip_optional_pos:
|
||||
Py_BEGIN_CRITICAL_SECTION(self);
|
||||
return_value = OrderedDict_pop_impl((PyODictObject *)self, key, default_value);
|
||||
Py_END_CRITICAL_SECTION();
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
|
|
@ -272,12 +324,62 @@ OrderedDict_popitem(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyO
|
|||
goto exit;
|
||||
}
|
||||
skip_optional_pos:
|
||||
Py_BEGIN_CRITICAL_SECTION(self);
|
||||
return_value = OrderedDict_popitem_impl((PyODictObject *)self, last);
|
||||
Py_END_CRITICAL_SECTION();
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(OrderedDict_clear__doc__,
|
||||
"clear($self, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Remove all items from ordered dict.");
|
||||
|
||||
#define ORDEREDDICT_CLEAR_METHODDEF \
|
||||
{"clear", (PyCFunction)OrderedDict_clear, METH_NOARGS, OrderedDict_clear__doc__},
|
||||
|
||||
static PyObject *
|
||||
OrderedDict_clear_impl(PyODictObject *self);
|
||||
|
||||
static PyObject *
|
||||
OrderedDict_clear(PyObject *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
|
||||
Py_BEGIN_CRITICAL_SECTION(self);
|
||||
return_value = OrderedDict_clear_impl((PyODictObject *)self);
|
||||
Py_END_CRITICAL_SECTION();
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(OrderedDict_copy__doc__,
|
||||
"copy($self, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"A shallow copy of ordered dict.");
|
||||
|
||||
#define ORDEREDDICT_COPY_METHODDEF \
|
||||
{"copy", (PyCFunction)OrderedDict_copy, METH_NOARGS, OrderedDict_copy__doc__},
|
||||
|
||||
static PyObject *
|
||||
OrderedDict_copy_impl(PyObject *od);
|
||||
|
||||
static PyObject *
|
||||
OrderedDict_copy(PyObject *od, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
|
||||
Py_BEGIN_CRITICAL_SECTION(od);
|
||||
return_value = OrderedDict_copy_impl(od);
|
||||
Py_END_CRITICAL_SECTION();
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(OrderedDict_move_to_end__doc__,
|
||||
"move_to_end($self, /, key, last=True)\n"
|
||||
"--\n"
|
||||
|
|
@ -342,9 +444,11 @@ OrderedDict_move_to_end(PyObject *self, PyObject *const *args, Py_ssize_t nargs,
|
|||
goto exit;
|
||||
}
|
||||
skip_optional_pos:
|
||||
Py_BEGIN_CRITICAL_SECTION(self);
|
||||
return_value = OrderedDict_move_to_end_impl((PyODictObject *)self, key, last);
|
||||
Py_END_CRITICAL_SECTION();
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
/*[clinic end generated code: output=7d8206823bb1f419 input=a9049054013a1b77]*/
|
||||
/*[clinic end generated code: output=7bc997ca7900f06f input=a9049054013a1b77]*/
|
||||
|
|
|
|||
25
Objects/clinic/typevarobject.c.h
generated
25
Objects/clinic/typevarobject.c.h
generated
|
|
@ -688,14 +688,14 @@ typealias_reduce(PyObject *self, PyObject *Py_UNUSED(ignored))
|
|||
}
|
||||
|
||||
PyDoc_STRVAR(typealias_new__doc__,
|
||||
"typealias(name, value, *, type_params=<unrepresentable>)\n"
|
||||
"typealias(name, value, *, type_params=<unrepresentable>, qualname=None)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Create a TypeAliasType.");
|
||||
|
||||
static PyObject *
|
||||
typealias_new_impl(PyTypeObject *type, PyObject *name, PyObject *value,
|
||||
PyObject *type_params);
|
||||
PyObject *type_params, PyObject *qualname);
|
||||
|
||||
static PyObject *
|
||||
typealias_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
|
||||
|
|
@ -703,7 +703,7 @@ typealias_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
|
|||
PyObject *return_value = NULL;
|
||||
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
|
||||
|
||||
#define NUM_KEYWORDS 3
|
||||
#define NUM_KEYWORDS 4
|
||||
static struct {
|
||||
PyGC_Head _this_is_not_used;
|
||||
PyObject_VAR_HEAD
|
||||
|
|
@ -712,7 +712,7 @@ typealias_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
|
|||
} _kwtuple = {
|
||||
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
|
||||
.ob_hash = -1,
|
||||
.ob_item = { &_Py_ID(name), &_Py_ID(value), &_Py_ID(type_params), },
|
||||
.ob_item = { &_Py_ID(name), &_Py_ID(value), &_Py_ID(type_params), &_Py_ID(qualname), },
|
||||
};
|
||||
#undef NUM_KEYWORDS
|
||||
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
|
||||
|
|
@ -721,20 +721,21 @@ typealias_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
|
|||
# define KWTUPLE NULL
|
||||
#endif // !Py_BUILD_CORE
|
||||
|
||||
static const char * const _keywords[] = {"name", "value", "type_params", NULL};
|
||||
static const char * const _keywords[] = {"name", "value", "type_params", "qualname", NULL};
|
||||
static _PyArg_Parser _parser = {
|
||||
.keywords = _keywords,
|
||||
.fname = "typealias",
|
||||
.kwtuple = KWTUPLE,
|
||||
};
|
||||
#undef KWTUPLE
|
||||
PyObject *argsbuf[3];
|
||||
PyObject *argsbuf[4];
|
||||
PyObject * const *fastargs;
|
||||
Py_ssize_t nargs = PyTuple_GET_SIZE(args);
|
||||
Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 2;
|
||||
PyObject *name;
|
||||
PyObject *value;
|
||||
PyObject *type_params = NULL;
|
||||
PyObject *qualname = NULL;
|
||||
|
||||
fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser,
|
||||
/*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
|
||||
|
|
@ -750,11 +751,17 @@ typealias_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
|
|||
if (!noptargs) {
|
||||
goto skip_optional_kwonly;
|
||||
}
|
||||
type_params = fastargs[2];
|
||||
if (fastargs[2]) {
|
||||
type_params = fastargs[2];
|
||||
if (!--noptargs) {
|
||||
goto skip_optional_kwonly;
|
||||
}
|
||||
}
|
||||
qualname = fastargs[3];
|
||||
skip_optional_kwonly:
|
||||
return_value = typealias_new_impl(type, name, value, type_params);
|
||||
return_value = typealias_new_impl(type, name, value, type_params, qualname);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
/*[clinic end generated code: output=9dad71445e079303 input=a9049054013a1b77]*/
|
||||
/*[clinic end generated code: output=67ab9a5d1869f2c9 input=a9049054013a1b77]*/
|
||||
|
|
|
|||
|
|
@ -313,7 +313,7 @@ method_vectorcall_VARARGS(
|
|||
if (method_check_args(func, args, nargs, kwnames)) {
|
||||
return NULL;
|
||||
}
|
||||
PyObject *argstuple = _PyTuple_FromArray(args+1, nargs-1);
|
||||
PyObject *argstuple = PyTuple_FromArray(args+1, nargs-1);
|
||||
if (argstuple == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -338,7 +338,7 @@ method_vectorcall_VARARGS_KEYWORDS(
|
|||
if (method_check_args(func, args, nargs, NULL)) {
|
||||
return NULL;
|
||||
}
|
||||
PyObject *argstuple = _PyTuple_FromArray(args+1, nargs-1);
|
||||
PyObject *argstuple = PyTuple_FromArray(args+1, nargs-1);
|
||||
if (argstuple == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1775,6 +1775,14 @@ static inline int
|
|||
insert_combined_dict(PyInterpreterState *interp, PyDictObject *mp,
|
||||
Py_hash_t hash, PyObject *key, PyObject *value)
|
||||
{
|
||||
// gh-140551: If dict was cleared in _Py_dict_lookup,
|
||||
// we have to resize one more time to force general key kind.
|
||||
if (DK_IS_UNICODE(mp->ma_keys) && !PyUnicode_CheckExact(key)) {
|
||||
if (insertion_resize(mp, 0) < 0)
|
||||
return -1;
|
||||
assert(mp->ma_keys->dk_kind == DICT_KEYS_GENERAL);
|
||||
}
|
||||
|
||||
if (mp->ma_keys->dk_usable <= 0) {
|
||||
/* Need to resize. */
|
||||
if (insertion_resize(mp, 1) < 0) {
|
||||
|
|
@ -1871,38 +1879,31 @@ insertdict(PyInterpreterState *interp, PyDictObject *mp,
|
|||
PyObject *key, Py_hash_t hash, PyObject *value)
|
||||
{
|
||||
PyObject *old_value;
|
||||
Py_ssize_t ix;
|
||||
|
||||
ASSERT_DICT_LOCKED(mp);
|
||||
|
||||
if (DK_IS_UNICODE(mp->ma_keys) && !PyUnicode_CheckExact(key)) {
|
||||
if (insertion_resize(mp, 0) < 0)
|
||||
goto Fail;
|
||||
assert(mp->ma_keys->dk_kind == DICT_KEYS_GENERAL);
|
||||
}
|
||||
|
||||
if (_PyDict_HasSplitTable(mp)) {
|
||||
Py_ssize_t ix = insert_split_key(mp->ma_keys, key, hash);
|
||||
if (_PyDict_HasSplitTable(mp) && PyUnicode_CheckExact(key)) {
|
||||
ix = insert_split_key(mp->ma_keys, key, hash);
|
||||
if (ix != DKIX_EMPTY) {
|
||||
insert_split_value(interp, mp, key, value, ix);
|
||||
Py_DECREF(key);
|
||||
Py_DECREF(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* No space in shared keys. Resize and continue below. */
|
||||
if (insertion_resize(mp, 1) < 0) {
|
||||
// No space in shared keys. Go to insert_combined_dict() below.
|
||||
}
|
||||
else {
|
||||
ix = _Py_dict_lookup(mp, key, hash, &old_value);
|
||||
if (ix == DKIX_ERROR)
|
||||
goto Fail;
|
||||
}
|
||||
}
|
||||
|
||||
Py_ssize_t ix = _Py_dict_lookup(mp, key, hash, &old_value);
|
||||
if (ix == DKIX_ERROR)
|
||||
goto Fail;
|
||||
|
||||
if (ix == DKIX_EMPTY) {
|
||||
assert(!_PyDict_HasSplitTable(mp));
|
||||
/* Insert into new slot. */
|
||||
assert(old_value == NULL);
|
||||
// insert_combined_dict() will convert from non DICT_KEYS_GENERAL table
|
||||
// into DICT_KEYS_GENERAL table if key is not Unicode.
|
||||
// We don't convert it before _Py_dict_lookup because non-Unicode key
|
||||
// may change generic table into Unicode table.
|
||||
if (insert_combined_dict(interp, mp, hash, key, value) < 0) {
|
||||
goto Fail;
|
||||
}
|
||||
|
|
@ -2819,8 +2820,8 @@ PyDict_DelItem(PyObject *op, PyObject *key)
|
|||
return _PyDict_DelItem_KnownHash(op, key, hash);
|
||||
}
|
||||
|
||||
static int
|
||||
delitem_knownhash_lock_held(PyObject *op, PyObject *key, Py_hash_t hash)
|
||||
int
|
||||
_PyDict_DelItem_KnownHash_LockHeld(PyObject *op, PyObject *key, Py_hash_t hash)
|
||||
{
|
||||
Py_ssize_t ix;
|
||||
PyDictObject *mp;
|
||||
|
|
@ -2855,7 +2856,7 @@ _PyDict_DelItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash)
|
|||
{
|
||||
int res;
|
||||
Py_BEGIN_CRITICAL_SECTION(op);
|
||||
res = delitem_knownhash_lock_held(op, key, hash);
|
||||
res = _PyDict_DelItem_KnownHash_LockHeld(op, key, hash);
|
||||
Py_END_CRITICAL_SECTION();
|
||||
return res;
|
||||
}
|
||||
|
|
@ -4374,6 +4375,7 @@ dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_valu
|
|||
PyDictObject *mp = (PyDictObject *)d;
|
||||
PyObject *value;
|
||||
Py_hash_t hash;
|
||||
Py_ssize_t ix;
|
||||
PyInterpreterState *interp = _PyInterpreterState_GET();
|
||||
|
||||
ASSERT_DICT_LOCKED(d);
|
||||
|
|
@ -4409,17 +4411,8 @@ dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_valu
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (!PyUnicode_CheckExact(key) && DK_IS_UNICODE(mp->ma_keys)) {
|
||||
if (insertion_resize(mp, 0) < 0) {
|
||||
if (result) {
|
||||
*result = NULL;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (_PyDict_HasSplitTable(mp)) {
|
||||
Py_ssize_t ix = insert_split_key(mp->ma_keys, key, hash);
|
||||
if (_PyDict_HasSplitTable(mp) && PyUnicode_CheckExact(key)) {
|
||||
ix = insert_split_key(mp->ma_keys, key, hash);
|
||||
if (ix != DKIX_EMPTY) {
|
||||
PyObject *value = mp->ma_values->values[ix];
|
||||
int already_present = value != NULL;
|
||||
|
|
@ -4432,27 +4425,22 @@ dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_valu
|
|||
}
|
||||
return already_present;
|
||||
}
|
||||
|
||||
/* No space in shared keys. Resize and continue below. */
|
||||
if (insertion_resize(mp, 1) < 0) {
|
||||
goto error;
|
||||
}
|
||||
// No space in shared keys. Go to insert_combined_dict() below.
|
||||
}
|
||||
|
||||
assert(!_PyDict_HasSplitTable(mp));
|
||||
|
||||
Py_ssize_t ix = _Py_dict_lookup(mp, key, hash, &value);
|
||||
if (ix == DKIX_ERROR) {
|
||||
if (result) {
|
||||
*result = NULL;
|
||||
else {
|
||||
ix = _Py_dict_lookup(mp, key, hash, &value);
|
||||
if (ix == DKIX_ERROR) {
|
||||
if (result) {
|
||||
*result = NULL;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ix == DKIX_EMPTY) {
|
||||
assert(!_PyDict_HasSplitTable(mp));
|
||||
value = default_value;
|
||||
|
||||
// See comment to this function in insertdict.
|
||||
if (insert_combined_dict(interp, mp, hash, Py_NewRef(key), Py_NewRef(value)) < 0) {
|
||||
Py_DECREF(key);
|
||||
Py_DECREF(value);
|
||||
|
|
@ -4477,12 +4465,6 @@ dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_valu
|
|||
*result = incref_result ? Py_NewRef(value) : value;
|
||||
}
|
||||
return 1;
|
||||
|
||||
error:
|
||||
if (result) {
|
||||
*result = NULL;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
@ -4703,9 +4685,11 @@ dict_tp_clear(PyObject *op)
|
|||
|
||||
static PyObject *dictiter_new(PyDictObject *, PyTypeObject *);
|
||||
|
||||
static Py_ssize_t
|
||||
sizeof_lock_held(PyDictObject *mp)
|
||||
Py_ssize_t
|
||||
_PyDict_SizeOf_LockHeld(PyDictObject *mp)
|
||||
{
|
||||
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(mp);
|
||||
|
||||
size_t res = _PyObject_SIZE(Py_TYPE(mp));
|
||||
if (_PyDict_HasSplitTable(mp)) {
|
||||
res += shared_keys_usable_size(mp->ma_keys) * sizeof(PyObject*);
|
||||
|
|
@ -4732,7 +4716,7 @@ _PyDict_SizeOf(PyDictObject *mp)
|
|||
{
|
||||
Py_ssize_t res;
|
||||
Py_BEGIN_CRITICAL_SECTION(mp);
|
||||
res = sizeof_lock_held(mp);
|
||||
res = _PyDict_SizeOf_LockHeld(mp);
|
||||
Py_END_CRITICAL_SECTION();
|
||||
|
||||
return res;
|
||||
|
|
@ -5673,22 +5657,10 @@ dictiter_iternext_threadsafe(PyDictObject *d, PyObject *self,
|
|||
|
||||
#endif
|
||||
|
||||
static bool
|
||||
has_unique_reference(PyObject *op)
|
||||
{
|
||||
#ifdef Py_GIL_DISABLED
|
||||
return (_Py_IsOwnedByCurrentThread(op) &&
|
||||
op->ob_ref_local == 1 &&
|
||||
_Py_atomic_load_ssize_relaxed(&op->ob_ref_shared) == 0);
|
||||
#else
|
||||
return Py_REFCNT(op) == 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool
|
||||
acquire_iter_result(PyObject *result)
|
||||
{
|
||||
if (has_unique_reference(result)) {
|
||||
if (_PyObject_IsUniquelyReferenced(result)) {
|
||||
Py_INCREF(result);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -5725,8 +5697,11 @@ dictiter_iternextitem(PyObject *self)
|
|||
}
|
||||
else {
|
||||
result = PyTuple_New(2);
|
||||
if (result == NULL)
|
||||
if (result == NULL) {
|
||||
Py_DECREF(key);
|
||||
Py_DECREF(value);
|
||||
return NULL;
|
||||
}
|
||||
PyTuple_SET_ITEM(result, 0, key);
|
||||
PyTuple_SET_ITEM(result, 1, value);
|
||||
}
|
||||
|
|
@ -5834,7 +5809,7 @@ dictreviter_iter_lock_held(PyDictObject *d, PyObject *self)
|
|||
}
|
||||
else if (Py_IS_TYPE(di, &PyDictRevIterItem_Type)) {
|
||||
result = di->di_result;
|
||||
if (Py_REFCNT(result) == 1) {
|
||||
if (_PyObject_IsUniquelyReferenced(result)) {
|
||||
PyObject *oldkey = PyTuple_GET_ITEM(result, 0);
|
||||
PyObject *oldvalue = PyTuple_GET_ITEM(result, 1);
|
||||
PyTuple_SET_ITEM(result, 0, Py_NewRef(key));
|
||||
|
|
@ -6917,7 +6892,7 @@ _PyDict_SetItem_LockHeld(PyDictObject *dict, PyObject *name, PyObject *value)
|
|||
dict_unhashable_type(name);
|
||||
return -1;
|
||||
}
|
||||
return delitem_knownhash_lock_held((PyObject *)dict, name, hash);
|
||||
return _PyDict_DelItem_KnownHash_LockHeld((PyObject *)dict, name, hash);
|
||||
} else {
|
||||
return setitem_lock_held(dict, name, value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
#include "pycore_modsupport.h" // _PyArg_NoKeywords()
|
||||
#include "pycore_object.h"
|
||||
#include "pycore_pyerrors.h" // struct _PyErr_SetRaisedException
|
||||
#include "pycore_tuple.h" // _PyTuple_FromArray()
|
||||
|
||||
#include "osdefs.h" // SEP
|
||||
#include "clinic/exceptions.c.h"
|
||||
|
|
@ -119,7 +118,7 @@ BaseException_vectorcall(PyObject *type_obj, PyObject * const*args,
|
|||
self->context = NULL;
|
||||
self->suppress_context = 0;
|
||||
|
||||
self->args = _PyTuple_FromArray(args, PyVectorcall_NARGS(nargsf));
|
||||
self->args = PyTuple_FromArray(args, PyVectorcall_NARGS(nargsf));
|
||||
if (!self->args) {
|
||||
Py_DECREF(self);
|
||||
return NULL;
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ handle_func_event(PyFunction_WatchEvent event, PyFunctionObject *func,
|
|||
case PyFunction_EVENT_MODIFY_CODE:
|
||||
case PyFunction_EVENT_MODIFY_DEFAULTS:
|
||||
case PyFunction_EVENT_MODIFY_KWDEFAULTS:
|
||||
case PyFunction_EVENT_MODIFY_QUALNAME:
|
||||
RARE_EVENT_INTERP_INC(interp, func_modification);
|
||||
break;
|
||||
default:
|
||||
|
|
@ -747,6 +748,7 @@ func_set_qualname(PyObject *self, PyObject *value, void *Py_UNUSED(ignored))
|
|||
"__qualname__ must be set to a string object");
|
||||
return -1;
|
||||
}
|
||||
handle_func_event(PyFunction_EVENT_MODIFY_QUALNAME, (PyFunctionObject *) op, value);
|
||||
Py_XSETREF(op->func_qualname, Py_NewRef(value));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -407,11 +407,12 @@ gen_close(PyObject *self, PyObject *args)
|
|||
}
|
||||
_PyInterpreterFrame *frame = &gen->gi_iframe;
|
||||
if (is_resume(frame->instr_ptr)) {
|
||||
bool no_unwind_tools = _PyEval_NoToolsForUnwind(_PyThreadState_GET());
|
||||
/* We can safely ignore the outermost try block
|
||||
* as it is automatically generated to handle
|
||||
* StopIteration. */
|
||||
int oparg = frame->instr_ptr->op.arg;
|
||||
if (oparg & RESUME_OPARG_DEPTH1_MASK) {
|
||||
if (oparg & RESUME_OPARG_DEPTH1_MASK && no_unwind_tools) {
|
||||
// RESUME after YIELD_VALUE and exception depth is 1
|
||||
assert((oparg & RESUME_OPARG_LOCATION_MASK) != RESUME_AT_FUNC_START);
|
||||
gen->gi_frame_state = FRAME_COMPLETED;
|
||||
|
|
@ -932,6 +933,7 @@ make_gen(PyTypeObject *type, PyFunctionObject *func)
|
|||
gen->gi_weakreflist = NULL;
|
||||
gen->gi_exc_state.exc_value = NULL;
|
||||
gen->gi_exc_state.previous_item = NULL;
|
||||
gen->gi_iframe.f_executable = PyStackRef_None;
|
||||
assert(func->func_name != NULL);
|
||||
gen->gi_name = Py_NewRef(func->func_name);
|
||||
assert(func->func_qualname != NULL);
|
||||
|
|
|
|||
|
|
@ -6,16 +6,16 @@
|
|||
#include "pycore_critical_section.h" // _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED()
|
||||
#include "pycore_dict.h" // _PyDictViewObject
|
||||
#include "pycore_freelist.h" // _Py_FREELIST_FREE(), _Py_FREELIST_POP()
|
||||
#include "pycore_pyatomic_ft_wrappers.h"
|
||||
#include "pycore_interp.h" // PyInterpreterState.list
|
||||
#include "pycore_list.h" // struct _Py_list_freelist, _PyListIterObject
|
||||
#include "pycore_long.h" // _PyLong_DigitCount
|
||||
#include "pycore_modsupport.h" // _PyArg_NoKwnames()
|
||||
#include "pycore_object.h" // _PyObject_GC_TRACK(), _PyDebugAllocatorStats()
|
||||
#include "pycore_stackref.h" // _Py_TryIncrefCompareStackRef()
|
||||
#include "pycore_tuple.h" // _PyTuple_FromArray()
|
||||
#include "pycore_typeobject.h" // _Py_TYPE_VERSION_LIST
|
||||
#include "pycore_pyatomic_ft_wrappers.h"
|
||||
#include "pycore_setobject.h" // _PySet_NextEntry()
|
||||
#include "pycore_stackref.h" // _Py_TryIncrefCompareStackRef()
|
||||
#include "pycore_tuple.h" // _PyTuple_FromArraySteal()
|
||||
#include "pycore_typeobject.h" // _Py_TYPE_VERSION_LIST
|
||||
#include <stddef.h>
|
||||
|
||||
/*[clinic input]
|
||||
|
|
@ -1382,9 +1382,9 @@ list_extend_dictitems(PyListObject *self, PyDictObject *dict)
|
|||
PyObject **dest = self->ob_item + m;
|
||||
Py_ssize_t pos = 0;
|
||||
Py_ssize_t i = 0;
|
||||
PyObject *key, *value;
|
||||
while (_PyDict_Next((PyObject *)dict, &pos, &key, &value, NULL)) {
|
||||
PyObject *item = PyTuple_Pack(2, key, value);
|
||||
PyObject *key_value[2];
|
||||
while (_PyDict_Next((PyObject *)dict, &pos, &key_value[0], &key_value[1], NULL)) {
|
||||
PyObject *item = PyTuple_FromArray(key_value, 2);
|
||||
if (item == NULL) {
|
||||
Py_SET_SIZE(self, m + i);
|
||||
return -1;
|
||||
|
|
@ -3221,7 +3221,7 @@ PyList_AsTuple(PyObject *v)
|
|||
PyObject *ret;
|
||||
PyListObject *self = (PyListObject *)v;
|
||||
Py_BEGIN_CRITICAL_SECTION(self);
|
||||
ret = _PyTuple_FromArray(self->ob_item, Py_SIZE(v));
|
||||
ret = PyTuple_FromArray(self->ob_item, Py_SIZE(v));
|
||||
Py_END_CRITICAL_SECTION();
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -352,7 +352,7 @@ _PyLong_Negate(PyLongObject **x_p)
|
|||
PyLongObject *x;
|
||||
|
||||
x = (PyLongObject *)*x_p;
|
||||
if (Py_REFCNT(x) == 1) {
|
||||
if (_PyObject_IsUniquelyReferenced((PyObject *)x)) {
|
||||
_PyLong_FlipSign(x);
|
||||
return;
|
||||
}
|
||||
|
|
@ -5849,7 +5849,7 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg)
|
|||
assert(size_a >= 0);
|
||||
_PyLong_SetSignAndDigitCount(c, 1, size_a);
|
||||
}
|
||||
else if (Py_REFCNT(a) == 1) {
|
||||
else if (_PyObject_IsUniquelyReferenced((PyObject *)a)) {
|
||||
c = (PyLongObject*)Py_NewRef(a);
|
||||
}
|
||||
else {
|
||||
|
|
@ -5863,7 +5863,8 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg)
|
|||
assert(size_a >= 0);
|
||||
_PyLong_SetSignAndDigitCount(d, 1, size_a);
|
||||
}
|
||||
else if (Py_REFCNT(b) == 1 && size_a <= alloc_b) {
|
||||
else if (_PyObject_IsUniquelyReferenced((PyObject *)b)
|
||||
&& size_a <= alloc_b) {
|
||||
d = (PyLongObject*)Py_NewRef(b);
|
||||
assert(size_a >= 0);
|
||||
_PyLong_SetSignAndDigitCount(d, 1, size_a);
|
||||
|
|
|
|||
|
|
@ -536,6 +536,7 @@ struct _odictnode {
|
|||
static Py_ssize_t
|
||||
_odict_get_index_raw(PyODictObject *od, PyObject *key, Py_hash_t hash)
|
||||
{
|
||||
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od);
|
||||
PyObject *value = NULL;
|
||||
PyDictKeysObject *keys = ((PyDictObject *)od)->ma_keys;
|
||||
Py_ssize_t ix;
|
||||
|
|
@ -560,6 +561,7 @@ _odict_get_index_raw(PyODictObject *od, PyObject *key, Py_hash_t hash)
|
|||
static int
|
||||
_odict_resize(PyODictObject *od)
|
||||
{
|
||||
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od);
|
||||
Py_ssize_t size, i;
|
||||
_ODictNode **fast_nodes, *node;
|
||||
|
||||
|
|
@ -596,6 +598,7 @@ _odict_resize(PyODictObject *od)
|
|||
static Py_ssize_t
|
||||
_odict_get_index(PyODictObject *od, PyObject *key, Py_hash_t hash)
|
||||
{
|
||||
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od);
|
||||
PyDictKeysObject *keys;
|
||||
|
||||
assert(key != NULL);
|
||||
|
|
@ -616,6 +619,7 @@ _odict_get_index(PyODictObject *od, PyObject *key, Py_hash_t hash)
|
|||
static _ODictNode *
|
||||
_odict_find_node_hash(PyODictObject *od, PyObject *key, Py_hash_t hash)
|
||||
{
|
||||
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od);
|
||||
Py_ssize_t index;
|
||||
|
||||
if (_odict_EMPTY(od))
|
||||
|
|
@ -630,6 +634,7 @@ _odict_find_node_hash(PyODictObject *od, PyObject *key, Py_hash_t hash)
|
|||
static _ODictNode *
|
||||
_odict_find_node(PyODictObject *od, PyObject *key)
|
||||
{
|
||||
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od);
|
||||
Py_ssize_t index;
|
||||
Py_hash_t hash;
|
||||
|
||||
|
|
@ -648,6 +653,7 @@ _odict_find_node(PyODictObject *od, PyObject *key)
|
|||
static void
|
||||
_odict_add_head(PyODictObject *od, _ODictNode *node)
|
||||
{
|
||||
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od);
|
||||
_odictnode_PREV(node) = NULL;
|
||||
_odictnode_NEXT(node) = _odict_FIRST(od);
|
||||
if (_odict_FIRST(od) == NULL)
|
||||
|
|
@ -661,6 +667,7 @@ _odict_add_head(PyODictObject *od, _ODictNode *node)
|
|||
static void
|
||||
_odict_add_tail(PyODictObject *od, _ODictNode *node)
|
||||
{
|
||||
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od);
|
||||
_odictnode_PREV(node) = _odict_LAST(od);
|
||||
_odictnode_NEXT(node) = NULL;
|
||||
if (_odict_LAST(od) == NULL)
|
||||
|
|
@ -675,6 +682,7 @@ _odict_add_tail(PyODictObject *od, _ODictNode *node)
|
|||
static int
|
||||
_odict_add_new_node(PyODictObject *od, PyObject *key, Py_hash_t hash)
|
||||
{
|
||||
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od);
|
||||
Py_ssize_t i;
|
||||
_ODictNode *node;
|
||||
|
||||
|
|
@ -719,6 +727,7 @@ _odict_add_new_node(PyODictObject *od, PyObject *key, Py_hash_t hash)
|
|||
static void
|
||||
_odict_remove_node(PyODictObject *od, _ODictNode *node)
|
||||
{
|
||||
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od);
|
||||
if (_odict_FIRST(od) == node)
|
||||
_odict_FIRST(od) = _odictnode_NEXT(node);
|
||||
else if (_odictnode_PREV(node) != NULL)
|
||||
|
|
@ -754,6 +763,7 @@ static int
|
|||
_odict_clear_node(PyODictObject *od, _ODictNode *node, PyObject *key,
|
||||
Py_hash_t hash)
|
||||
{
|
||||
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od);
|
||||
Py_ssize_t i;
|
||||
|
||||
assert(key != NULL);
|
||||
|
|
@ -952,31 +962,34 @@ OrderedDict_fromkeys_impl(PyTypeObject *type, PyObject *seq, PyObject *value)
|
|||
return _PyDict_FromKeys((PyObject *)type, seq, value);
|
||||
}
|
||||
|
||||
/* __sizeof__() */
|
||||
/*[clinic input]
|
||||
@critical_section
|
||||
OrderedDict.__sizeof__ -> Py_ssize_t
|
||||
[clinic start generated code]*/
|
||||
|
||||
/* OrderedDict.__sizeof__() does not have a docstring. */
|
||||
PyDoc_STRVAR(odict_sizeof__doc__, "");
|
||||
|
||||
static PyObject *
|
||||
odict_sizeof(PyObject *op, PyObject *Py_UNUSED(ignored))
|
||||
static Py_ssize_t
|
||||
OrderedDict___sizeof___impl(PyODictObject *self)
|
||||
/*[clinic end generated code: output=1a8560db8cf83ac5 input=655e989ae24daa6a]*/
|
||||
{
|
||||
PyODictObject *od = _PyODictObject_CAST(op);
|
||||
Py_ssize_t res = _PyDict_SizeOf((PyDictObject *)od);
|
||||
res += sizeof(_ODictNode *) * od->od_fast_nodes_size; /* od_fast_nodes */
|
||||
if (!_odict_EMPTY(od)) {
|
||||
res += sizeof(_ODictNode) * PyODict_SIZE(od); /* linked-list */
|
||||
Py_ssize_t res = _PyDict_SizeOf_LockHeld((PyDictObject *)self);
|
||||
res += sizeof(_ODictNode *) * self->od_fast_nodes_size; /* od_fast_nodes */
|
||||
if (!_odict_EMPTY(self)) {
|
||||
res += sizeof(_ODictNode) * PyODict_SIZE(self); /* linked-list */
|
||||
}
|
||||
return PyLong_FromSsize_t(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* __reduce__() */
|
||||
/*[clinic input]
|
||||
OrderedDict.__reduce__
|
||||
self as od: self(type="PyODictObject *")
|
||||
|
||||
PyDoc_STRVAR(odict_reduce__doc__, "Return state information for pickling");
|
||||
Return state information for pickling
|
||||
[clinic start generated code]*/
|
||||
|
||||
static PyObject *
|
||||
odict_reduce(PyObject *op, PyObject *Py_UNUSED(ignored))
|
||||
OrderedDict___reduce___impl(PyODictObject *od)
|
||||
/*[clinic end generated code: output=71eeb81f760a6a8e input=b0467c7ec400fe5e]*/
|
||||
{
|
||||
register PyODictObject *od = _PyODictObject_CAST(op);
|
||||
PyObject *state, *result = NULL;
|
||||
PyObject *items_iter, *items, *args = NULL;
|
||||
|
||||
|
|
@ -1011,8 +1024,10 @@ odict_reduce(PyObject *op, PyObject *Py_UNUSED(ignored))
|
|||
|
||||
/* setdefault(): Skips __missing__() calls. */
|
||||
|
||||
static int PyODict_SetItem_LockHeld(PyObject *self, PyObject *key, PyObject *value);
|
||||
|
||||
/*[clinic input]
|
||||
@critical_section
|
||||
OrderedDict.setdefault
|
||||
|
||||
key: object
|
||||
|
|
@ -1026,7 +1041,7 @@ Return the value for key if key is in the dictionary, else default.
|
|||
static PyObject *
|
||||
OrderedDict_setdefault_impl(PyODictObject *self, PyObject *key,
|
||||
PyObject *default_value)
|
||||
/*[clinic end generated code: output=97537cb7c28464b6 input=38e098381c1efbc6]*/
|
||||
/*[clinic end generated code: output=97537cb7c28464b6 input=d7b93e92734f99b5]*/
|
||||
{
|
||||
PyObject *result = NULL;
|
||||
|
||||
|
|
@ -1036,7 +1051,7 @@ OrderedDict_setdefault_impl(PyODictObject *self, PyObject *key,
|
|||
if (PyErr_Occurred())
|
||||
return NULL;
|
||||
assert(_odict_find_node(self, key) == NULL);
|
||||
if (PyODict_SetItem((PyObject *)self, key, default_value) >= 0) {
|
||||
if (PyODict_SetItem_LockHeld((PyObject *)self, key, default_value) >= 0) {
|
||||
result = Py_NewRef(default_value);
|
||||
}
|
||||
}
|
||||
|
|
@ -1066,10 +1081,9 @@ static PyObject *
|
|||
_odict_popkey_hash(PyObject *od, PyObject *key, PyObject *failobj,
|
||||
Py_hash_t hash)
|
||||
{
|
||||
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od);
|
||||
|
||||
PyObject *value = NULL;
|
||||
|
||||
Py_BEGIN_CRITICAL_SECTION(od);
|
||||
|
||||
_ODictNode *node = _odict_find_node_hash(_PyODictObject_CAST(od), key, hash);
|
||||
if (node != NULL) {
|
||||
/* Pop the node first to avoid a possible dict resize (due to
|
||||
|
|
@ -1094,7 +1108,6 @@ _odict_popkey_hash(PyObject *od, PyObject *key, PyObject *failobj,
|
|||
PyErr_SetObject(PyExc_KeyError, key);
|
||||
}
|
||||
}
|
||||
Py_END_CRITICAL_SECTION();
|
||||
done:
|
||||
|
||||
return value;
|
||||
|
|
@ -1102,6 +1115,7 @@ _odict_popkey_hash(PyObject *od, PyObject *key, PyObject *failobj,
|
|||
|
||||
/* Skips __missing__() calls. */
|
||||
/*[clinic input]
|
||||
@critical_section
|
||||
@permit_long_summary
|
||||
OrderedDict.pop
|
||||
|
||||
|
|
@ -1117,7 +1131,7 @@ raise a KeyError.
|
|||
static PyObject *
|
||||
OrderedDict_pop_impl(PyODictObject *self, PyObject *key,
|
||||
PyObject *default_value)
|
||||
/*[clinic end generated code: output=7a6447d104e7494b input=eebd40ac51666d33]*/
|
||||
/*[clinic end generated code: output=7a6447d104e7494b input=0742e3c9bf076a72]*/
|
||||
{
|
||||
Py_hash_t hash = PyObject_Hash(key);
|
||||
if (hash == -1)
|
||||
|
|
@ -1129,6 +1143,7 @@ OrderedDict_pop_impl(PyODictObject *self, PyObject *key,
|
|||
/* popitem() */
|
||||
|
||||
/*[clinic input]
|
||||
@critical_section
|
||||
OrderedDict.popitem
|
||||
|
||||
last: bool = True
|
||||
|
|
@ -1140,7 +1155,7 @@ Pairs are returned in LIFO order if last is true or FIFO order if false.
|
|||
|
||||
static PyObject *
|
||||
OrderedDict_popitem_impl(PyODictObject *self, int last)
|
||||
/*[clinic end generated code: output=98e7d986690d49eb input=d992ac5ee8305e1a]*/
|
||||
/*[clinic end generated code: output=98e7d986690d49eb input=8aafc7433e0a40e7]*/
|
||||
{
|
||||
PyObject *key, *value, *item = NULL;
|
||||
_ODictNode *node;
|
||||
|
|
@ -1169,6 +1184,9 @@ OrderedDict_popitem_impl(PyODictObject *self, int last)
|
|||
PyDoc_STRVAR(odict_keys__doc__, "");
|
||||
|
||||
static PyObject * odictkeys_new(PyObject *od, PyObject *Py_UNUSED(ignored)); /* forward */
|
||||
static int
|
||||
_PyODict_SetItem_KnownHash_LockHeld(PyObject *od, PyObject *key, PyObject *value,
|
||||
Py_hash_t hash); /* forward */
|
||||
|
||||
/* values() */
|
||||
|
||||
|
|
@ -1194,32 +1212,36 @@ static PyObject * mutablemapping_update(PyObject *, PyObject *, PyObject *);
|
|||
|
||||
#define odict_update mutablemapping_update
|
||||
|
||||
/* clear() */
|
||||
/*[clinic input]
|
||||
@critical_section
|
||||
OrderedDict.clear
|
||||
|
||||
PyDoc_STRVAR(odict_clear__doc__,
|
||||
"od.clear() -> None. Remove all items from od.");
|
||||
Remove all items from ordered dict.
|
||||
[clinic start generated code]*/
|
||||
|
||||
static PyObject *
|
||||
odict_clear(PyObject *op, PyObject *Py_UNUSED(ignored))
|
||||
OrderedDict_clear_impl(PyODictObject *self)
|
||||
/*[clinic end generated code: output=a1a76d1322f556c5 input=08b12322e74c535c]*/
|
||||
{
|
||||
register PyODictObject *od = _PyODictObject_CAST(op);
|
||||
PyDict_Clear(op);
|
||||
_odict_clear_nodes(od);
|
||||
_PyDict_Clear_LockHeld((PyObject *)self);
|
||||
_odict_clear_nodes(self);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
/* copy() */
|
||||
|
||||
/* forward */
|
||||
static int _PyODict_SetItem_KnownHash(PyObject *, PyObject *, PyObject *,
|
||||
Py_hash_t);
|
||||
/*[clinic input]
|
||||
@critical_section
|
||||
OrderedDict.copy
|
||||
self as od: self
|
||||
|
||||
PyDoc_STRVAR(odict_copy__doc__, "od.copy() -> a shallow copy of od");
|
||||
A shallow copy of ordered dict.
|
||||
[clinic start generated code]*/
|
||||
|
||||
static PyObject *
|
||||
odict_copy(PyObject *op, PyObject *Py_UNUSED(ignored))
|
||||
OrderedDict_copy_impl(PyObject *od)
|
||||
/*[clinic end generated code: output=9cdbe7394aecc576 input=e329951ae617ed48]*/
|
||||
{
|
||||
register PyODictObject *od = _PyODictObject_CAST(op);
|
||||
_ODictNode *node;
|
||||
PyObject *od_copy;
|
||||
|
||||
|
|
@ -1239,8 +1261,8 @@ odict_copy(PyObject *op, PyObject *Py_UNUSED(ignored))
|
|||
PyErr_SetObject(PyExc_KeyError, key);
|
||||
goto fail;
|
||||
}
|
||||
if (_PyODict_SetItem_KnownHash((PyObject *)od_copy, key, value,
|
||||
_odictnode_HASH(node)) != 0)
|
||||
if (_PyODict_SetItem_KnownHash_LockHeld((PyObject *)od_copy, key, value,
|
||||
_odictnode_HASH(node)) != 0)
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
|
@ -1288,6 +1310,7 @@ odict_reversed(PyObject *op, PyObject *Py_UNUSED(ignored))
|
|||
/* move_to_end() */
|
||||
|
||||
/*[clinic input]
|
||||
@critical_section
|
||||
OrderedDict.move_to_end
|
||||
|
||||
key: object
|
||||
|
|
@ -1300,7 +1323,7 @@ Raise KeyError if the element does not exist.
|
|||
|
||||
static PyObject *
|
||||
OrderedDict_move_to_end_impl(PyODictObject *self, PyObject *key, int last)
|
||||
/*[clinic end generated code: output=fafa4c5cc9b92f20 input=d6ceff7132a2fcd7]*/
|
||||
/*[clinic end generated code: output=fafa4c5cc9b92f20 input=09f8bc7053c0f6d4]*/
|
||||
{
|
||||
_ODictNode *node;
|
||||
|
||||
|
|
@ -1341,10 +1364,8 @@ static PyMethodDef odict_methods[] = {
|
|||
|
||||
/* overridden dict methods */
|
||||
ORDEREDDICT_FROMKEYS_METHODDEF
|
||||
{"__sizeof__", odict_sizeof, METH_NOARGS,
|
||||
odict_sizeof__doc__},
|
||||
{"__reduce__", odict_reduce, METH_NOARGS,
|
||||
odict_reduce__doc__},
|
||||
ORDEREDDICT___SIZEOF___METHODDEF
|
||||
ORDEREDDICT___REDUCE___METHODDEF
|
||||
ORDEREDDICT_SETDEFAULT_METHODDEF
|
||||
ORDEREDDICT_POP_METHODDEF
|
||||
ORDEREDDICT_POPITEM_METHODDEF
|
||||
|
|
@ -1356,11 +1377,8 @@ static PyMethodDef odict_methods[] = {
|
|||
odict_items__doc__},
|
||||
{"update", _PyCFunction_CAST(odict_update), METH_VARARGS | METH_KEYWORDS,
|
||||
odict_update__doc__},
|
||||
{"clear", odict_clear, METH_NOARGS,
|
||||
odict_clear__doc__},
|
||||
{"copy", odict_copy, METH_NOARGS,
|
||||
odict_copy__doc__},
|
||||
|
||||
ORDEREDDICT_CLEAR_METHODDEF
|
||||
ORDEREDDICT_COPY_METHODDEF
|
||||
/* new methods */
|
||||
{"__reversed__", odict_reversed, METH_NOARGS,
|
||||
odict_reversed__doc__},
|
||||
|
|
@ -1459,7 +1477,8 @@ odict_tp_clear(PyObject *op)
|
|||
{
|
||||
PyODictObject *od = _PyODictObject_CAST(op);
|
||||
Py_CLEAR(od->od_inst_dict);
|
||||
PyDict_Clear((PyObject *)od);
|
||||
// cannot use lock held variant as critical section is not held here
|
||||
PyDict_Clear(op);
|
||||
_odict_clear_nodes(od);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1467,7 +1486,7 @@ odict_tp_clear(PyObject *op)
|
|||
/* tp_richcompare */
|
||||
|
||||
static PyObject *
|
||||
odict_richcompare(PyObject *v, PyObject *w, int op)
|
||||
odict_richcompare_lock_held(PyObject *v, PyObject *w, int op)
|
||||
{
|
||||
if (!PyODict_Check(v) || !PyDict_Check(w)) {
|
||||
Py_RETURN_NOTIMPLEMENTED;
|
||||
|
|
@ -1500,6 +1519,16 @@ odict_richcompare(PyObject *v, PyObject *w, int op)
|
|||
}
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
odict_richcompare(PyObject *v, PyObject *w, int op)
|
||||
{
|
||||
PyObject *res;
|
||||
Py_BEGIN_CRITICAL_SECTION2(v, w);
|
||||
res = odict_richcompare_lock_held(v, w, op);
|
||||
Py_END_CRITICAL_SECTION2();
|
||||
return res;
|
||||
}
|
||||
|
||||
/* tp_iter */
|
||||
|
||||
static PyObject *
|
||||
|
|
@ -1590,10 +1619,11 @@ PyODict_New(void)
|
|||
}
|
||||
|
||||
static int
|
||||
_PyODict_SetItem_KnownHash(PyObject *od, PyObject *key, PyObject *value,
|
||||
Py_hash_t hash)
|
||||
_PyODict_SetItem_KnownHash_LockHeld(PyObject *od, PyObject *key, PyObject *value,
|
||||
Py_hash_t hash)
|
||||
{
|
||||
int res = _PyDict_SetItem_KnownHash(od, key, value, hash);
|
||||
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od);
|
||||
int res = _PyDict_SetItem_KnownHash_LockHeld((PyDictObject *)od, key, value, hash);
|
||||
if (res == 0) {
|
||||
res = _odict_add_new_node(_PyODictObject_CAST(od), key, hash);
|
||||
if (res < 0) {
|
||||
|
|
@ -1606,18 +1636,32 @@ _PyODict_SetItem_KnownHash(PyObject *od, PyObject *key, PyObject *value,
|
|||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
PyODict_SetItem(PyObject *od, PyObject *key, PyObject *value)
|
||||
|
||||
static int
|
||||
PyODict_SetItem_LockHeld(PyObject *od, PyObject *key, PyObject *value)
|
||||
{
|
||||
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od);
|
||||
Py_hash_t hash = PyObject_Hash(key);
|
||||
if (hash == -1)
|
||||
if (hash == -1) {
|
||||
return -1;
|
||||
return _PyODict_SetItem_KnownHash(od, key, value, hash);
|
||||
}
|
||||
return _PyODict_SetItem_KnownHash_LockHeld(od, key, value, hash);
|
||||
}
|
||||
|
||||
int
|
||||
PyODict_DelItem(PyObject *od, PyObject *key)
|
||||
PyODict_SetItem(PyObject *od, PyObject *key, PyObject *value)
|
||||
{
|
||||
int res;
|
||||
Py_BEGIN_CRITICAL_SECTION(od);
|
||||
res = PyODict_SetItem_LockHeld(od, key, value);
|
||||
Py_END_CRITICAL_SECTION();
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
PyODict_DelItem_LockHeld(PyObject *od, PyObject *key)
|
||||
{
|
||||
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od);
|
||||
int res;
|
||||
Py_hash_t hash = PyObject_Hash(key);
|
||||
if (hash == -1)
|
||||
|
|
@ -1625,9 +1669,18 @@ PyODict_DelItem(PyObject *od, PyObject *key)
|
|||
res = _odict_clear_node(_PyODictObject_CAST(od), NULL, key, hash);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
return _PyDict_DelItem_KnownHash(od, key, hash);
|
||||
return _PyDict_DelItem_KnownHash_LockHeld(od, key, hash);
|
||||
}
|
||||
|
||||
int
|
||||
PyODict_DelItem(PyObject *od, PyObject *key)
|
||||
{
|
||||
int res;
|
||||
Py_BEGIN_CRITICAL_SECTION(od);
|
||||
res = PyODict_DelItem_LockHeld(od, key);
|
||||
Py_END_CRITICAL_SECTION();
|
||||
return res;
|
||||
}
|
||||
|
||||
/* -------------------------------------------
|
||||
* The OrderedDict views (keys/values/items)
|
||||
|
|
@ -1669,14 +1722,14 @@ odictiter_traverse(PyObject *op, visitproc visit, void *arg)
|
|||
/* In order to protect against modifications during iteration, we track
|
||||
* the current key instead of the current node. */
|
||||
static PyObject *
|
||||
odictiter_nextkey(odictiterobject *di)
|
||||
odictiter_nextkey_lock_held(odictiterobject *di)
|
||||
{
|
||||
assert(di->di_odict != NULL);
|
||||
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(di->di_odict);
|
||||
PyObject *key = NULL;
|
||||
_ODictNode *node;
|
||||
int reversed = di->kind & _odict_ITER_REVERSED;
|
||||
|
||||
if (di->di_odict == NULL)
|
||||
return NULL;
|
||||
if (di->di_current == NULL)
|
||||
goto done; /* We're already done. */
|
||||
|
||||
|
|
@ -1721,8 +1774,23 @@ odictiter_nextkey(odictiterobject *di)
|
|||
return key;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
odictiter_iternext(PyObject *op)
|
||||
odictiter_nextkey(odictiterobject *di)
|
||||
{
|
||||
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(di);
|
||||
if (di->di_odict == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
PyObject *res;
|
||||
Py_BEGIN_CRITICAL_SECTION(di->di_odict);
|
||||
res = odictiter_nextkey_lock_held(di);
|
||||
Py_END_CRITICAL_SECTION();
|
||||
return res;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
odictiter_iternext_lock_held(PyObject *op)
|
||||
{
|
||||
odictiterobject *di = (odictiterobject*)op;
|
||||
PyObject *result, *value;
|
||||
|
|
@ -1736,14 +1804,12 @@ odictiter_iternext(PyObject *op)
|
|||
return key;
|
||||
}
|
||||
|
||||
value = PyODict_GetItem((PyObject *)di->di_odict, key); /* borrowed */
|
||||
if (value == NULL) {
|
||||
if (PyDict_GetItemRef((PyObject *)di->di_odict, key, &value) != 1) {
|
||||
if (!PyErr_Occurred())
|
||||
PyErr_SetObject(PyExc_KeyError, key);
|
||||
Py_DECREF(key);
|
||||
goto done;
|
||||
}
|
||||
Py_INCREF(value);
|
||||
|
||||
/* Handle the values case. */
|
||||
if (!(di->kind & _odict_ITER_KEYS)) {
|
||||
|
|
@ -1754,7 +1820,7 @@ odictiter_iternext(PyObject *op)
|
|||
/* Handle the items case. */
|
||||
result = di->di_result;
|
||||
|
||||
if (Py_REFCNT(result) == 1) {
|
||||
if (_PyObject_IsUniquelyReferenced(result)) {
|
||||
/* not in use so we can reuse it
|
||||
* (the common case during iteration) */
|
||||
Py_INCREF(result);
|
||||
|
|
@ -1783,6 +1849,17 @@ odictiter_iternext(PyObject *op)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
odictiter_iternext(PyObject *op)
|
||||
{
|
||||
PyObject *res;
|
||||
Py_BEGIN_CRITICAL_SECTION(op);
|
||||
res = odictiter_iternext_lock_held(op);
|
||||
Py_END_CRITICAL_SECTION();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* No need for tp_clear because odictiterobject is not mutable. */
|
||||
|
||||
PyDoc_STRVAR(reduce_doc, "Return state information for pickling");
|
||||
|
|
|
|||
|
|
@ -2444,7 +2444,7 @@ set_init(PyObject *so, PyObject *args, PyObject *kwds)
|
|||
if (!PyArg_UnpackTuple(args, Py_TYPE(self)->tp_name, 0, 1, &iterable))
|
||||
return -1;
|
||||
|
||||
if (Py_REFCNT(self) == 1 && self->fill == 0) {
|
||||
if (_PyObject_IsUniquelyReferenced((PyObject *)self) && self->fill == 0) {
|
||||
self->hash = -1;
|
||||
if (iterable == NULL) {
|
||||
return 0;
|
||||
|
|
@ -2774,7 +2774,7 @@ int
|
|||
PySet_Add(PyObject *anyset, PyObject *key)
|
||||
{
|
||||
if (!PySet_Check(anyset) &&
|
||||
(!PyFrozenSet_Check(anyset) || Py_REFCNT(anyset) != 1)) {
|
||||
(!PyFrozenSet_Check(anyset) || !_PyObject_IsUniquelyReferenced(anyset))) {
|
||||
PyErr_BadInternalCall();
|
||||
return -1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,97 +0,0 @@
|
|||
/* _PyUnicode_InsertThousandsGrouping() helper functions */
|
||||
|
||||
typedef struct {
|
||||
const char *grouping;
|
||||
char previous;
|
||||
Py_ssize_t i; /* Where we're currently pointing in grouping. */
|
||||
} GroupGenerator;
|
||||
|
||||
|
||||
static void
|
||||
GroupGenerator_init(GroupGenerator *self, const char *grouping)
|
||||
{
|
||||
self->grouping = grouping;
|
||||
self->i = 0;
|
||||
self->previous = 0;
|
||||
}
|
||||
|
||||
|
||||
/* Returns the next grouping, or 0 to signify end. */
|
||||
static Py_ssize_t
|
||||
GroupGenerator_next(GroupGenerator *self)
|
||||
{
|
||||
/* Note that we don't really do much error checking here. If a
|
||||
grouping string contains just CHAR_MAX, for example, then just
|
||||
terminate the generator. That shouldn't happen, but at least we
|
||||
fail gracefully. */
|
||||
switch (self->grouping[self->i]) {
|
||||
case 0:
|
||||
return self->previous;
|
||||
case CHAR_MAX:
|
||||
/* Stop the generator. */
|
||||
return 0;
|
||||
default: {
|
||||
char ch = self->grouping[self->i];
|
||||
self->previous = ch;
|
||||
self->i++;
|
||||
return (Py_ssize_t)ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Fill in some digits, leading zeros, and thousands separator. All
|
||||
are optional, depending on when we're called. */
|
||||
static void
|
||||
InsertThousandsGrouping_fill(_PyUnicodeWriter *writer, Py_ssize_t *buffer_pos,
|
||||
PyObject *digits, Py_ssize_t *digits_pos,
|
||||
Py_ssize_t n_chars, Py_ssize_t n_zeros,
|
||||
PyObject *thousands_sep, Py_ssize_t thousands_sep_len,
|
||||
Py_UCS4 *maxchar, int forward)
|
||||
{
|
||||
if (!writer) {
|
||||
/* if maxchar > 127, maxchar is already set */
|
||||
if (*maxchar == 127 && thousands_sep) {
|
||||
Py_UCS4 maxchar2 = PyUnicode_MAX_CHAR_VALUE(thousands_sep);
|
||||
*maxchar = Py_MAX(*maxchar, maxchar2);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (thousands_sep) {
|
||||
if (!forward) {
|
||||
*buffer_pos -= thousands_sep_len;
|
||||
}
|
||||
/* Copy the thousands_sep chars into the buffer. */
|
||||
_PyUnicode_FastCopyCharacters(writer->buffer, *buffer_pos,
|
||||
thousands_sep, 0,
|
||||
thousands_sep_len);
|
||||
if (forward) {
|
||||
*buffer_pos += thousands_sep_len;
|
||||
}
|
||||
}
|
||||
|
||||
if (!forward) {
|
||||
*buffer_pos -= n_chars;
|
||||
*digits_pos -= n_chars;
|
||||
}
|
||||
_PyUnicode_FastCopyCharacters(writer->buffer, *buffer_pos,
|
||||
digits, *digits_pos,
|
||||
n_chars);
|
||||
if (forward) {
|
||||
*buffer_pos += n_chars;
|
||||
*digits_pos += n_chars;
|
||||
}
|
||||
|
||||
if (n_zeros) {
|
||||
if (!forward) {
|
||||
*buffer_pos -= n_zeros;
|
||||
}
|
||||
int kind = PyUnicode_KIND(writer->buffer);
|
||||
void *data = PyUnicode_DATA(writer->buffer);
|
||||
unicode_fill(kind, data, '0', *buffer_pos, n_zeros);
|
||||
if (forward) {
|
||||
*buffer_pos += n_zeros;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
#include "pycore_modsupport.h" // _PyArg_NoPositional()
|
||||
#include "pycore_object.h" // _PyObject_GC_TRACK()
|
||||
#include "pycore_structseq.h" // PyStructSequence_InitType()
|
||||
#include "pycore_tuple.h" // _PyTuple_FromArray()
|
||||
#include "pycore_tuple.h" // _PyTuple_RESET_HASH_CACHE()
|
||||
#include "pycore_typeobject.h" // _PyStaticType_FiniBuiltin()
|
||||
|
||||
static const char visible_length_key[] = "n_sequence_fields";
|
||||
|
|
@ -353,7 +353,7 @@ structseq_reduce(PyObject *op, PyObject *Py_UNUSED(ignored))
|
|||
if (n_unnamed_fields < 0) {
|
||||
return NULL;
|
||||
}
|
||||
tup = _PyTuple_FromArray(self->ob_item, n_visible_fields);
|
||||
tup = PyTuple_FromArray(self->ob_item, n_visible_fields);
|
||||
if (!tup)
|
||||
goto error;
|
||||
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ int
|
|||
PyTuple_SetItem(PyObject *op, Py_ssize_t i, PyObject *newitem)
|
||||
{
|
||||
PyObject **p;
|
||||
if (!PyTuple_Check(op) || Py_REFCNT(op) != 1) {
|
||||
if (!PyTuple_Check(op) || !_PyObject_IsUniquelyReferenced(op)) {
|
||||
Py_XDECREF(newitem);
|
||||
PyErr_BadInternalCall();
|
||||
return -1;
|
||||
|
|
@ -156,6 +156,18 @@ _PyTuple_MaybeUntrack(PyObject *op)
|
|||
_PyObject_GC_UNTRACK(op);
|
||||
}
|
||||
|
||||
/* Fast, but conservative check if an object maybe tracked
|
||||
May return true for an object that is not tracked,
|
||||
Will always return true for an object that is tracked.
|
||||
This is a temporary workaround until _PyObject_GC_IS_TRACKED
|
||||
becomes fast and safe to call on non-GC objects.
|
||||
*/
|
||||
static bool
|
||||
maybe_tracked(PyObject *ob)
|
||||
{
|
||||
return _PyType_IS_GC(Py_TYPE(ob));
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyTuple_Pack(Py_ssize_t n, ...)
|
||||
{
|
||||
|
|
@ -163,6 +175,7 @@ PyTuple_Pack(Py_ssize_t n, ...)
|
|||
PyObject *o;
|
||||
PyObject **items;
|
||||
va_list vargs;
|
||||
bool track = false;
|
||||
|
||||
if (n == 0) {
|
||||
return tuple_get_empty();
|
||||
|
|
@ -177,10 +190,15 @@ PyTuple_Pack(Py_ssize_t n, ...)
|
|||
items = result->ob_item;
|
||||
for (i = 0; i < n; i++) {
|
||||
o = va_arg(vargs, PyObject *);
|
||||
if (!track && maybe_tracked(o)) {
|
||||
track = true;
|
||||
}
|
||||
items[i] = Py_NewRef(o);
|
||||
}
|
||||
va_end(vargs);
|
||||
_PyObject_GC_TRACK(result);
|
||||
if (track) {
|
||||
_PyObject_GC_TRACK(result);
|
||||
}
|
||||
return (PyObject *)result;
|
||||
}
|
||||
|
||||
|
|
@ -366,7 +384,7 @@ tuple_item(PyObject *op, Py_ssize_t i)
|
|||
}
|
||||
|
||||
PyObject *
|
||||
_PyTuple_FromArray(PyObject *const *src, Py_ssize_t n)
|
||||
PyTuple_FromArray(PyObject *const *src, Py_ssize_t n)
|
||||
{
|
||||
if (n == 0) {
|
||||
return tuple_get_empty();
|
||||
|
|
@ -377,11 +395,17 @@ _PyTuple_FromArray(PyObject *const *src, Py_ssize_t n)
|
|||
return NULL;
|
||||
}
|
||||
PyObject **dst = tuple->ob_item;
|
||||
bool track = false;
|
||||
for (Py_ssize_t i = 0; i < n; i++) {
|
||||
PyObject *item = src[i];
|
||||
if (!track && maybe_tracked(item)) {
|
||||
track = true;
|
||||
}
|
||||
dst[i] = Py_NewRef(item);
|
||||
}
|
||||
_PyObject_GC_TRACK(tuple);
|
||||
if (track) {
|
||||
_PyObject_GC_TRACK(tuple);
|
||||
}
|
||||
return (PyObject *)tuple;
|
||||
}
|
||||
|
||||
|
|
@ -396,10 +420,17 @@ _PyTuple_FromStackRefStealOnSuccess(const _PyStackRef *src, Py_ssize_t n)
|
|||
return NULL;
|
||||
}
|
||||
PyObject **dst = tuple->ob_item;
|
||||
bool track = false;
|
||||
for (Py_ssize_t i = 0; i < n; i++) {
|
||||
dst[i] = PyStackRef_AsPyObjectSteal(src[i]);
|
||||
PyObject *item = PyStackRef_AsPyObjectSteal(src[i]);
|
||||
if (!track && maybe_tracked(item)) {
|
||||
track = true;
|
||||
}
|
||||
dst[i] = item;
|
||||
}
|
||||
if (track) {
|
||||
_PyObject_GC_TRACK(tuple);
|
||||
}
|
||||
_PyObject_GC_TRACK(tuple);
|
||||
return (PyObject *)tuple;
|
||||
}
|
||||
|
||||
|
|
@ -438,7 +469,7 @@ tuple_slice(PyTupleObject *a, Py_ssize_t ilow,
|
|||
if (ilow == 0 && ihigh == Py_SIZE(a) && PyTuple_CheckExact(a)) {
|
||||
return Py_NewRef(a);
|
||||
}
|
||||
return _PyTuple_FromArray(a->ob_item + ilow, ihigh - ilow);
|
||||
return PyTuple_FromArray(a->ob_item + ilow, ihigh - ilow);
|
||||
}
|
||||
|
||||
PyObject *
|
||||
|
|
@ -923,7 +954,7 @@ _PyTuple_Resize(PyObject **pv, Py_ssize_t newsize)
|
|||
|
||||
v = (PyTupleObject *) *pv;
|
||||
if (v == NULL || !Py_IS_TYPE(v, &PyTuple_Type) ||
|
||||
(Py_SIZE(v) != 0 && Py_REFCNT(v) != 1)) {
|
||||
(Py_SIZE(v) != 0 && !_PyObject_IsUniquelyReferenced(*pv))) {
|
||||
*pv = 0;
|
||||
Py_XDECREF(v);
|
||||
PyErr_BadInternalCall();
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ class object "PyObject *" "&PyBaseObject_Type"
|
|||
// the type has been revealed to other threads or we only do those updates
|
||||
// while the stop-the-world mechanism is active. The slots and flags are read
|
||||
// in many places without holding a lock and without atomics.
|
||||
#define TYPE_LOCK &PyInterpreterState_Get()->types.mutex
|
||||
#define TYPE_LOCK &_PyInterpreterState_GET()->types.mutex
|
||||
#define BEGIN_TYPE_LOCK() Py_BEGIN_CRITICAL_SECTION_MUTEX(TYPE_LOCK)
|
||||
#define END_TYPE_LOCK() Py_END_CRITICAL_SECTION()
|
||||
|
||||
|
|
@ -81,7 +81,7 @@ class object "PyObject *" "&PyBaseObject_Type"
|
|||
|
||||
#define END_TYPE_DICT_LOCK() Py_END_CRITICAL_SECTION2()
|
||||
|
||||
#ifdef Py_DEBUG
|
||||
#ifndef NDEBUG
|
||||
// Return true if the world is currently stopped.
|
||||
static bool
|
||||
types_world_is_stopped(void)
|
||||
|
|
@ -1780,7 +1780,7 @@ static int recurse_down_subclasses(PyTypeObject *type, PyObject *name,
|
|||
// Compute tp_mro for this type and all of its subclasses. This
|
||||
// is called after __bases__ is assigned to an existing type.
|
||||
static int
|
||||
mro_hierarchy(PyTypeObject *type, PyObject *temp)
|
||||
mro_hierarchy_for_complete_type(PyTypeObject *type, PyObject *temp)
|
||||
{
|
||||
ASSERT_TYPE_LOCK_HELD();
|
||||
|
||||
|
|
@ -1791,6 +1791,7 @@ mro_hierarchy(PyTypeObject *type, PyObject *temp)
|
|||
return res;
|
||||
}
|
||||
PyObject *new_mro = lookup_tp_mro(type);
|
||||
assert(new_mro != NULL);
|
||||
|
||||
PyObject *tuple;
|
||||
if (old_mro != NULL) {
|
||||
|
|
@ -1835,7 +1836,7 @@ mro_hierarchy(PyTypeObject *type, PyObject *temp)
|
|||
Py_ssize_t n = PyList_GET_SIZE(subclasses);
|
||||
for (Py_ssize_t i = 0; i < n; i++) {
|
||||
PyTypeObject *subclass = _PyType_CAST(PyList_GET_ITEM(subclasses, i));
|
||||
res = mro_hierarchy(subclass, temp);
|
||||
res = mro_hierarchy_for_complete_type(subclass, temp);
|
||||
if (res < 0) {
|
||||
break;
|
||||
}
|
||||
|
|
@ -1926,7 +1927,7 @@ type_set_bases_unlocked(PyTypeObject *type, PyObject *new_bases, PyTypeObject *b
|
|||
if (temp == NULL) {
|
||||
goto bail;
|
||||
}
|
||||
if (mro_hierarchy(type, temp) < 0) {
|
||||
if (mro_hierarchy_for_complete_type(type, temp) < 0) {
|
||||
goto undo;
|
||||
}
|
||||
Py_DECREF(temp);
|
||||
|
|
@ -3432,6 +3433,7 @@ mro_implementation_unlocked(PyTypeObject *type)
|
|||
*/
|
||||
PyTypeObject *base = _PyType_CAST(PyTuple_GET_ITEM(bases, 0));
|
||||
PyObject *base_mro = lookup_tp_mro(base);
|
||||
assert(base_mro != NULL);
|
||||
Py_ssize_t k = PyTuple_GET_SIZE(base_mro);
|
||||
PyObject *result = PyTuple_New(k + 1);
|
||||
if (result == NULL) {
|
||||
|
|
@ -3466,9 +3468,12 @@ mro_implementation_unlocked(PyTypeObject *type)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *mro_to_merge;
|
||||
for (Py_ssize_t i = 0; i < n; i++) {
|
||||
PyTypeObject *base = _PyType_CAST(PyTuple_GET_ITEM(bases, i));
|
||||
to_merge[i] = lookup_tp_mro(base);
|
||||
mro_to_merge = lookup_tp_mro(base);
|
||||
assert(mro_to_merge != NULL);
|
||||
to_merge[i] = mro_to_merge;
|
||||
}
|
||||
to_merge[n] = bases;
|
||||
|
||||
|
|
@ -8893,6 +8898,13 @@ type_ready_preheader(PyTypeObject *type)
|
|||
type->tp_name);
|
||||
return -1;
|
||||
}
|
||||
if (!(type->tp_flags & Py_TPFLAGS_HAVE_GC)) {
|
||||
PyErr_Format(PyExc_SystemError,
|
||||
"type %s has the Py_TPFLAGS_MANAGED_DICT flag "
|
||||
"but not Py_TPFLAGS_HAVE_GC flag",
|
||||
type->tp_name);
|
||||
return -1;
|
||||
}
|
||||
type->tp_dictoffset = -1;
|
||||
}
|
||||
if (type->tp_flags & Py_TPFLAGS_MANAGED_WEAKREF) {
|
||||
|
|
@ -8905,6 +8917,13 @@ type_ready_preheader(PyTypeObject *type)
|
|||
type->tp_name);
|
||||
return -1;
|
||||
}
|
||||
if (!(type->tp_flags & Py_TPFLAGS_HAVE_GC)) {
|
||||
PyErr_Format(PyExc_SystemError,
|
||||
"type %s has the Py_TPFLAGS_MANAGED_WEAKREF flag "
|
||||
"but not Py_TPFLAGS_HAVE_GC flag",
|
||||
type->tp_name);
|
||||
return -1;
|
||||
}
|
||||
type->tp_weaklistoffset = MANAGED_WEAKREF_OFFSET;
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -8998,6 +9017,7 @@ type_ready_inherit(PyTypeObject *type)
|
|||
|
||||
// Inherit slots
|
||||
PyObject *mro = lookup_tp_mro(type);
|
||||
assert(mro != NULL);
|
||||
Py_ssize_t n = PyTuple_GET_SIZE(mro);
|
||||
for (Py_ssize_t i = 1; i < n; i++) {
|
||||
PyObject *b = PyTuple_GET_ITEM(mro, i);
|
||||
|
|
@ -10569,6 +10589,7 @@ slot_tp_hash(PyObject *self)
|
|||
return PyObject_HashNotImplemented(self);
|
||||
}
|
||||
if (!PyLong_Check(res)) {
|
||||
Py_DECREF(res);
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"__hash__ method should return an integer");
|
||||
return -1;
|
||||
|
|
@ -11422,6 +11443,11 @@ static pytype_slotdef slotdefs[] = {
|
|||
{NULL}
|
||||
};
|
||||
|
||||
/* Stores the number of times where slotdefs has elements with same name.
|
||||
This counter precalculated by _PyType_InitSlotDefs() when the main
|
||||
interpreter starts. */
|
||||
static uint8_t slotdefs_name_counts[Py_ARRAY_LENGTH(slotdefs)];
|
||||
|
||||
/* Given a type pointer and an offset gotten from a slotdef entry, return a
|
||||
pointer to the actual slot. This is not quite the same as simply adding
|
||||
the offset to the type pointer, since it takes care to indirect through the
|
||||
|
|
@ -11464,61 +11490,6 @@ slotptr(PyTypeObject *type, int ioffset)
|
|||
return (void **)ptr;
|
||||
}
|
||||
|
||||
/* Return a slot pointer for a given name, but ONLY if the attribute has
|
||||
exactly one slot function. The name must be an interned string. */
|
||||
static void **
|
||||
resolve_slotdups(PyTypeObject *type, PyObject *name)
|
||||
{
|
||||
/* XXX Maybe this could be optimized more -- but is it worth it? */
|
||||
|
||||
#ifdef Py_GIL_DISABLED
|
||||
pytype_slotdef *ptrs[MAX_EQUIV];
|
||||
pytype_slotdef **pp = ptrs;
|
||||
/* Collect all slotdefs that match name into ptrs. */
|
||||
for (pytype_slotdef *p = slotdefs; p->name_strobj; p++) {
|
||||
if (p->name_strobj == name)
|
||||
*pp++ = p;
|
||||
}
|
||||
*pp = NULL;
|
||||
#else
|
||||
/* pname and ptrs act as a little cache */
|
||||
PyInterpreterState *interp = _PyInterpreterState_GET();
|
||||
#define pname _Py_INTERP_CACHED_OBJECT(interp, type_slots_pname)
|
||||
#define ptrs _Py_INTERP_CACHED_OBJECT(interp, type_slots_ptrs)
|
||||
pytype_slotdef *p, **pp;
|
||||
|
||||
if (pname != name) {
|
||||
/* Collect all slotdefs that match name into ptrs. */
|
||||
pname = name;
|
||||
pp = ptrs;
|
||||
for (p = slotdefs; p->name_strobj; p++) {
|
||||
if (p->name_strobj == name)
|
||||
*pp++ = p;
|
||||
}
|
||||
*pp = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Look in all slots of the type matching the name. If exactly one of these
|
||||
has a filled-in slot, return a pointer to that slot.
|
||||
Otherwise, return NULL. */
|
||||
void **res, **ptr;
|
||||
res = NULL;
|
||||
for (pp = ptrs; *pp; pp++) {
|
||||
ptr = slotptr(type, (*pp)->offset);
|
||||
if (ptr == NULL || *ptr == NULL)
|
||||
continue;
|
||||
if (res != NULL)
|
||||
return NULL;
|
||||
res = ptr;
|
||||
}
|
||||
#ifndef Py_GIL_DISABLED
|
||||
#undef pname
|
||||
#undef ptrs
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
// Return true if "name" corresponds to at least one slot definition. This is
|
||||
// a more accurate but more expensive test compared to is_dunder_name().
|
||||
static bool
|
||||
|
|
@ -11645,7 +11616,15 @@ update_one_slot(PyTypeObject *type, pytype_slotdef *p, pytype_slotdef **next_p,
|
|||
}
|
||||
if (Py_IS_TYPE(descr, &PyWrapperDescr_Type) &&
|
||||
((PyWrapperDescrObject *)descr)->d_base->name_strobj == p->name_strobj) {
|
||||
void **tptr = resolve_slotdups(type, p->name_strobj);
|
||||
void **tptr;
|
||||
size_t index = (p - slotdefs) / sizeof(slotdefs[0]);
|
||||
if (slotdefs_name_counts[index] == 1) {
|
||||
tptr = slotptr(type, p->offset);
|
||||
}
|
||||
else {
|
||||
tptr = NULL;
|
||||
}
|
||||
|
||||
if (tptr == NULL || tptr == ptr)
|
||||
generic = p->function;
|
||||
d = (PyWrapperDescrObject *)descr;
|
||||
|
|
@ -11858,6 +11837,76 @@ update_all_slots(PyTypeObject* type)
|
|||
|
||||
#endif
|
||||
|
||||
int
|
||||
_PyType_InitSlotDefs(PyInterpreterState *interp)
|
||||
{
|
||||
if (!_Py_IsMainInterpreter(interp)) {
|
||||
return 0;
|
||||
}
|
||||
PyObject *bytearray = NULL;
|
||||
PyObject *cache = PyDict_New();
|
||||
if (!cache) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pytype_slotdef *p;
|
||||
Py_ssize_t idx = 0;
|
||||
for (p = slotdefs; p->name_strobj; p++, idx++) {
|
||||
assert(idx < 255);
|
||||
|
||||
if (PyDict_GetItemRef(cache, p->name_strobj, &bytearray) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!bytearray) {
|
||||
Py_ssize_t size = sizeof(uint8_t) * (1 + MAX_EQUIV);
|
||||
bytearray = PyByteArray_FromStringAndSize(NULL, size);
|
||||
if (!bytearray) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
uint8_t *data = (uint8_t *)PyByteArray_AS_STRING(bytearray);
|
||||
data[0] = 0;
|
||||
|
||||
if (PyDict_SetItem(cache, p->name_strobj, bytearray) < 0) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
assert(PyByteArray_CheckExact(bytearray));
|
||||
uint8_t *data = (uint8_t *)PyByteArray_AS_STRING(bytearray);
|
||||
|
||||
data[0] += 1;
|
||||
assert(data[0] < MAX_EQUIV);
|
||||
|
||||
data[data[0]] = (uint8_t)idx;
|
||||
|
||||
Py_CLEAR(bytearray);
|
||||
}
|
||||
|
||||
memset(slotdefs_name_counts, 0, sizeof(slotdefs_name_counts));
|
||||
|
||||
Py_ssize_t pos = 0;
|
||||
PyObject *key = NULL;
|
||||
PyObject *value = NULL;
|
||||
while (PyDict_Next(cache, &pos, &key, &value)) {
|
||||
uint8_t *data = (uint8_t *)PyByteArray_AS_STRING(value);
|
||||
uint8_t n = data[0];
|
||||
for (uint8_t i = 0; i < n; i++) {
|
||||
uint8_t idx = data[i + 1];
|
||||
slotdefs_name_counts[idx] = n;
|
||||
}
|
||||
}
|
||||
|
||||
Py_DECREF(cache);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
Py_XDECREF(bytearray);
|
||||
Py_DECREF(cache);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
PyObject *
|
||||
_PyType_GetSlotWrapperNames(void)
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ typedef struct {
|
|||
typedef struct {
|
||||
PyObject_HEAD
|
||||
PyObject *name;
|
||||
PyObject *qualname;
|
||||
PyObject *type_params;
|
||||
PyObject *compute_value;
|
||||
PyObject *value;
|
||||
|
|
@ -472,7 +473,7 @@ typevar_dealloc(PyObject *self)
|
|||
|
||||
_PyObject_GC_UNTRACK(self);
|
||||
|
||||
Py_DECREF(tv->name);
|
||||
Py_XDECREF(tv->name);
|
||||
Py_XDECREF(tv->bound);
|
||||
Py_XDECREF(tv->evaluate_bound);
|
||||
Py_XDECREF(tv->constraints);
|
||||
|
|
@ -491,6 +492,7 @@ typevar_traverse(PyObject *self, visitproc visit, void *arg)
|
|||
{
|
||||
Py_VISIT(Py_TYPE(self));
|
||||
typevarobject *tv = typevarobject_CAST(self);
|
||||
Py_VISIT(tv->name);
|
||||
Py_VISIT(tv->bound);
|
||||
Py_VISIT(tv->evaluate_bound);
|
||||
Py_VISIT(tv->constraints);
|
||||
|
|
@ -505,6 +507,7 @@ static int
|
|||
typevar_clear(PyObject *op)
|
||||
{
|
||||
typevarobject *self = typevarobject_CAST(op);
|
||||
Py_CLEAR(self->name);
|
||||
Py_CLEAR(self->bound);
|
||||
Py_CLEAR(self->evaluate_bound);
|
||||
Py_CLEAR(self->constraints);
|
||||
|
|
@ -1171,7 +1174,7 @@ paramspec_dealloc(PyObject *self)
|
|||
|
||||
_PyObject_GC_UNTRACK(self);
|
||||
|
||||
Py_DECREF(ps->name);
|
||||
Py_XDECREF(ps->name);
|
||||
Py_XDECREF(ps->bound);
|
||||
Py_XDECREF(ps->default_value);
|
||||
Py_XDECREF(ps->evaluate_default);
|
||||
|
|
@ -1187,6 +1190,7 @@ paramspec_traverse(PyObject *self, visitproc visit, void *arg)
|
|||
{
|
||||
Py_VISIT(Py_TYPE(self));
|
||||
paramspecobject *ps = paramspecobject_CAST(self);
|
||||
Py_VISIT(ps->name);
|
||||
Py_VISIT(ps->bound);
|
||||
Py_VISIT(ps->default_value);
|
||||
Py_VISIT(ps->evaluate_default);
|
||||
|
|
@ -1198,6 +1202,7 @@ static int
|
|||
paramspec_clear(PyObject *op)
|
||||
{
|
||||
paramspecobject *self = paramspecobject_CAST(op);
|
||||
Py_CLEAR(self->name);
|
||||
Py_CLEAR(self->bound);
|
||||
Py_CLEAR(self->default_value);
|
||||
Py_CLEAR(self->evaluate_default);
|
||||
|
|
@ -1519,7 +1524,7 @@ typevartuple_dealloc(PyObject *self)
|
|||
_PyObject_GC_UNTRACK(self);
|
||||
typevartupleobject *tvt = typevartupleobject_CAST(self);
|
||||
|
||||
Py_DECREF(tvt->name);
|
||||
Py_XDECREF(tvt->name);
|
||||
Py_XDECREF(tvt->default_value);
|
||||
Py_XDECREF(tvt->evaluate_default);
|
||||
PyObject_ClearManagedDict(self);
|
||||
|
|
@ -1683,6 +1688,7 @@ typevartuple_traverse(PyObject *self, visitproc visit, void *arg)
|
|||
{
|
||||
Py_VISIT(Py_TYPE(self));
|
||||
typevartupleobject *tvt = typevartupleobject_CAST(self);
|
||||
Py_VISIT(tvt->name);
|
||||
Py_VISIT(tvt->default_value);
|
||||
Py_VISIT(tvt->evaluate_default);
|
||||
PyObject_VisitManagedDict(self, visit, arg);
|
||||
|
|
@ -1693,6 +1699,7 @@ static int
|
|||
typevartuple_clear(PyObject *self)
|
||||
{
|
||||
typevartupleobject *tvt = typevartupleobject_CAST(self);
|
||||
Py_CLEAR(tvt->name);
|
||||
Py_CLEAR(tvt->default_value);
|
||||
Py_CLEAR(tvt->evaluate_default);
|
||||
PyObject_ClearManagedDict(self);
|
||||
|
|
@ -1851,7 +1858,8 @@ typealias_dealloc(PyObject *self)
|
|||
PyTypeObject *tp = Py_TYPE(self);
|
||||
_PyObject_GC_UNTRACK(self);
|
||||
typealiasobject *ta = typealiasobject_CAST(self);
|
||||
Py_DECREF(ta->name);
|
||||
Py_XDECREF(ta->name);
|
||||
Py_XDECREF(ta->qualname);
|
||||
Py_XDECREF(ta->type_params);
|
||||
Py_XDECREF(ta->compute_value);
|
||||
Py_XDECREF(ta->value);
|
||||
|
|
@ -1878,11 +1886,12 @@ static PyObject *
|
|||
typealias_repr(PyObject *self)
|
||||
{
|
||||
typealiasobject *ta = (typealiasobject *)self;
|
||||
return Py_NewRef(ta->name);
|
||||
return Py_NewRef(ta->qualname);
|
||||
}
|
||||
|
||||
static PyMemberDef typealias_members[] = {
|
||||
{"__name__", _Py_T_OBJECT, offsetof(typealiasobject, name), Py_READONLY},
|
||||
{"__qualname__", _Py_T_OBJECT, offsetof(typealiasobject, qualname), Py_READONLY},
|
||||
{0}
|
||||
};
|
||||
|
||||
|
|
@ -1997,7 +2006,7 @@ typealias_check_type_params(PyObject *type_params, int *err) {
|
|||
}
|
||||
|
||||
static PyObject *
|
||||
typelias_convert_type_params(PyObject *type_params)
|
||||
typealias_convert_type_params(PyObject *type_params)
|
||||
{
|
||||
if (
|
||||
type_params == NULL
|
||||
|
|
@ -2012,14 +2021,15 @@ typelias_convert_type_params(PyObject *type_params)
|
|||
}
|
||||
|
||||
static typealiasobject *
|
||||
typealias_alloc(PyObject *name, PyObject *type_params, PyObject *compute_value,
|
||||
PyObject *value, PyObject *module)
|
||||
typealias_alloc(PyObject *name, PyObject *qualname, PyObject *type_params,
|
||||
PyObject *compute_value, PyObject *value, PyObject *module)
|
||||
{
|
||||
typealiasobject *ta = PyObject_GC_New(typealiasobject, &_PyTypeAlias_Type);
|
||||
if (ta == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ta->name = Py_NewRef(name);
|
||||
ta->qualname = Py_NewRef(qualname);
|
||||
ta->type_params = Py_XNewRef(type_params);
|
||||
ta->compute_value = Py_XNewRef(compute_value);
|
||||
ta->value = Py_XNewRef(value);
|
||||
|
|
@ -2032,6 +2042,8 @@ static int
|
|||
typealias_traverse(PyObject *op, visitproc visit, void *arg)
|
||||
{
|
||||
typealiasobject *self = typealiasobject_CAST(op);
|
||||
Py_VISIT(self->name);
|
||||
Py_VISIT(self->qualname);
|
||||
Py_VISIT(self->type_params);
|
||||
Py_VISIT(self->compute_value);
|
||||
Py_VISIT(self->value);
|
||||
|
|
@ -2043,6 +2055,8 @@ static int
|
|||
typealias_clear(PyObject *op)
|
||||
{
|
||||
typealiasobject *self = typealiasobject_CAST(op);
|
||||
Py_CLEAR(self->name);
|
||||
Py_CLEAR(self->qualname);
|
||||
Py_CLEAR(self->type_params);
|
||||
Py_CLEAR(self->compute_value);
|
||||
Py_CLEAR(self->value);
|
||||
|
|
@ -2088,14 +2102,15 @@ typealias.__new__ as typealias_new
|
|||
value: object
|
||||
*
|
||||
type_params: object = NULL
|
||||
qualname: object(c_default="NULL") = None
|
||||
|
||||
Create a TypeAliasType.
|
||||
[clinic start generated code]*/
|
||||
|
||||
static PyObject *
|
||||
typealias_new_impl(PyTypeObject *type, PyObject *name, PyObject *value,
|
||||
PyObject *type_params)
|
||||
/*[clinic end generated code: output=8920ce6bdff86f00 input=df163c34e17e1a35]*/
|
||||
PyObject *type_params, PyObject *qualname)
|
||||
/*[clinic end generated code: output=b7f6d9f1c577cd9c input=cbec290f8c4886ef]*/
|
||||
{
|
||||
if (type_params != NULL && !PyTuple_Check(type_params)) {
|
||||
PyErr_SetString(PyExc_TypeError, "type_params must be a tuple");
|
||||
|
|
@ -2108,12 +2123,23 @@ typealias_new_impl(PyTypeObject *type, PyObject *name, PyObject *value,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (qualname == NULL || qualname == Py_None) {
|
||||
// If qualname was not set directly, we use name instead.
|
||||
qualname = name;
|
||||
} else {
|
||||
if (!PyUnicode_Check(qualname)) {
|
||||
PyErr_SetString(PyExc_TypeError, "qualname must be a string");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
PyObject *module = caller();
|
||||
if (module == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
PyObject *ta = (PyObject *)typealias_alloc(name, checked_params, NULL, value,
|
||||
module);
|
||||
|
||||
PyObject *ta = (PyObject *)typealias_alloc(
|
||||
name, qualname, checked_params, NULL, value, module);
|
||||
Py_DECREF(module);
|
||||
return ta;
|
||||
}
|
||||
|
|
@ -2179,10 +2205,17 @@ _Py_make_typealias(PyThreadState* unused, PyObject *args)
|
|||
assert(PyTuple_GET_SIZE(args) == 3);
|
||||
PyObject *name = PyTuple_GET_ITEM(args, 0);
|
||||
assert(PyUnicode_Check(name));
|
||||
PyObject *type_params = typelias_convert_type_params(PyTuple_GET_ITEM(args, 1));
|
||||
PyObject *type_params = typealias_convert_type_params(PyTuple_GET_ITEM(args, 1));
|
||||
PyObject *compute_value = PyTuple_GET_ITEM(args, 2);
|
||||
assert(PyFunction_Check(compute_value));
|
||||
return (PyObject *)typealias_alloc(name, type_params, compute_value, NULL, NULL);
|
||||
|
||||
PyFunctionObject *compute_func = (PyFunctionObject *)compute_value;
|
||||
PyCodeObject *code_obj = (PyCodeObject *)compute_func->func_code;
|
||||
PyObject *qualname = code_obj->co_qualname;
|
||||
assert(qualname != NULL);
|
||||
|
||||
return (PyObject *)typealias_alloc(
|
||||
name, qualname, type_params, compute_value, NULL, NULL);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(generic_doc,
|
||||
|
|
|
|||
1002
Objects/unicode_format.c
Normal file
1002
Objects/unicode_format.c
Normal file
File diff suppressed because it is too large
Load diff
1961
Objects/unicode_formatter.c
Normal file
1961
Objects/unicode_formatter.c
Normal file
File diff suppressed because it is too large
Load diff
639
Objects/unicode_writer.c
Normal file
639
Objects/unicode_writer.c
Normal file
|
|
@ -0,0 +1,639 @@
|
|||
/*
|
||||
|
||||
Unicode implementation based on original code by Fredrik Lundh,
|
||||
modified by Marc-Andre Lemburg <mal@lemburg.com>.
|
||||
|
||||
Major speed upgrades to the method implementations at the Reykjavik
|
||||
NeedForSpeed sprint, by Fredrik Lundh and Andrew Dalke.
|
||||
|
||||
Copyright (c) Corporation for National Research Initiatives.
|
||||
|
||||
--------------------------------------------------------------------
|
||||
The original string type implementation is:
|
||||
|
||||
Copyright (c) 1999 by Secret Labs AB
|
||||
Copyright (c) 1999 by Fredrik Lundh
|
||||
|
||||
By obtaining, using, and/or copying this software and/or its
|
||||
associated documentation, you agree that you have read, understood,
|
||||
and will comply with the following terms and conditions:
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and its
|
||||
associated documentation for any purpose and without fee is hereby
|
||||
granted, provided that the above copyright notice appears in all
|
||||
copies, and that both that copyright notice and this permission notice
|
||||
appear in supporting documentation, and that the name of Secret Labs
|
||||
AB or the author not be used in advertising or publicity pertaining to
|
||||
distribution of the software without specific, written prior
|
||||
permission.
|
||||
|
||||
SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO
|
||||
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
--------------------------------------------------------------------
|
||||
|
||||
*/
|
||||
|
||||
#include "Python.h"
|
||||
#include "pycore_freelist.h" // _Py_FREELIST_FREE()
|
||||
#include "pycore_long.h" // _PyLong_FormatWriter()
|
||||
#include "pycore_unicodeobject.h" // _PyUnicode_Result()
|
||||
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
/* On Windows, overallocate by 50% is the best factor */
|
||||
# define OVERALLOCATE_FACTOR 2
|
||||
#else
|
||||
/* On Linux, overallocate by 25% is the best factor */
|
||||
# define OVERALLOCATE_FACTOR 4
|
||||
#endif
|
||||
|
||||
|
||||
/* Compilation of templated routines */
|
||||
|
||||
#define STRINGLIB_GET_EMPTY() _PyUnicode_GetEmpty()
|
||||
|
||||
#include "stringlib/ucs1lib.h"
|
||||
#include "stringlib/find_max_char.h"
|
||||
#include "stringlib/undef.h"
|
||||
|
||||
|
||||
/* Copy an ASCII or latin1 char* string into a Python Unicode string.
|
||||
|
||||
WARNING: The function doesn't copy the terminating null character and
|
||||
doesn't check the maximum character (may write a latin1 character in an
|
||||
ASCII string). */
|
||||
static void
|
||||
unicode_write_cstr(PyObject *unicode, Py_ssize_t index,
|
||||
const char *str, Py_ssize_t len)
|
||||
{
|
||||
int kind = PyUnicode_KIND(unicode);
|
||||
const void *data = PyUnicode_DATA(unicode);
|
||||
const char *end = str + len;
|
||||
|
||||
assert(index + len <= PyUnicode_GET_LENGTH(unicode));
|
||||
switch (kind) {
|
||||
case PyUnicode_1BYTE_KIND: {
|
||||
#ifdef Py_DEBUG
|
||||
if (PyUnicode_IS_ASCII(unicode)) {
|
||||
Py_UCS4 maxchar = ucs1lib_find_max_char(
|
||||
(const Py_UCS1*)str,
|
||||
(const Py_UCS1*)str + len);
|
||||
assert(maxchar < 128);
|
||||
}
|
||||
#endif
|
||||
memcpy((char *) data + index, str, len);
|
||||
break;
|
||||
}
|
||||
case PyUnicode_2BYTE_KIND: {
|
||||
Py_UCS2 *start = (Py_UCS2 *)data + index;
|
||||
Py_UCS2 *ucs2 = start;
|
||||
|
||||
for (; str < end; ++ucs2, ++str)
|
||||
*ucs2 = (Py_UCS2)*str;
|
||||
|
||||
assert((ucs2 - start) <= PyUnicode_GET_LENGTH(unicode));
|
||||
break;
|
||||
}
|
||||
case PyUnicode_4BYTE_KIND: {
|
||||
Py_UCS4 *start = (Py_UCS4 *)data + index;
|
||||
Py_UCS4 *ucs4 = start;
|
||||
|
||||
for (; str < end; ++ucs4, ++str)
|
||||
*ucs4 = (Py_UCS4)*str;
|
||||
|
||||
assert((ucs4 - start) <= PyUnicode_GET_LENGTH(unicode));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Py_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
_PyUnicodeWriter_Update(_PyUnicodeWriter *writer)
|
||||
{
|
||||
writer->maxchar = PyUnicode_MAX_CHAR_VALUE(writer->buffer);
|
||||
writer->data = PyUnicode_DATA(writer->buffer);
|
||||
|
||||
if (!writer->readonly) {
|
||||
writer->kind = PyUnicode_KIND(writer->buffer);
|
||||
writer->size = PyUnicode_GET_LENGTH(writer->buffer);
|
||||
}
|
||||
else {
|
||||
/* use a value smaller than PyUnicode_1BYTE_KIND() so
|
||||
_PyUnicodeWriter_PrepareKind() will copy the buffer. */
|
||||
writer->kind = 0;
|
||||
assert(writer->kind <= PyUnicode_1BYTE_KIND);
|
||||
|
||||
/* Copy-on-write mode: set buffer size to 0 so
|
||||
* _PyUnicodeWriter_Prepare() will copy (and enlarge) the buffer on
|
||||
* next write. */
|
||||
writer->size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_PyUnicodeWriter_Init(_PyUnicodeWriter *writer)
|
||||
{
|
||||
memset(writer, 0, sizeof(*writer));
|
||||
|
||||
/* ASCII is the bare minimum */
|
||||
writer->min_char = 127;
|
||||
|
||||
/* use a kind value smaller than PyUnicode_1BYTE_KIND so
|
||||
_PyUnicodeWriter_PrepareKind() will copy the buffer. */
|
||||
assert(writer->kind == 0);
|
||||
assert(writer->kind < PyUnicode_1BYTE_KIND);
|
||||
}
|
||||
|
||||
|
||||
PyUnicodeWriter*
|
||||
PyUnicodeWriter_Create(Py_ssize_t length)
|
||||
{
|
||||
if (length < 0) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"length must be positive");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const size_t size = sizeof(_PyUnicodeWriter);
|
||||
PyUnicodeWriter *pub_writer;
|
||||
pub_writer = _Py_FREELIST_POP_MEM(unicode_writers);
|
||||
if (pub_writer == NULL) {
|
||||
pub_writer = (PyUnicodeWriter *)PyMem_Malloc(size);
|
||||
if (pub_writer == NULL) {
|
||||
return (PyUnicodeWriter *)PyErr_NoMemory();
|
||||
}
|
||||
}
|
||||
_PyUnicodeWriter *writer = (_PyUnicodeWriter *)pub_writer;
|
||||
|
||||
_PyUnicodeWriter_Init(writer);
|
||||
if (_PyUnicodeWriter_Prepare(writer, length, 127) < 0) {
|
||||
PyUnicodeWriter_Discard(pub_writer);
|
||||
return NULL;
|
||||
}
|
||||
writer->overallocate = 1;
|
||||
|
||||
return pub_writer;
|
||||
}
|
||||
|
||||
|
||||
void PyUnicodeWriter_Discard(PyUnicodeWriter *writer)
|
||||
{
|
||||
if (writer == NULL) {
|
||||
return;
|
||||
}
|
||||
_PyUnicodeWriter_Dealloc((_PyUnicodeWriter*)writer);
|
||||
_Py_FREELIST_FREE(unicode_writers, writer, PyMem_Free);
|
||||
}
|
||||
|
||||
|
||||
// Initialize _PyUnicodeWriter with initial buffer
|
||||
void
|
||||
_PyUnicodeWriter_InitWithBuffer(_PyUnicodeWriter *writer, PyObject *buffer)
|
||||
{
|
||||
memset(writer, 0, sizeof(*writer));
|
||||
writer->buffer = buffer;
|
||||
_PyUnicodeWriter_Update(writer);
|
||||
writer->min_length = writer->size;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
_PyUnicodeWriter_PrepareInternal(_PyUnicodeWriter *writer,
|
||||
Py_ssize_t length, Py_UCS4 maxchar)
|
||||
{
|
||||
Py_ssize_t newlen;
|
||||
PyObject *newbuffer;
|
||||
|
||||
assert(length >= 0);
|
||||
assert(maxchar <= _Py_MAX_UNICODE);
|
||||
|
||||
/* ensure that the _PyUnicodeWriter_Prepare macro was used */
|
||||
assert((maxchar > writer->maxchar && length >= 0)
|
||||
|| length > 0);
|
||||
|
||||
if (length > PY_SSIZE_T_MAX - writer->pos) {
|
||||
PyErr_NoMemory();
|
||||
return -1;
|
||||
}
|
||||
newlen = writer->pos + length;
|
||||
|
||||
maxchar = Py_MAX(maxchar, writer->min_char);
|
||||
|
||||
if (writer->buffer == NULL) {
|
||||
assert(!writer->readonly);
|
||||
if (writer->overallocate
|
||||
&& newlen <= (PY_SSIZE_T_MAX - newlen / OVERALLOCATE_FACTOR)) {
|
||||
/* overallocate to limit the number of realloc() */
|
||||
newlen += newlen / OVERALLOCATE_FACTOR;
|
||||
}
|
||||
if (newlen < writer->min_length)
|
||||
newlen = writer->min_length;
|
||||
|
||||
writer->buffer = PyUnicode_New(newlen, maxchar);
|
||||
if (writer->buffer == NULL)
|
||||
return -1;
|
||||
}
|
||||
else if (newlen > writer->size) {
|
||||
if (writer->overallocate
|
||||
&& newlen <= (PY_SSIZE_T_MAX - newlen / OVERALLOCATE_FACTOR)) {
|
||||
/* overallocate to limit the number of realloc() */
|
||||
newlen += newlen / OVERALLOCATE_FACTOR;
|
||||
}
|
||||
if (newlen < writer->min_length)
|
||||
newlen = writer->min_length;
|
||||
|
||||
if (maxchar > writer->maxchar || writer->readonly) {
|
||||
/* resize + widen */
|
||||
maxchar = Py_MAX(maxchar, writer->maxchar);
|
||||
newbuffer = PyUnicode_New(newlen, maxchar);
|
||||
if (newbuffer == NULL)
|
||||
return -1;
|
||||
_PyUnicode_FastCopyCharacters(newbuffer, 0,
|
||||
writer->buffer, 0, writer->pos);
|
||||
Py_DECREF(writer->buffer);
|
||||
writer->readonly = 0;
|
||||
}
|
||||
else {
|
||||
newbuffer = _PyUnicode_ResizeCompact(writer->buffer, newlen);
|
||||
if (newbuffer == NULL)
|
||||
return -1;
|
||||
}
|
||||
writer->buffer = newbuffer;
|
||||
}
|
||||
else if (maxchar > writer->maxchar) {
|
||||
assert(!writer->readonly);
|
||||
newbuffer = PyUnicode_New(writer->size, maxchar);
|
||||
if (newbuffer == NULL)
|
||||
return -1;
|
||||
_PyUnicode_FastCopyCharacters(newbuffer, 0,
|
||||
writer->buffer, 0, writer->pos);
|
||||
Py_SETREF(writer->buffer, newbuffer);
|
||||
}
|
||||
_PyUnicodeWriter_Update(writer);
|
||||
return 0;
|
||||
|
||||
#undef OVERALLOCATE_FACTOR
|
||||
}
|
||||
|
||||
int
|
||||
_PyUnicodeWriter_PrepareKindInternal(_PyUnicodeWriter *writer,
|
||||
int kind)
|
||||
{
|
||||
Py_UCS4 maxchar;
|
||||
|
||||
/* ensure that the _PyUnicodeWriter_PrepareKind macro was used */
|
||||
assert(writer->kind < kind);
|
||||
|
||||
switch (kind)
|
||||
{
|
||||
case PyUnicode_1BYTE_KIND: maxchar = 0xff; break;
|
||||
case PyUnicode_2BYTE_KIND: maxchar = 0xffff; break;
|
||||
case PyUnicode_4BYTE_KIND: maxchar = _Py_MAX_UNICODE; break;
|
||||
default:
|
||||
Py_UNREACHABLE();
|
||||
}
|
||||
|
||||
return _PyUnicodeWriter_PrepareInternal(writer, 0, maxchar);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
_PyUnicodeWriter_WriteChar(_PyUnicodeWriter *writer, Py_UCS4 ch)
|
||||
{
|
||||
return _PyUnicodeWriter_WriteCharInline(writer, ch);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
PyUnicodeWriter_WriteChar(PyUnicodeWriter *writer, Py_UCS4 ch)
|
||||
{
|
||||
if (ch > _Py_MAX_UNICODE) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"character must be in range(0x110000)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _PyUnicodeWriter_WriteChar((_PyUnicodeWriter*)writer, ch);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
_PyUnicodeWriter_WriteStr(_PyUnicodeWriter *writer, PyObject *str)
|
||||
{
|
||||
assert(PyUnicode_Check(str));
|
||||
|
||||
Py_UCS4 maxchar;
|
||||
Py_ssize_t len;
|
||||
|
||||
len = PyUnicode_GET_LENGTH(str);
|
||||
if (len == 0)
|
||||
return 0;
|
||||
maxchar = PyUnicode_MAX_CHAR_VALUE(str);
|
||||
if (maxchar > writer->maxchar || len > writer->size - writer->pos) {
|
||||
if (writer->buffer == NULL && !writer->overallocate) {
|
||||
assert(_PyUnicode_CheckConsistency(str, 1));
|
||||
writer->readonly = 1;
|
||||
writer->buffer = Py_NewRef(str);
|
||||
_PyUnicodeWriter_Update(writer);
|
||||
writer->pos += len;
|
||||
return 0;
|
||||
}
|
||||
if (_PyUnicodeWriter_PrepareInternal(writer, len, maxchar) == -1)
|
||||
return -1;
|
||||
}
|
||||
_PyUnicode_FastCopyCharacters(writer->buffer, writer->pos,
|
||||
str, 0, len);
|
||||
writer->pos += len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
PyUnicodeWriter_WriteStr(PyUnicodeWriter *writer, PyObject *obj)
|
||||
{
|
||||
PyTypeObject *type = Py_TYPE(obj);
|
||||
if (type == &PyUnicode_Type) {
|
||||
return _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, obj);
|
||||
}
|
||||
|
||||
if (type == &PyLong_Type) {
|
||||
return _PyLong_FormatWriter((_PyUnicodeWriter*)writer, obj, 10, 0);
|
||||
}
|
||||
|
||||
PyObject *str = PyObject_Str(obj);
|
||||
if (str == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str);
|
||||
Py_DECREF(str);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
PyUnicodeWriter_WriteRepr(PyUnicodeWriter *writer, PyObject *obj)
|
||||
{
|
||||
if (Py_TYPE(obj) == &PyLong_Type) {
|
||||
return _PyLong_FormatWriter((_PyUnicodeWriter*)writer, obj, 10, 0);
|
||||
}
|
||||
|
||||
PyObject *repr = PyObject_Repr(obj);
|
||||
if (repr == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, repr);
|
||||
Py_DECREF(repr);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
_PyUnicodeWriter_WriteSubstring(_PyUnicodeWriter *writer, PyObject *str,
|
||||
Py_ssize_t start, Py_ssize_t end)
|
||||
{
|
||||
assert(0 <= start);
|
||||
assert(end <= PyUnicode_GET_LENGTH(str));
|
||||
assert(start <= end);
|
||||
|
||||
if (start == 0 && end == PyUnicode_GET_LENGTH(str))
|
||||
return _PyUnicodeWriter_WriteStr(writer, str);
|
||||
|
||||
Py_ssize_t len = end - start;
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Py_UCS4 maxchar;
|
||||
if (PyUnicode_MAX_CHAR_VALUE(str) > writer->maxchar) {
|
||||
maxchar = _PyUnicode_FindMaxChar(str, start, end);
|
||||
}
|
||||
else {
|
||||
maxchar = writer->maxchar;
|
||||
}
|
||||
if (_PyUnicodeWriter_Prepare(writer, len, maxchar) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
_PyUnicode_FastCopyCharacters(writer->buffer, writer->pos,
|
||||
str, start, len);
|
||||
writer->pos += len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
PyUnicodeWriter_WriteSubstring(PyUnicodeWriter *writer, PyObject *str,
|
||||
Py_ssize_t start, Py_ssize_t end)
|
||||
{
|
||||
if (!PyUnicode_Check(str)) {
|
||||
PyErr_Format(PyExc_TypeError, "expect str, not %T", str);
|
||||
return -1;
|
||||
}
|
||||
if (start < 0 || start > end) {
|
||||
PyErr_Format(PyExc_ValueError, "invalid start argument");
|
||||
return -1;
|
||||
}
|
||||
if (end > PyUnicode_GET_LENGTH(str)) {
|
||||
PyErr_Format(PyExc_ValueError, "invalid end argument");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _PyUnicodeWriter_WriteSubstring((_PyUnicodeWriter*)writer, str,
|
||||
start, end);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
_PyUnicodeWriter_WriteASCIIString(_PyUnicodeWriter *writer,
|
||||
const char *ascii, Py_ssize_t len)
|
||||
{
|
||||
if (len == -1)
|
||||
len = strlen(ascii);
|
||||
|
||||
assert(ucs1lib_find_max_char((const Py_UCS1*)ascii, (const Py_UCS1*)ascii + len) < 128);
|
||||
|
||||
if (writer->buffer == NULL && !writer->overallocate) {
|
||||
PyObject *str;
|
||||
|
||||
str = _PyUnicode_FromASCII(ascii, len);
|
||||
if (str == NULL)
|
||||
return -1;
|
||||
|
||||
writer->readonly = 1;
|
||||
writer->buffer = str;
|
||||
_PyUnicodeWriter_Update(writer);
|
||||
writer->pos += len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_PyUnicodeWriter_Prepare(writer, len, 127) == -1)
|
||||
return -1;
|
||||
|
||||
switch (writer->kind)
|
||||
{
|
||||
case PyUnicode_1BYTE_KIND:
|
||||
{
|
||||
const Py_UCS1 *str = (const Py_UCS1 *)ascii;
|
||||
Py_UCS1 *data = writer->data;
|
||||
|
||||
memcpy(data + writer->pos, str, len);
|
||||
break;
|
||||
}
|
||||
case PyUnicode_2BYTE_KIND:
|
||||
{
|
||||
_PyUnicode_CONVERT_BYTES(
|
||||
Py_UCS1, Py_UCS2,
|
||||
ascii, ascii + len,
|
||||
(Py_UCS2 *)writer->data + writer->pos);
|
||||
break;
|
||||
}
|
||||
case PyUnicode_4BYTE_KIND:
|
||||
{
|
||||
_PyUnicode_CONVERT_BYTES(
|
||||
Py_UCS1, Py_UCS4,
|
||||
ascii, ascii + len,
|
||||
(Py_UCS4 *)writer->data + writer->pos);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Py_UNREACHABLE();
|
||||
}
|
||||
|
||||
writer->pos += len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
PyUnicodeWriter_WriteASCII(PyUnicodeWriter *writer,
|
||||
const char *str,
|
||||
Py_ssize_t size)
|
||||
{
|
||||
assert(writer != NULL);
|
||||
_Py_AssertHoldsTstate();
|
||||
|
||||
_PyUnicodeWriter *priv_writer = (_PyUnicodeWriter*)writer;
|
||||
return _PyUnicodeWriter_WriteASCIIString(priv_writer, str, size);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
PyUnicodeWriter_WriteUTF8(PyUnicodeWriter *writer,
|
||||
const char *str,
|
||||
Py_ssize_t size)
|
||||
{
|
||||
if (size < 0) {
|
||||
size = strlen(str);
|
||||
}
|
||||
|
||||
_PyUnicodeWriter *_writer = (_PyUnicodeWriter*)writer;
|
||||
Py_ssize_t old_pos = _writer->pos;
|
||||
int res = _PyUnicode_DecodeUTF8Writer(_writer, str, size,
|
||||
_Py_ERROR_STRICT, NULL, NULL);
|
||||
if (res < 0) {
|
||||
_writer->pos = old_pos;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
PyUnicodeWriter_DecodeUTF8Stateful(PyUnicodeWriter *writer,
|
||||
const char *string,
|
||||
Py_ssize_t length,
|
||||
const char *errors,
|
||||
Py_ssize_t *consumed)
|
||||
{
|
||||
if (length < 0) {
|
||||
length = strlen(string);
|
||||
}
|
||||
|
||||
_PyUnicodeWriter *_writer = (_PyUnicodeWriter*)writer;
|
||||
Py_ssize_t old_pos = _writer->pos;
|
||||
int res = _PyUnicode_DecodeUTF8Writer(_writer, string, length,
|
||||
_Py_ERROR_UNKNOWN, errors,
|
||||
consumed);
|
||||
if (res < 0) {
|
||||
_writer->pos = old_pos;
|
||||
if (consumed) {
|
||||
*consumed = 0;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
_PyUnicodeWriter_WriteLatin1String(_PyUnicodeWriter *writer,
|
||||
const char *str, Py_ssize_t len)
|
||||
{
|
||||
Py_UCS4 maxchar;
|
||||
|
||||
maxchar = ucs1lib_find_max_char((const Py_UCS1*)str, (const Py_UCS1*)str + len);
|
||||
if (_PyUnicodeWriter_Prepare(writer, len, maxchar) == -1)
|
||||
return -1;
|
||||
unicode_write_cstr(writer->buffer, writer->pos, str, len);
|
||||
writer->pos += len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PyObject *
|
||||
_PyUnicodeWriter_Finish(_PyUnicodeWriter *writer)
|
||||
{
|
||||
PyObject *str;
|
||||
|
||||
if (writer->pos == 0) {
|
||||
Py_CLEAR(writer->buffer);
|
||||
return _PyUnicode_GetEmpty();
|
||||
}
|
||||
|
||||
str = writer->buffer;
|
||||
writer->buffer = NULL;
|
||||
|
||||
if (writer->readonly) {
|
||||
assert(PyUnicode_GET_LENGTH(str) == writer->pos);
|
||||
return str;
|
||||
}
|
||||
|
||||
if (PyUnicode_GET_LENGTH(str) != writer->pos) {
|
||||
PyObject *str2;
|
||||
str2 = _PyUnicode_ResizeCompact(str, writer->pos);
|
||||
if (str2 == NULL) {
|
||||
Py_DECREF(str);
|
||||
return NULL;
|
||||
}
|
||||
str = str2;
|
||||
}
|
||||
|
||||
assert(_PyUnicode_CheckConsistency(str, 1));
|
||||
return _PyUnicode_Result(str);
|
||||
}
|
||||
|
||||
|
||||
PyObject*
|
||||
PyUnicodeWriter_Finish(PyUnicodeWriter *writer)
|
||||
{
|
||||
PyObject *str = _PyUnicodeWriter_Finish((_PyUnicodeWriter*)writer);
|
||||
assert(((_PyUnicodeWriter*)writer)->buffer == NULL);
|
||||
_Py_FREELIST_FREE(unicode_writers, writer, PyMem_Free);
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_PyUnicodeWriter_Dealloc(_PyUnicodeWriter *writer)
|
||||
{
|
||||
Py_CLEAR(writer->buffer);
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
*/
|
||||
|
||||
#include "Python.h"
|
||||
#include "pycore_unicodectype.h" // export _PyUnicode_IsXidStart(), _PyUnicode_IsXidContinue()
|
||||
|
||||
#define ALPHA_MASK 0x01
|
||||
#define DECIMAL_MASK 0x02
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -393,8 +393,23 @@ static PyGetSetDef union_properties[] = {
|
|||
{0}
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
union_nb_or(PyObject *a, PyObject *b)
|
||||
{
|
||||
unionbuilder ub;
|
||||
if (!unionbuilder_init(&ub, true)) {
|
||||
return NULL;
|
||||
}
|
||||
if (!unionbuilder_add_single(&ub, a) ||
|
||||
!unionbuilder_add_single(&ub, b)) {
|
||||
unionbuilder_finalize(&ub);
|
||||
return NULL;
|
||||
}
|
||||
return make_union(&ub);
|
||||
}
|
||||
|
||||
static PyNumberMethods union_as_number = {
|
||||
.nb_or = _Py_union_type_or, // Add __or__ function
|
||||
.nb_or = union_nb_or, // Add __or__ function
|
||||
};
|
||||
|
||||
static const char* const cls_attrs[] = {
|
||||
|
|
@ -474,11 +489,13 @@ _Py_union_from_tuple(PyObject *args)
|
|||
}
|
||||
if (PyTuple_CheckExact(args)) {
|
||||
if (!unionbuilder_add_tuple(&ub, args)) {
|
||||
unionbuilder_finalize(&ub);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!unionbuilder_add_single(&ub, args)) {
|
||||
unionbuilder_finalize(&ub);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue