https://github.com/python/cpython/commit/d2d24e46d31821fb2f0f4368fa27057e9859a918
commit: d2d24e46d31821fb2f0f4368fa27057e9859a918
branch: main
author: Neko Asakura <[email protected]>
committer: kumaraditya303 <[email protected]>
date: 2026-05-08T11:12:20Z
summary:
gh-100239: expose `sq_repeat` helpers for `BINARY_OP_EXTEND` (#148791)
files:
M Include/internal/pycore_bytesobject.h
M Include/internal/pycore_tuple.h
M Include/internal/pycore_unicodeobject.h
M Modules/arraymodule.c
M Objects/bytearrayobject.c
M Objects/bytesobject.c
M Objects/tupleobject.c
M Objects/unicodeobject.c
M Python/specialize.c
diff --git a/Include/internal/pycore_bytesobject.h
b/Include/internal/pycore_bytesobject.h
index 177e6d10134adb..27a7a46152f57b 100644
--- a/Include/internal/pycore_bytesobject.h
+++ b/Include/internal/pycore_bytesobject.h
@@ -62,9 +62,11 @@ _PyBytes_ReverseFind(const char *haystack, Py_ssize_t
len_haystack,
//
// Export for 'array' shared extension.
PyAPI_FUNC(void)
-_PyBytes_Repeat(char* dest, Py_ssize_t len_dest,
+_PyBytes_RepeatBuffer(char* dest, Py_ssize_t len_dest,
const char* src, Py_ssize_t len_src);
+PyAPI_FUNC(PyObject *) _PyBytes_Repeat(PyObject *self, Py_ssize_t n);
+
/* _PyBytesObject_SIZE gives the basic size of a bytes object; any memory
allocation
for a bytes object of length n should request PyBytesObject_SIZE + n bytes.
diff --git a/Include/internal/pycore_tuple.h b/Include/internal/pycore_tuple.h
index bf80f96396ea4a..e294b16b3df60f 100644
--- a/Include/internal/pycore_tuple.h
+++ b/Include/internal/pycore_tuple.h
@@ -29,6 +29,7 @@ PyAPI_FUNC(PyObject
*)_PyTuple_FromStackRefStealOnSuccess(const union _PyStackRe
PyAPI_FUNC(PyObject *)_PyTuple_FromArraySteal(PyObject *const *, Py_ssize_t);
PyAPI_FUNC(PyObject *) _PyTuple_BinarySlice(PyObject *, PyObject *, PyObject
*);
PyAPI_FUNC(PyObject *) _PyTuple_Concat(PyObject *, PyObject *);
+PyAPI_FUNC(PyObject *) _PyTuple_Repeat(PyObject *self, Py_ssize_t n);
PyAPI_FUNC(PyObject *) _PyTuple_FromPair(PyObject *, PyObject *);
PyAPI_FUNC(PyObject *) _PyTuple_FromPairSteal(PyObject *, PyObject *);
diff --git a/Include/internal/pycore_unicodeobject.h
b/Include/internal/pycore_unicodeobject.h
index 74d84052a2bb2b..75d5068f815b91 100644
--- a/Include/internal/pycore_unicodeobject.h
+++ b/Include/internal/pycore_unicodeobject.h
@@ -33,6 +33,7 @@ extern PyObject* _PyUnicode_ResizeCompact(
Py_ssize_t length);
extern PyObject* _PyUnicode_GetEmpty(void);
PyAPI_FUNC(PyObject*) _PyUnicode_BinarySlice(PyObject *, PyObject *, PyObject
*);
+PyAPI_FUNC(PyObject *) _PyUnicode_Repeat(PyObject *str, Py_ssize_t len);
/* Generic helper macro to convert characters of different types.
diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c
index 472c59ea8c9882..646b73bd4af7db 100644
--- a/Modules/arraymodule.c
+++ b/Modules/arraymodule.c
@@ -8,7 +8,7 @@
#endif
#include "Python.h"
-#include "pycore_bytesobject.h" // _PyBytes_Repeat
+#include "pycore_bytesobject.h" // _PyBytes_RepeatBuffer
#include "pycore_call.h" // _PyObject_CallMethod()
#include "pycore_ceval.h" // _PyEval_GetBuiltin()
#include "pycore_floatobject.h" // _PY_FLOAT_BIG_ENDIAN
@@ -1147,7 +1147,7 @@ array_repeat(PyObject *op, Py_ssize_t n)
const Py_ssize_t oldbytes = array_length * a->ob_descr->itemsize;
const Py_ssize_t newbytes = oldbytes * n;
- _PyBytes_Repeat(np->ob_item, newbytes, a->ob_item, oldbytes);
+ _PyBytes_RepeatBuffer(np->ob_item, newbytes, a->ob_item, oldbytes);
return (PyObject *)np;
}
@@ -1304,7 +1304,7 @@ array_inplace_repeat(PyObject *op, Py_ssize_t n)
if (array_resize(self, n * array_size) == -1)
return NULL;
- _PyBytes_Repeat(self->ob_item, n*size, self->ob_item, size);
+ _PyBytes_RepeatBuffer(self->ob_item, n*size, self->ob_item, size);
}
return Py_NewRef(self);
}
diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c
index c583193b5a252c..e698d260795480 100644
--- a/Objects/bytearrayobject.c
+++ b/Objects/bytearrayobject.c
@@ -402,7 +402,7 @@ bytearray_repeat_lock_held(PyObject *op, Py_ssize_t count)
PyByteArrayObject* result = (PyByteArrayObject
*)PyByteArray_FromStringAndSize(NULL, size);
const char* buf = PyByteArray_AS_STRING(self);
if (result != NULL && size != 0) {
- _PyBytes_Repeat(result->ob_bytes, size, buf, mysize);
+ _PyBytes_RepeatBuffer(result->ob_bytes, size, buf, mysize);
}
return (PyObject *)result;
}
@@ -439,7 +439,7 @@ bytearray_irepeat_lock_held(PyObject *op, Py_ssize_t count)
}
char* buf = PyByteArray_AS_STRING(self);
- _PyBytes_Repeat(buf, size, buf, mysize);
+ _PyBytes_RepeatBuffer(buf, size, buf, mysize);
return Py_NewRef(self);
}
diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c
index 8a9d1b133affb3..cd8417e2583916 100644
--- a/Objects/bytesobject.c
+++ b/Objects/bytesobject.c
@@ -3,7 +3,7 @@
#include "Python.h"
#include "pycore_abstract.h" // _PyIndex_Check()
#include "pycore_bytes_methods.h" // _Py_bytes_startswith()
-#include "pycore_bytesobject.h" // _PyBytes_Find(), _PyBytes_Repeat()
+#include "pycore_bytesobject.h" // _PyBytes_Find(), _PyBytes_RepeatBuffer()
#include "pycore_call.h" // _PyObject_CallNoArgs()
#include "pycore_ceval.h" // _PyEval_GetBuiltin()
#include "pycore_format.h" // F_LJUST
@@ -1581,8 +1581,8 @@ _PyBytes_Concat(PyObject *a, PyObject *b)
return result;
}
-static PyObject *
-bytes_repeat(PyObject *self, Py_ssize_t n)
+PyObject *
+_PyBytes_Repeat(PyObject *self, Py_ssize_t n)
{
PyBytesObject *a = _PyBytes_CAST(self);
if (n < 0)
@@ -1613,7 +1613,7 @@ bytes_repeat(PyObject *self, Py_ssize_t n)
set_ob_shash(op, -1);
op->ob_sval[size] = '\0';
- _PyBytes_Repeat(op->ob_sval, size, a->ob_sval, Py_SIZE(a));
+ _PyBytes_RepeatBuffer(op->ob_sval, size, a->ob_sval, Py_SIZE(a));
return (PyObject *) op;
}
@@ -1805,7 +1805,7 @@ bytes_buffer_getbuffer(PyObject *op, Py_buffer *view, int
flags)
static PySequenceMethods bytes_as_sequence = {
bytes_length, /*sq_length*/
_PyBytes_Concat, /*sq_concat*/
- bytes_repeat, /*sq_repeat*/
+ _PyBytes_Repeat, /*sq_repeat*/
bytes_item, /*sq_item*/
0, /*sq_slice*/
0, /*sq_ass_item*/
@@ -3555,7 +3555,7 @@ bytes_iter(PyObject *seq)
void
-_PyBytes_Repeat(char* dest, Py_ssize_t len_dest,
+_PyBytes_RepeatBuffer(char* dest, Py_ssize_t len_dest,
const char* src, Py_ssize_t len_src)
{
if (len_dest == 0) {
diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c
index 753c270f525976..94230002427546 100644
--- a/Objects/tupleobject.c
+++ b/Objects/tupleobject.c
@@ -594,8 +594,8 @@ _PyTuple_Concat(PyObject *aa, PyObject *bb)
return (PyObject *)np;
}
-static PyObject *
-tuple_repeat(PyObject *self, Py_ssize_t n)
+PyObject *
+_PyTuple_Repeat(PyObject *self, Py_ssize_t n)
{
PyTupleObject *a = _PyTuple_CAST(self);
const Py_ssize_t input_size = Py_SIZE(a);
@@ -865,7 +865,7 @@ tuple_subtype_new(PyTypeObject *type, PyObject *iterable)
static PySequenceMethods tuple_as_sequence = {
tuple_length, /* sq_length */
_PyTuple_Concat, /* sq_concat */
- tuple_repeat, /* sq_repeat */
+ _PyTuple_Repeat, /* sq_repeat */
tuple_item, /* sq_item */
0, /* sq_slice */
0, /* sq_ass_item */
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index 9aee7120c811de..5c97efd6838ef3 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -41,7 +41,7 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
#include "Python.h"
#include "pycore_abstract.h" // _PyIndex_Check()
#include "pycore_bytes_methods.h" // _Py_bytes_lower()
-#include "pycore_bytesobject.h" // _PyBytes_Repeat()
+#include "pycore_bytesobject.h" // _PyBytes_RepeatBuffer()
#include "pycore_ceval.h" // _PyEval_GetBuiltin()
#include "pycore_codecs.h" // _PyCodec_Lookup()
#include "pycore_critical_section.h" // Py_*_CRITICAL_SECTION_SEQUENCE_FAST
@@ -12502,8 +12502,8 @@ unicode_rstrip_impl(PyObject *self, PyObject *chars)
}
-static PyObject*
-unicode_repeat(PyObject *str, Py_ssize_t len)
+PyObject *
+_PyUnicode_Repeat(PyObject *str, Py_ssize_t len)
{
PyObject *u;
Py_ssize_t nchars, n;
@@ -12548,7 +12548,7 @@ unicode_repeat(PyObject *str, Py_ssize_t len)
else {
Py_ssize_t char_size = PyUnicode_KIND(str);
char *to = (char *) PyUnicode_DATA(u);
- _PyBytes_Repeat(to, nchars * char_size, PyUnicode_DATA(str),
+ _PyBytes_RepeatBuffer(to, nchars * char_size, PyUnicode_DATA(str),
PyUnicode_GET_LENGTH(str) * char_size);
}
@@ -13734,7 +13734,7 @@ static PyNumberMethods unicode_as_number = {
static PySequenceMethods unicode_as_sequence = {
unicode_length, /* sq_length */
PyUnicode_Concat, /* sq_concat */
- unicode_repeat, /* sq_repeat */
+ _PyUnicode_Repeat, /* sq_repeat */
unicode_getitem, /* sq_item */
0, /* sq_slice */
0, /* sq_ass_item */
diff --git a/Python/specialize.c b/Python/specialize.c
index 459e69de5709b8..2ff0a9d0072cec 100644
--- a/Python/specialize.c
+++ b/Python/specialize.c
@@ -2124,55 +2124,23 @@ is_compactlong(PyObject *v)
_PyLong_IsCompact((PyLongObject *)v);
}
-/* sequence * int helpers: bypass PyNumber_Multiply dispatch overhead
- by calling sq_repeat directly with PyLong_AsSsize_t. */
-
-static inline PyObject *
-seq_int_multiply(PyObject *seq, PyObject *n,
- ssizeargfunc repeat)
-{
- Py_ssize_t count = PyLong_AsSsize_t(n);
- if (count == -1 && PyErr_Occurred()) {
- return NULL;
- }
- return repeat(seq, count);
-}
-
-static PyObject *
-str_int_multiply(PyObject *lhs, PyObject *rhs)
-{
- return seq_int_multiply(lhs, rhs,
PyUnicode_Type.tp_as_sequence->sq_repeat);
-}
-
-static PyObject *
-int_str_multiply(PyObject *lhs, PyObject *rhs)
-{
- return seq_int_multiply(rhs, lhs,
PyUnicode_Type.tp_as_sequence->sq_repeat);
-}
-
-static PyObject *
-bytes_int_multiply(PyObject *lhs, PyObject *rhs)
-{
- return seq_int_multiply(lhs, rhs, PyBytes_Type.tp_as_sequence->sq_repeat);
-}
-
-static PyObject *
-int_bytes_multiply(PyObject *lhs, PyObject *rhs)
-{
- return seq_int_multiply(rhs, lhs, PyBytes_Type.tp_as_sequence->sq_repeat);
-}
-
-static PyObject *
-tuple_int_multiply(PyObject *lhs, PyObject *rhs)
-{
- return seq_int_multiply(lhs, rhs, PyTuple_Type.tp_as_sequence->sq_repeat);
-}
-
-static PyObject *
-int_tuple_multiply(PyObject *lhs, PyObject *rhs)
-{
- return seq_int_multiply(rhs, lhs, PyTuple_Type.tp_as_sequence->sq_repeat);
-}
+#define SEQ_INT_MULTIPLY_ACTION(NAME, REPEAT, SEQ, COUNT) \
+ static PyObject * \
+ (NAME)(PyObject *lhs, PyObject *rhs) \
+ { \
+ Py_ssize_t count = PyLong_AsSsize_t(COUNT); \
+ if (count == -1 && PyErr_Occurred()) { \
+ return NULL; \
+ } \
+ return REPEAT(SEQ, count); \
+ }
+SEQ_INT_MULTIPLY_ACTION(str_int_multiply, _PyUnicode_Repeat, lhs, rhs)
+SEQ_INT_MULTIPLY_ACTION(int_str_multiply, _PyUnicode_Repeat, rhs, lhs)
+SEQ_INT_MULTIPLY_ACTION(bytes_int_multiply, _PyBytes_Repeat, lhs, rhs)
+SEQ_INT_MULTIPLY_ACTION(int_bytes_multiply, _PyBytes_Repeat, rhs, lhs)
+SEQ_INT_MULTIPLY_ACTION(tuple_int_multiply, _PyTuple_Repeat, lhs, rhs)
+SEQ_INT_MULTIPLY_ACTION(int_tuple_multiply, _PyTuple_Repeat, rhs, lhs)
+#undef SEQ_INT_MULTIPLY_ACTION
static int
compactlongs_guard(PyObject *lhs, PyObject *rhs)
@@ -2300,8 +2268,8 @@ static _PyBinaryOpSpecializationDescr
binaryop_extend_descrs[] = {
to be a freshly allocated object. */
{NB_ADD, NULL, _PyTuple_Concat, &PyTuple_Type, 0, &PyTuple_Type,
&PyTuple_Type},
- /* str * int / int * str: call unicode_repeat directly.
- unicode_repeat returns the original when n == 1. */
+ /* str * int / int * str: call _PyUnicode_Repeat directly.
+ _PyUnicode_Repeat returns the original when n == 1. */
{NB_MULTIPLY, NULL, str_int_multiply, &PyUnicode_Type, 0, &PyUnicode_Type,
&PyLong_Type},
{NB_MULTIPLY, NULL, int_str_multiply, &PyUnicode_Type, 0, &PyLong_Type,
&PyUnicode_Type},
{NB_INPLACE_MULTIPLY, NULL, str_int_multiply, &PyUnicode_Type, 0,
&PyUnicode_Type, &PyLong_Type},
@@ -2312,15 +2280,15 @@ static _PyBinaryOpSpecializationDescr
binaryop_extend_descrs[] = {
{NB_ADD, NULL, _PyBytes_Concat, &PyBytes_Type, 0, &PyBytes_Type,
&PyBytes_Type},
{NB_INPLACE_ADD, NULL, _PyBytes_Concat, &PyBytes_Type, 0, &PyBytes_Type,
&PyBytes_Type},
- /* bytes * int / int * bytes: call bytes_repeat directly.
- bytes_repeat returns the original when n == 1. */
+ /* bytes * int / int * bytes: call _PyBytes_Repeat directly.
+ _PyBytes_Repeat returns the original when n == 1. */
{NB_MULTIPLY, NULL, bytes_int_multiply, &PyBytes_Type, 0, &PyBytes_Type,
&PyLong_Type},
{NB_MULTIPLY, NULL, int_bytes_multiply, &PyBytes_Type, 0, &PyLong_Type,
&PyBytes_Type},
{NB_INPLACE_MULTIPLY, NULL, bytes_int_multiply, &PyBytes_Type, 0,
&PyBytes_Type, &PyLong_Type},
{NB_INPLACE_MULTIPLY, NULL, int_bytes_multiply, &PyBytes_Type, 0,
&PyLong_Type, &PyBytes_Type},
- /* tuple * int / int * tuple: call tuple_repeat directly.
- tuple_repeat returns the original when n == 1. */
+ /* tuple * int / int * tuple: call _PyTuple_Repeat directly.
+ _PyTuple_Repeat returns the original when n == 1. */
{NB_MULTIPLY, NULL, tuple_int_multiply, &PyTuple_Type, 0, &PyTuple_Type,
&PyLong_Type},
{NB_MULTIPLY, NULL, int_tuple_multiply, &PyTuple_Type, 0, &PyLong_Type,
&PyTuple_Type},
{NB_INPLACE_MULTIPLY, NULL, tuple_int_multiply, &PyTuple_Type, 0,
&PyTuple_Type, &PyLong_Type},
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]