From 234531b4462b20d668762bd78406fd2ebab129c9 Mon Sep 17 00:00:00 2001 From: Sergey Fedoseev Date: Mon, 25 Feb 2019 21:59:12 +0500 Subject: [PATCH] bpo-36030: Add _PyTuple_FromArray() function (GH-11954) --- Include/internal/pycore_tupleobject.h | 1 + Modules/itertoolsmodule.c | 29 ++++------------------- Objects/call.c | 30 ++---------------------- Objects/listobject.c | 18 ++------------- Objects/structseq.c | 10 +++----- Objects/tupleobject.c | 33 ++++++++++++++------------- Python/ceval.c | 7 +----- 7 files changed, 31 insertions(+), 97 deletions(-) diff --git a/Include/internal/pycore_tupleobject.h b/Include/internal/pycore_tupleobject.h index fdd74146766..d0c5b620d35 100644 --- a/Include/internal/pycore_tupleobject.h +++ b/Include/internal/pycore_tupleobject.h @@ -11,6 +11,7 @@ extern "C" { #include "tupleobject.h" #define _PyTuple_ITEMS(op) (_PyTuple_CAST(op)->ob_item) +PyAPI_FUNC(PyObject *) _PyTuple_FromArray(PyObject *const *, Py_ssize_t); #ifdef __cplusplus } diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index c589dd10d49..536f7fa6253 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -1,6 +1,7 @@ #define PY_SSIZE_T_CLEAN #include "Python.h" +#include "pycore_tupleobject.h" #include "structmember.h" /* Itertools module written and maintained @@ -2239,15 +2240,10 @@ product_next(productobject *lz) /* Copy the previous result tuple or re-use it if available */ if (Py_REFCNT(result) > 1) { PyObject *old_result = result; - result = PyTuple_New(npools); + result = _PyTuple_FromArray(_PyTuple_ITEMS(old_result), npools); if (result == NULL) goto empty; lz->result = result; - for (i=0; i < npools; i++) { - elem = PyTuple_GET_ITEM(old_result, i); - Py_INCREF(elem); - PyTuple_SET_ITEM(result, i, elem); - } Py_DECREF(old_result); } /* Now, we've got the only copy so we can update it in-place */ @@ -2569,15 +2565,10 @@ combinations_next(combinationsobject *co) /* Copy the previous result tuple or re-use it if available */ if (Py_REFCNT(result) > 1) { PyObject *old_result = result; - result = PyTuple_New(r); + result = _PyTuple_FromArray(_PyTuple_ITEMS(old_result), r); if (result == NULL) goto empty; co->result = result; - for (i=0; i 1) { PyObject *old_result = result; - result = PyTuple_New(r); + result = _PyTuple_FromArray(_PyTuple_ITEMS(old_result), r); if (result == NULL) goto empty; co->result = result; - for (i=0; i 1) { PyObject *old_result = result; - result = PyTuple_New(r); + result = _PyTuple_FromArray(_PyTuple_ITEMS(old_result), r); if (result == NULL) goto empty; po->result = result; - for (i=0; iob_item; - q = ((PyListObject *)v)->ob_item; - while (--n >= 0) { - Py_INCREF(*q); - *p = *q; - p++; - q++; - } - return w; + return _PyTuple_FromArray(((PyListObject *)v)->ob_item, Py_SIZE(v)); } /*[clinic input] diff --git a/Objects/structseq.c b/Objects/structseq.c index cf94155f18f..56b06c707f8 100644 --- a/Objects/structseq.c +++ b/Objects/structseq.c @@ -2,6 +2,7 @@ and posixmodule for example uses. */ #include "Python.h" +#include "pycore_tupleobject.h" #include "structmember.h" static const char visible_length_key[] = "n_sequence_fields"; @@ -250,7 +251,7 @@ structseq_reduce(PyStructSequence* self, PyObject *Py_UNUSED(ignored)) n_fields = REAL_SIZE(self); n_visible_fields = VISIBLE_SIZE(self); n_unnamed_fields = UNNAMED_FIELDS(self); - tup = PyTuple_New(n_visible_fields); + tup = _PyTuple_FromArray(self->ob_item, n_visible_fields); if (!tup) goto error; @@ -258,12 +259,7 @@ structseq_reduce(PyStructSequence* self, PyObject *Py_UNUSED(ignored)) if (!dict) goto error; - for (i = 0; i < n_visible_fields; i++) { - Py_INCREF(self->ob_item[i]); - PyTuple_SET_ITEM(tup, i, self->ob_item[i]); - } - - for (; i < n_fields; i++) { + for (i = n_visible_fields; i < n_fields; i++) { const char *n = Py_TYPE(self)->tp_members[i-n_unnamed_fields].name; if (PyDict_SetItemString(dict, n, self->ob_item[i]) < 0) goto error; diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index 9cf3f3dd66e..75d2bf95e66 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -419,14 +419,26 @@ tupleitem(PyTupleObject *a, Py_ssize_t i) return a->ob_item[i]; } +PyObject * +_PyTuple_FromArray(PyObject *const *src, Py_ssize_t n) +{ + PyTupleObject *tuple = (PyTupleObject *)PyTuple_New(n); + if (tuple == NULL) { + return NULL; + } + PyObject **dst = tuple->ob_item; + for (Py_ssize_t i = 0; i < n; i++) { + PyObject *item = src[i]; + Py_INCREF(item); + dst[i] = item; + } + return (PyObject *)tuple; +} + static PyObject * tupleslice(PyTupleObject *a, Py_ssize_t ilow, Py_ssize_t ihigh) { - PyTupleObject *np; - PyObject **src, **dest; - Py_ssize_t i; - Py_ssize_t len; if (ilow < 0) ilow = 0; if (ihigh > Py_SIZE(a)) @@ -437,18 +449,7 @@ tupleslice(PyTupleObject *a, Py_ssize_t ilow, Py_INCREF(a); return (PyObject *)a; } - len = ihigh - ilow; - np = (PyTupleObject *)PyTuple_New(len); - if (np == NULL) - return NULL; - src = a->ob_item + ilow; - dest = np->ob_item; - for (i = 0; i < len; i++) { - PyObject *v = src[i]; - Py_INCREF(v); - dest[i] = v; - } - return (PyObject *)np; + return _PyTuple_FromArray(a->ob_item + ilow, ihigh - ilow); } PyObject * diff --git a/Python/ceval.c b/Python/ceval.c index ff8386352ba..68c1617c78f 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3831,16 +3831,11 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals, /* Pack other positional arguments into the *args argument */ if (co->co_flags & CO_VARARGS) { - u = PyTuple_New(argcount - n); + u = _PyTuple_FromArray(args + n, argcount - n); if (u == NULL) { goto fail; } SETLOCAL(total_args, u); - for (i = n; i < argcount; i++) { - x = args[i]; - Py_INCREF(x); - PyTuple_SET_ITEM(u, i-n, x); - } } /* Handle keyword arguments passed as two strided arrays */