summaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/Objects/structseq.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/tools/python3/Objects/structseq.c')
-rw-r--r--contrib/tools/python3/Objects/structseq.c163
1 files changed, 133 insertions, 30 deletions
diff --git a/contrib/tools/python3/Objects/structseq.c b/contrib/tools/python3/Objects/structseq.c
index 246d4c7630c..efcadf50078 100644
--- a/contrib/tools/python3/Objects/structseq.c
+++ b/contrib/tools/python3/Objects/structseq.c
@@ -8,11 +8,11 @@
*/
#include "Python.h"
-#include "pycore_tuple.h" // _PyTuple_FromArray()
+#include "pycore_initconfig.h" // _PyStatus_OK()
+#include "pycore_modsupport.h" // _PyArg_NoPositional()
#include "pycore_object.h" // _PyObject_GC_TRACK()
-#include "structmember.h" // PyMemberDef
#include "pycore_structseq.h" // PyStructSequence_InitType()
-#include "pycore_initconfig.h" // _PyStatus_OK()
+#include "pycore_tuple.h" // _PyTuple_FromArray()
static const char visible_length_key[] = "n_sequence_fields";
static const char real_length_key[] = "n_fields";
@@ -82,15 +82,28 @@ PyStructSequence_New(PyTypeObject *type)
}
void
-PyStructSequence_SetItem(PyObject* op, Py_ssize_t i, PyObject* v)
+PyStructSequence_SetItem(PyObject *op, Py_ssize_t index, PyObject *value)
{
- PyStructSequence_SET_ITEM(op, i, v);
+ PyTupleObject *tuple = _PyTuple_CAST(op);
+ assert(0 <= index);
+#ifndef NDEBUG
+ Py_ssize_t n_fields = REAL_SIZE(op);
+ assert(n_fields >= 0);
+ assert(index < n_fields);
+#endif
+ tuple->ob_item[index] = value;
}
PyObject*
-PyStructSequence_GetItem(PyObject* op, Py_ssize_t i)
+PyStructSequence_GetItem(PyObject *op, Py_ssize_t index)
{
- return PyStructSequence_GET_ITEM(op, i);
+ assert(0 <= index);
+#ifndef NDEBUG
+ Py_ssize_t n_fields = REAL_SIZE(op);
+ assert(n_fields >= 0);
+ assert(index < n_fields);
+#endif
+ return PyTuple_GET_ITEM(op, index);
}
@@ -146,7 +159,6 @@ static PyObject *
structseq_new_impl(PyTypeObject *type, PyObject *arg, PyObject *dict)
/*[clinic end generated code: output=baa082e788b171da input=90532511101aa3fb]*/
{
- PyObject *ob;
PyStructSequence *res = NULL;
Py_ssize_t len, min_len, max_len, i, n_unnamed_fields;
@@ -215,22 +227,34 @@ structseq_new_impl(PyTypeObject *type, PyObject *arg, PyObject *dict)
res->ob_item[i] = Py_NewRef(v);
}
Py_DECREF(arg);
- for (; i < max_len; ++i) {
- if (dict == NULL) {
- ob = Py_None;
- }
- else {
- ob = _PyDict_GetItemStringWithError(dict,
- type->tp_members[i-n_unnamed_fields].name);
+ if (dict != NULL && PyDict_GET_SIZE(dict) > 0) {
+ Py_ssize_t n_found_keys = 0;
+ for (i = len; i < max_len; ++i) {
+ PyObject *ob = NULL;
+ const char *name = type->tp_members[i - n_unnamed_fields].name;
+ if (PyDict_GetItemStringRef(dict, name, &ob) < 0) {
+ Py_DECREF(res);
+ return NULL;
+ }
if (ob == NULL) {
- if (PyErr_Occurred()) {
- Py_DECREF(res);
- return NULL;
- }
- ob = Py_None;
+ ob = Py_NewRef(Py_None);
+ }
+ else {
+ ++n_found_keys;
}
+ res->ob_item[i] = ob;
+ }
+ if (PyDict_GET_SIZE(dict) > n_found_keys) {
+ PyErr_Format(PyExc_TypeError,
+ "%.500s() got duplicate or unexpected field name(s)",
+ type->tp_name);
+ Py_DECREF(res);
+ return NULL;
+ }
+ } else {
+ for (i = len; i < max_len; ++i) {
+ res->ob_item[i] = Py_NewRef(Py_None);
}
- res->ob_item[i] = Py_NewRef(ob);
}
_PyObject_GC_TRACK(res);
@@ -298,7 +322,7 @@ structseq_repr(PyStructSequence *obj)
goto error;
}
- PyObject *value = PyStructSequence_GET_ITEM(obj, i);
+ PyObject *value = PyStructSequence_GetItem((PyObject*)obj, i);
assert(value != NULL);
PyObject *repr = PyObject_Repr(value);
if (repr == NULL) {
@@ -367,9 +391,84 @@ error:
return NULL;
}
+
+static PyObject *
+structseq_replace(PyStructSequence *self, PyObject *args, PyObject *kwargs)
+{
+ PyStructSequence *result = NULL;
+ Py_ssize_t n_fields, n_unnamed_fields, i;
+
+ if (!_PyArg_NoPositional("__replace__", args)) {
+ return NULL;
+ }
+
+ n_fields = REAL_SIZE(self);
+ if (n_fields < 0) {
+ return NULL;
+ }
+ n_unnamed_fields = UNNAMED_FIELDS(self);
+ if (n_unnamed_fields < 0) {
+ return NULL;
+ }
+ if (n_unnamed_fields > 0) {
+ PyErr_Format(PyExc_TypeError,
+ "__replace__() is not supported for %.500s "
+ "because it has unnamed field(s)",
+ Py_TYPE(self)->tp_name);
+ return NULL;
+ }
+
+ result = (PyStructSequence *) PyStructSequence_New(Py_TYPE(self));
+ if (!result) {
+ return NULL;
+ }
+
+ if (kwargs != NULL) {
+ // We do not support types with unnamed fields, so we can iterate over
+ // i >= n_visible_fields case without slicing with (i - n_unnamed_fields).
+ for (i = 0; i < n_fields; ++i) {
+ PyObject *ob;
+ if (PyDict_PopString(kwargs, Py_TYPE(self)->tp_members[i].name,
+ &ob) < 0) {
+ goto error;
+ }
+ if (ob == NULL) {
+ ob = Py_NewRef(self->ob_item[i]);
+ }
+ result->ob_item[i] = ob;
+ }
+ // Check if there are any unexpected fields.
+ if (PyDict_GET_SIZE(kwargs) > 0) {
+ PyObject *names = PyDict_Keys(kwargs);
+ if (names) {
+ PyErr_Format(PyExc_TypeError, "Got unexpected field name(s): %R", names);
+ Py_DECREF(names);
+ }
+ goto error;
+ }
+ }
+ else
+ {
+ // Just create a copy of the original.
+ for (i = 0; i < n_fields; ++i) {
+ result->ob_item[i] = Py_NewRef(self->ob_item[i]);
+ }
+ }
+
+ _PyObject_GC_TRACK(result);
+ return (PyObject *)result;
+
+error:
+ Py_DECREF(result);
+ return NULL;
+}
+
static PyMethodDef structseq_methods[] = {
{"__reduce__", (PyCFunction)structseq_reduce, METH_NOARGS, NULL},
- {NULL, NULL}
+ {"__replace__", _PyCFunction_CAST(structseq_replace), METH_VARARGS | METH_KEYWORDS,
+ PyDoc_STR("__replace__($self, /, **changes)\n--\n\n"
+ "Return a copy of the structure with new values for the specified fields.")},
+ {NULL, NULL} // sentinel
};
static Py_ssize_t
@@ -463,10 +562,10 @@ initialize_members(PyStructSequence_Desc *desc,
/* The names and docstrings in these MemberDefs are statically */
/* allocated so it is expected that they'll outlive the MemberDef */
members[k].name = desc->fields[i].name;
- members[k].type = T_OBJECT;
+ members[k].type = _Py_T_OBJECT;
members[k].offset = offsetof(PyStructSequence, ob_item)
+ i * sizeof(PyObject*);
- members[k].flags = READONLY;
+ members[k].flags = Py_READONLY;
members[k].doc = desc->fields[i].doc;
k++;
}
@@ -522,6 +621,9 @@ _PyStructSequence_InitBuiltinWithFlags(PyInterpreterState *interp,
PyStructSequence_Desc *desc,
unsigned long tp_flags)
{
+ if (Py_TYPE(type) == NULL) {
+ Py_SET_TYPE(type, &PyType_Type);
+ }
Py_ssize_t n_unnamed_members;
Py_ssize_t n_members = count_members(desc, &n_unnamed_members);
PyMemberDef *members = NULL;
@@ -537,7 +639,7 @@ _PyStructSequence_InitBuiltinWithFlags(PyInterpreterState *interp,
}
initialize_static_fields(type, desc, members, n_members, tp_flags);
- _Py_SetImmortal(type);
+ _Py_SetImmortal((PyObject *)type);
}
#ifndef NDEBUG
else {
@@ -579,9 +681,10 @@ PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc)
Py_ssize_t n_members, n_unnamed_members;
#ifdef Py_TRACE_REFS
- /* if the type object was chained, unchain it first
+ /* if the type object was traced, remove it first
before overwriting its storage */
- if (type->ob_base.ob_base._ob_next) {
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ if (_PyRefchain_IsTraced(interp, (PyObject *)type)) {
_Py_ForgetReference((PyObject *)type);
}
#endif
@@ -623,7 +726,7 @@ _PyStructSequence_FiniBuiltin(PyInterpreterState *interp, PyTypeObject *type)
assert(type->tp_name != NULL);
assert(type->tp_base == &PyTuple_Type);
assert((type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN));
- assert(_Py_IsImmortal(type));
+ assert(_Py_IsImmortalLoose(type));
// Cannot delete a type if it still has subclasses
if (_PyType_HasSubclasses(type)) {
@@ -631,7 +734,7 @@ _PyStructSequence_FiniBuiltin(PyInterpreterState *interp, PyTypeObject *type)
return;
}
- _PyStaticType_Dealloc(interp, type);
+ _PyStaticType_FiniBuiltin(interp, type);
if (_Py_IsMainInterpreter(interp)) {
// Undo _PyStructSequence_InitBuiltinWithFlags().