From 02df96396c6859cd2d629ca2184cc6f8c6e90672 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 29 Sep 2026 20:56:21 +0200 Subject: [PATCH] gh-157710: Avoid copy for large int in PyUnicodeWriter_WriteStr() Enable the PyUnicodeWriter read-only optimization for large integer (more than 1000 digits) in PyUnicodeWriter_WriteStr() and PyUnicodeWriter_WriteRepr(). --- Lib/test/test_capi/test_unicode.py | 29 +++++++++++++++++++++++++++++ Objects/longobject.c | 4 ---- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_capi/test_unicode.py b/Lib/test/test_capi/test_unicode.py index 032b910a280083..fc837c51a6de51 100644 --- a/Lib/test/test_capi/test_unicode.py +++ b/Lib/test/test_capi/test_unicode.py @@ -2262,6 +2262,35 @@ def __repr__(self): self.assertEqual(writer.get_buffer(), expected) self.assertIs(writer.finish(), unique_string) + def test_readonly_optim_large_int(self): + # Read-only optimization in _PyLong_FormatWriter() for large integer: + # use _pylong.int_to_decimal_string() result as a read-only string. + # See pylong_int_to_decimal_string(). + + self.addCleanup(sys.set_int_max_str_digits, + sys.get_int_max_str_digits()) + sys.set_int_max_str_digits(0) + + # _PyLong_FormatWriter() calls _pylong.int_to_decimal_string() for + # integer with Py_SIZE() > 1000. + large_int = 1 << (sys.int_info.bits_per_digit * 1020) + large_int_str = str(large_int) + expected = (len(large_int_str), 127, True) + + for size in (0, 123): + with self.subTest(size=size): + # Test PyUnicodeWriter_WriteStr() + writer = self.create_writer(size) + writer.write_str(large_int) + self.assertEqual(writer.get_buffer(), expected) + self.assertEqual(writer.finish(), large_int_str) + + # Test PyUnicodeWriter_WriteRepr() + writer = self.create_writer(size) + writer.write_repr(large_int) + self.assertEqual(writer.get_buffer(), expected) + self.assertEqual(writer.finish(), large_int_str) + # Test PyUnicodeWriter_Format() @unittest.skipIf(ctypes is None, 'need ctypes') diff --git a/Objects/longobject.c b/Objects/longobject.c index 1dac70820d142b..b9f00ca6fb471b 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -2045,10 +2045,6 @@ pylong_int_to_decimal_string(PyObject *aa, goto error; } if (writer) { - Py_ssize_t size = PyUnicode_GET_LENGTH(s); - if (_PyUnicodeWriter_Prepare(writer, size, '9') == -1) { - goto error; - } if (_PyUnicodeWriter_WriteStr(writer, s) < 0) { goto error; }