Skip to content

Commit 7b20ab0

Browse files
committed
gh-111489: Add PyList_FromArrayMoveRef() function
Add new functions to create tuple and list from arrays: * PyTuple_FromArray(). * PyTuple_FromArrayMoveRef(). * PyList_FromArrayMoveRef(). Add tests on new functions.
1 parent 3251ba8 commit 7b20ab0

File tree

14 files changed

+252
-31
lines changed

14 files changed

+252
-31
lines changed

Doc/c-api/list.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,19 @@ List Objects
4343
setting all items to a real object with :c:func:`PyList_SetItem`.
4444
4545
46+
.. c:function:: PyObject* PyList_FromArrayMoveRef(PyObject **array, Py_ssize_t size)
47+
48+
Create a list of *size* items and move *array* :term:`strong references
49+
<strong reference>` to the new list.
50+
51+
* Return a new reference on success. *array* references become
52+
:term:`borrowed references <borrowed reference>`.
53+
* Set an exception and return ``NULL`` on error. *array* is left unchanged,
54+
the caller should clear *array* strong references.
55+
56+
.. versionadded:: 3.13
57+
58+
4659
.. c:function:: Py_ssize_t PyList_Size(PyObject *list)
4760
4861
.. index:: pair: built-in function; len

Doc/c-api/tuple.rst

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,30 @@ Tuple Objects
3636
Return a new tuple object of size *len*, or ``NULL`` on failure.
3737
3838
39+
.. c:function:: PyObject* PyTuple_FromArray(PyObject *const *array, Py_ssize_t size)
40+
41+
Create a tuple of *size* items and copy references from *array* to the new
42+
tuple.
43+
44+
* Return a new reference on success.
45+
* Set an exception and return NULL on error.
46+
47+
.. versionadded:: 3.13
48+
49+
50+
.. c:function:: PyObject* PyTuple_FromArrayMoveRef(PyObject **array, Py_ssize_t size)
51+
52+
Create a tuple of *size* items and move *array* :term:`strong references
53+
<strong reference>` to the new tuple.
54+
55+
* Return a new reference on success. *array* references become :term:`borrowed
56+
references <borrowed reference>`.
57+
* Set an exception and return ``NULL`` on error. *array* is left unchanged,
58+
the caller should clear *array* strong references.
59+
60+
.. versionadded:: 3.13
61+
62+
3963
.. c:function:: PyObject* PyTuple_Pack(Py_ssize_t n, ...)
4064
4165
Return a new tuple object of size *n*, or ``NULL`` on failure. The tuple values

Doc/whatsnew/3.13.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1269,6 +1269,14 @@ New Features
12691269
* Add :c:func:`Py_HashPointer` function to hash a pointer.
12701270
(Contributed by Victor Stinner in :gh:`111545`.)
12711271

1272+
* Add new functions to create :class:`tuple` and :class:`list` from arrays:
1273+
1274+
* :c:func:`PyTuple_FromArray`.
1275+
* :c:func:`PyTuple_FromArrayMoveRef`.
1276+
* :c:func:`PyList_FromArrayMoveRef`.
1277+
1278+
(Contributed by Victor Stinner in :gh:`111489`.)
1279+
12721280

12731281
Porting to Python 3.13
12741282
----------------------

Include/cpython/listobject.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,6 @@ PyList_SET_ITEM(PyObject *op, Py_ssize_t index, PyObject *value) {
4747

4848
PyAPI_FUNC(int) PyList_Extend(PyObject *self, PyObject *iterable);
4949
PyAPI_FUNC(int) PyList_Clear(PyObject *self);
50+
PyAPI_FUNC(PyObject*) PyList_FromArrayMoveRef(
51+
PyObject *const *array,
52+
Py_ssize_t size);

Include/cpython/tupleobject.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,10 @@ PyTuple_SET_ITEM(PyObject *op, Py_ssize_t index, PyObject *value) {
3636
}
3737
#define PyTuple_SET_ITEM(op, index, value) \
3838
PyTuple_SET_ITEM(_PyObject_CAST(op), (index), _PyObject_CAST(value))
39+
40+
PyAPI_FUNC(PyObject*) PyTuple_FromArray(
41+
PyObject *const *array,
42+
Py_ssize_t size);
43+
PyAPI_FUNC(PyObject*) PyTuple_FromArrayMoveRef(
44+
PyObject *const *array,
45+
Py_ssize_t size);

Include/internal/pycore_list.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,9 @@ typedef struct {
7777
PyListObject *it_seq; /* Set to NULL when iterator is exhausted */
7878
} _PyListIterObject;
7979

80-
extern PyObject *_PyList_FromArraySteal(PyObject *const *src, Py_ssize_t n);
80+
extern PyObject *_PyList_FromArraySteal(
81+
PyObject *const *array,
82+
Py_ssize_t size);
8183

8284
#ifdef __cplusplus
8385
}

Include/internal/pycore_tuple.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,11 @@ struct _Py_tuple_state {
6363

6464
#define _PyTuple_ITEMS(op) _Py_RVALUE(_PyTuple_CAST(op)->ob_item)
6565

66-
extern PyObject *_PyTuple_FromArray(PyObject *const *, Py_ssize_t);
67-
extern PyObject *_PyTuple_FromArraySteal(PyObject *const *, Py_ssize_t);
66+
// Alias for backward compatibility
67+
#define _PyTuple_FromArray PyTuple_FromArray
68+
extern PyObject *_PyTuple_FromArraySteal(
69+
PyObject *const *array,
70+
Py_ssize_t size);
6871

6972

7073
typedef struct {

Lib/test/test_capi/test_list.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,3 +342,11 @@ def test_list_extend(self):
342342

343343
# CRASHES list_extend(NULL, [])
344344
# CRASHES list_extend([], NULL)
345+
346+
def test_list_fromarraymoveref(self):
347+
# Test PyList_FromArrayMoveRef()
348+
list_fromarraymoveref = _testcapi.list_fromarraymoveref
349+
350+
lst = [object() for _ in range(5)]
351+
copy = list_fromarraymoveref(lst)
352+
self.assertEqual(copy, lst)

Lib/test/test_capi/test_tuple.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import unittest
2+
from test.support import import_helper
3+
_testcapi = import_helper.import_module('_testcapi')
4+
5+
6+
class CAPITest(unittest.TestCase):
7+
def test_tuple_fromarray(self):
8+
# Test PyTuple_FromArray()
9+
tuple_fromarray = _testcapi.tuple_fromarraymoveref
10+
11+
tup = tuple(object() for _ in range(5))
12+
copy = tuple_fromarray(tup)
13+
self.assertEqual(copy, tup)
14+
15+
def test_tuple_fromarraymoveref(self):
16+
# Test PyTuple_FromArrayMoveRef()
17+
tuple_fromarraymoveref = _testcapi.tuple_fromarraymoveref
18+
19+
tup = tuple(object() for _ in range(5))
20+
copy = tuple_fromarraymoveref(tup)
21+
self.assertEqual(copy, tup)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Add new functions to create :class:`tuple` and :class:`list` from arrays:
2+
3+
* :c:func:`PyTuple_FromArray`.
4+
* :c:func:`PyTuple_FromArrayMoveRef`.
5+
* :c:func:`PyList_FromArrayMoveRef`.
6+
7+
Patch by Victor Stinner.

0 commit comments

Comments
 (0)