]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-100239: expose `sq_repeat` helpers for `BINARY_OP_EXTEND` (#148791)
authorNeko Asakura <neko.asakura@outlook.com>
Fri, 8 May 2026 11:12:20 +0000 (19:12 +0800)
committerGitHub <noreply@github.com>
Fri, 8 May 2026 11:12:20 +0000 (11:12 +0000)
Include/internal/pycore_bytesobject.h
Include/internal/pycore_tuple.h
Include/internal/pycore_unicodeobject.h
Modules/arraymodule.c
Objects/bytearrayobject.c
Objects/bytesobject.c
Objects/tupleobject.c
Objects/unicodeobject.c
Python/specialize.c

index 177e6d10134adbebf0e4abf35f84cb8846f0788c..27a7a46152f57b84fe0ea88133eb8df98dc0a1ba 100644 (file)
@@ -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.
 
index bf80f96396ea4a8f665a0de1255fb278db0d8690..e294b16b3df60f6c436acdc66d4ce5436200dc6f 100644 (file)
@@ -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 *);
index 74d84052a2bb2be8b7f60cdfef3ee11227982cf9..75d5068f815b9185e0abd1ea1e2bd421f3b7f925 100644 (file)
@@ -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.
index 472c59ea8c98826924750532a426e893405b8a80..646b73bd4af7db8094a7b0dbdf8c4093a13e9bc8 100644 (file)
@@ -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);
 }
index c583193b5a252ca7dcb0545493e059c943dc8758..e698d260795480c4fcea8a21a751e42f53619bb9 100644 (file)
@@ -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);
 }
index 8a9d1b133affb3ec03fc7ea098dd6058a6fa60cd..cd8417e25839161ca93b911f851723b69d39c683 100644 (file)
@@ -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) {
index 753c270f525976f8d32c74ec9325dc49fddf677d..9423000242754616ceb06d8dbe065d079a5e0723 100644 (file)
@@ -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 */
index 9aee7120c811de8076e7856d5c9b251268ab5351..5c97efd6838ef3fb70f9cf84a8625e93371c238f 100644 (file)
@@ -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 */
index 459e69de5709b8a8b408724b892b6657cc3efe6f..2ff0a9d0072cec3820cc77d2139da52aac3f8329 100644 (file)
@@ -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},