Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Include/internal/pycore_tupleobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vstinner Was there a reason to export this as an API function, iso. using the extern keyword?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only started to no longer export symbols by using "extern" recently. Previously, I kept the habit of exporting symbols using PyAPI_FUNC/PyAPI_DATA. You can propose a PR to use extern.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. Would that affect the Stable API, @encukou?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, nothing in Include/internal/ is in the limited API.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, thanks Petr.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, see GH-26352 and bpo-44231.


#ifdef __cplusplus
}
Expand Down
29 changes: 5 additions & 24 deletions Modules/itertoolsmodule.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

#define PY_SSIZE_T_CLEAN
#include "Python.h"
#include "pycore_tupleobject.h"
#include "structmember.h"

/* Itertools module written and maintained
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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<r ; 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
Expand Down Expand Up @@ -2910,15 +2901,10 @@ cwr_next(cwrobject *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<r ; 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 CPython's
Expand Down Expand Up @@ -3258,15 +3244,10 @@ permutations_next(permutationsobject *po)
/* 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;
po->result = result;
for (i=0; i<r ; 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 */
Expand Down
30 changes: 2 additions & 28 deletions Objects/call.c
Original file line number Diff line number Diff line change
Expand Up @@ -1276,45 +1276,19 @@ PyObject_CallFunctionObjArgs(PyObject *callable, ...)
_Py_NO_INLINE PyObject *
_PyStack_AsTuple(PyObject *const *stack, Py_ssize_t nargs)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vstinner
Does it make sense to have _PyStack_AsTuple() and _PyStack_AsTupleSlice() after adding PyTuple_FromArray()? Might make sense to remove them or replace with macros.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can remove _PyStack_AsTuple, but please do that in a second PR (once this one is merged, if it's merged ;-)).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would remove both _PyStack_AsTuple and _PyStack_AsTupleSlice. The former is just an alias of _PyTuple_FromArray, and the latter is an alias with trivial arguments transformation, and is used only once.

{
PyObject *args;
Py_ssize_t i;

args = PyTuple_New(nargs);
if (args == NULL) {
return NULL;
}

for (i=0; i < nargs; i++) {
PyObject *item = stack[i];
Py_INCREF(item);
PyTuple_SET_ITEM(args, i, item);
}
return args;
return _PyTuple_FromArray(stack, nargs);
}


PyObject*
_PyStack_AsTupleSlice(PyObject *const *stack, Py_ssize_t nargs,
Py_ssize_t start, Py_ssize_t end)
{
PyObject *args;
Py_ssize_t i;

assert(0 <= start);
assert(end <= nargs);
assert(start <= end);

args = PyTuple_New(end - start);
if (args == NULL) {
return NULL;
}

for (i=start; i < end; i++) {
PyObject *item = stack[i];
Py_INCREF(item);
PyTuple_SET_ITEM(args, i - start, item);
}
return args;
return _PyTuple_FromArray(stack + start, end - start);
}


Expand Down
18 changes: 2 additions & 16 deletions Objects/listobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "Python.h"
#include "pycore_object.h"
#include "pycore_pystate.h"
#include "pycore_tupleobject.h"
#include "pycore_accu.h"

#ifdef STDC_HEADERS
Expand Down Expand Up @@ -2501,26 +2502,11 @@ PyList_Reverse(PyObject *v)
PyObject *
PyList_AsTuple(PyObject *v)
{
PyObject *w;
PyObject **p, **q;
Py_ssize_t n;
if (v == NULL || !PyList_Check(v)) {
PyErr_BadInternalCall();
return NULL;
}
n = Py_SIZE(v);
w = PyTuple_New(n);
if (w == NULL)
return NULL;
p = ((PyTupleObject *)w)->ob_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]
Expand Down
10 changes: 3 additions & 7 deletions Objects/structseq.c
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -250,20 +251,15 @@ 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;

dict = PyDict_New();
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;
Expand Down
33 changes: 17 additions & 16 deletions Objects/tupleobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -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 *
Expand Down
7 changes: 1 addition & 6 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -3772,16 +3772,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 */
Expand Down