From 98242b4ed34398662140a527ae6af1dba1f1781a Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sat, 14 Dec 2024 10:17:40 +0300 Subject: [PATCH 1/4] gh-127937: deprecate _PyLong_FromDigits() function --- Doc/deprecations/c-api-pending-removal-in-future.rst | 2 ++ Include/cpython/longintrepr.h | 2 +- .../next/C_API/2024-12-14-10-14-27.gh-issue-127937.-tT1KP.rst | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/C_API/2024-12-14-10-14-27.gh-issue-127937.-tT1KP.rst diff --git a/Doc/deprecations/c-api-pending-removal-in-future.rst b/Doc/deprecations/c-api-pending-removal-in-future.rst index 8fc1c80c35d092..0ed1d607174525 100644 --- a/Doc/deprecations/c-api-pending-removal-in-future.rst +++ b/Doc/deprecations/c-api-pending-removal-in-future.rst @@ -35,6 +35,8 @@ although there is currently no date scheduled for their removal. * :c:member:`!PyBytesObject.ob_shash` member: call :c:func:`PyObject_Hash` instead. * :c:member:`!PyDictObject.ma_version_tag` member. +* :c:func::c:func:`!_PyLong_FromDigits` + Use instead :c:struct:`PyLongWriter` API. * Thread Local Storage (TLS) API: * :c:func:`PyThread_create_key`: diff --git a/Include/cpython/longintrepr.h b/Include/cpython/longintrepr.h index 357477b60d9a5a..cdb99509b6b50b 100644 --- a/Include/cpython/longintrepr.h +++ b/Include/cpython/longintrepr.h @@ -105,7 +105,7 @@ PyAPI_FUNC(PyLongObject*) _PyLong_New(Py_ssize_t); // Return a copy of src. PyAPI_FUNC(PyObject*) _PyLong_Copy(PyLongObject *src); -PyAPI_FUNC(PyLongObject*) _PyLong_FromDigits( +Py_DEPRECATED(3.14) PyAPI_FUNC(PyLongObject*) _PyLong_FromDigits( int negative, Py_ssize_t digit_count, digit *digits); diff --git a/Misc/NEWS.d/next/C_API/2024-12-14-10-14-27.gh-issue-127937.-tT1KP.rst b/Misc/NEWS.d/next/C_API/2024-12-14-10-14-27.gh-issue-127937.-tT1KP.rst new file mode 100644 index 00000000000000..ad74d45f17d250 --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2024-12-14-10-14-27.gh-issue-127937.-tT1KP.rst @@ -0,0 +1,2 @@ +Deprecate the :c:func:`!_PyLong_FromDigits`, use instead +:c:struct:`PyLongWriter` API. Patch by Sergey B Kirpichev. From 1b803503403c03f32e2353e74c34309f9b88e369 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Fri, 24 Jan 2025 08:58:24 +0300 Subject: [PATCH 2/4] address review: inline _PyLong_FromDigits & improve docs --- Doc/deprecations/c-api-pending-removal-in-3.18.rst | 3 ++- Doc/deprecations/c-api-pending-removal-in-future.rst | 2 -- Doc/whatsnew/3.14.rst | 3 ++- .../2024-12-14-10-14-27.gh-issue-127937.-tT1KP.rst | 2 -- .../2025-01-15-11-42-07.gh-issue-128863.C9MkB_.rst | 3 ++- Objects/longobject.c | 11 ++++++++++- 6 files changed, 16 insertions(+), 8 deletions(-) delete mode 100644 Misc/NEWS.d/next/C_API/2024-12-14-10-14-27.gh-issue-127937.-tT1KP.rst diff --git a/Doc/deprecations/c-api-pending-removal-in-3.18.rst b/Doc/deprecations/c-api-pending-removal-in-3.18.rst index 361e1a9abf22d7..0689d8b4f9e959 100644 --- a/Doc/deprecations/c-api-pending-removal-in-3.18.rst +++ b/Doc/deprecations/c-api-pending-removal-in-3.18.rst @@ -7,7 +7,8 @@ Pending removal in Python 3.18 * :c:func:`!_PyDict_GetItemStringWithError`: use :c:func:`PyDict_GetItemStringRef`. * :c:func:`!_PyDict_Pop()`: :c:func:`PyDict_Pop`. * :c:func:`!_PyLong_Sign()`: use :c:func:`PyLong_GetSign`. - * :c:func:`!_PyLong_New`: use :c:func:`PyLongWriter_Create`. + * :c:func:`!_PyLong_FromDigits` and :c:func:`!_PyLong_New`: + use :c:func:`PyLongWriter_Create`. * :c:func:`!_PyThreadState_UncheckedGet`: use :c:func:`PyThreadState_GetUnchecked`. * :c:func:`!_PyUnicode_AsString`: use :c:func:`PyUnicode_AsUTF8`. * :c:func:`!_Py_HashPointer`: use :c:func:`Py_HashPointer`. diff --git a/Doc/deprecations/c-api-pending-removal-in-future.rst b/Doc/deprecations/c-api-pending-removal-in-future.rst index 0ed1d607174525..8fc1c80c35d092 100644 --- a/Doc/deprecations/c-api-pending-removal-in-future.rst +++ b/Doc/deprecations/c-api-pending-removal-in-future.rst @@ -35,8 +35,6 @@ although there is currently no date scheduled for their removal. * :c:member:`!PyBytesObject.ob_shash` member: call :c:func:`PyObject_Hash` instead. * :c:member:`!PyDictObject.ma_version_tag` member. -* :c:func::c:func:`!_PyLong_FromDigits` - Use instead :c:struct:`PyLongWriter` API. * Thread Local Storage (TLS) API: * :c:func:`PyThread_create_key`: diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index f463ed415d6a20..b3c53b78903c7f 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -1396,7 +1396,8 @@ Deprecated * :c:func:`!_PyDict_GetItemStringWithError`: use :c:func:`PyDict_GetItemStringRef`. * :c:func:`!_PyDict_Pop()`: use :c:func:`PyDict_Pop`. * :c:func:`!_PyLong_Sign()`: use :c:func:`PyLong_GetSign`. - * :c:func:`!_PyLong_New`: use :c:func:`PyLongWriter_Create`. + * :c:func:`!_PyLong_FromDigits` and :c:func:`!_PyLong_New`: + use :c:func:`PyLongWriter_Create`. * :c:func:`!_PyThreadState_UncheckedGet`: use :c:func:`PyThreadState_GetUnchecked`. * :c:func:`!_PyUnicode_AsString`: use :c:func:`PyUnicode_AsUTF8`. * :c:func:`!_Py_HashPointer`: use :c:func:`Py_HashPointer`. diff --git a/Misc/NEWS.d/next/C_API/2024-12-14-10-14-27.gh-issue-127937.-tT1KP.rst b/Misc/NEWS.d/next/C_API/2024-12-14-10-14-27.gh-issue-127937.-tT1KP.rst deleted file mode 100644 index ad74d45f17d250..00000000000000 --- a/Misc/NEWS.d/next/C_API/2024-12-14-10-14-27.gh-issue-127937.-tT1KP.rst +++ /dev/null @@ -1,2 +0,0 @@ -Deprecate the :c:func:`!_PyLong_FromDigits`, use instead -:c:struct:`PyLongWriter` API. Patch by Sergey B Kirpichev. diff --git a/Misc/NEWS.d/next/C_API/2025-01-15-11-42-07.gh-issue-128863.C9MkB_.rst b/Misc/NEWS.d/next/C_API/2025-01-15-11-42-07.gh-issue-128863.C9MkB_.rst index 7e6a8484b8887c..b2e5664138fba2 100644 --- a/Misc/NEWS.d/next/C_API/2025-01-15-11-42-07.gh-issue-128863.C9MkB_.rst +++ b/Misc/NEWS.d/next/C_API/2025-01-15-11-42-07.gh-issue-128863.C9MkB_.rst @@ -5,7 +5,8 @@ Python 3.18: * :c:func:`!_PyDict_GetItemStringWithError`: use :c:func:`PyDict_GetItemStringRef`. * :c:func:`!_PyDict_Pop()`: use :c:func:`PyDict_Pop`. * :c:func:`!_PyLong_Sign()`: use :c:func:`PyLong_GetSign`. -* :c:func:`!_PyLong_New`: use :c:func:`PyLongWriter_Create`. +* :c:func:`!_PyLong_FromDigits` and :c:func:`!_PyLong_New`: + use :c:func:`PyLongWriter_Create`. * :c:func:`!_PyThreadState_UncheckedGet`: use :c:func:`PyThreadState_GetUnchecked`. * :c:func:`!_PyUnicode_AsString`: use :c:func:`PyUnicode_AsUTF8`. * :c:func:`!_Py_HashPointer`: use :c:func:`Py_HashPointer`. diff --git a/Objects/longobject.c b/Objects/longobject.c index b4e3a70adf2b5b..5fd677e2109e85 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -224,8 +224,17 @@ _PyLong_Copy(PyLongObject *src) return get_small_int((sdigit)ival); } } + Py_ssize_t size = _PyLong_DigitCount(src); - return (PyObject *)_PyLong_FromDigits(_PyLong_IsNegative(src), size, src->long_value.ob_digit); + PyLongObject *result = long_alloc(size); + + if (result == NULL) { + PyErr_NoMemory(); + return NULL; + } + _PyLong_SetSignAndDigitCount(result, _PyLong_Sign(src), size); + memcpy(result->long_value.ob_digit, src->long_value.ob_digit, size * sizeof(digit)); + return (PyObject *)result; } static PyObject * From d5e1fefc35d10e729ac7524f919e51146db445e2 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Fri, 24 Jan 2025 09:15:04 +0300 Subject: [PATCH 3/4] +1 --- Objects/longobject.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index 5fd677e2109e85..ea0bb36f6222ec 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -217,12 +217,17 @@ PyObject * _PyLong_Copy(PyLongObject *src) { assert(src != NULL); + int sign; if (_PyLong_IsCompact(src)) { stwodigits ival = medium_value(src); if (IS_SMALL_INT(ival)) { return get_small_int((sdigit)ival); } + sign = _PyLong_CompactSign(src); + } + else { + sign = _PyLong_NonCompactSign(src); } Py_ssize_t size = _PyLong_DigitCount(src); @@ -232,8 +237,9 @@ _PyLong_Copy(PyLongObject *src) PyErr_NoMemory(); return NULL; } - _PyLong_SetSignAndDigitCount(result, _PyLong_Sign(src), size); - memcpy(result->long_value.ob_digit, src->long_value.ob_digit, size * sizeof(digit)); + _PyLong_SetSignAndDigitCount(result, sign, size); + memcpy(result->long_value.ob_digit, src->long_value.ob_digit, + size * sizeof(digit)); return (PyObject *)result; } From 4e766223b10854730aa69c3bac0e75dcb1fb986a Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Fri, 24 Jan 2025 14:45:18 +0300 Subject: [PATCH 4/4] address review: remove PyErr_NoMemory() --- Objects/longobject.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index ea0bb36f6222ec..905c4695f60d4f 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -205,7 +205,6 @@ _PyLong_FromDigits(int negative, Py_ssize_t digit_count, digit *digits) } PyLongObject *result = long_alloc(digit_count); if (result == NULL) { - PyErr_NoMemory(); return NULL; } _PyLong_SetSignAndDigitCount(result, negative?-1:1, digit_count); @@ -234,7 +233,6 @@ _PyLong_Copy(PyLongObject *src) PyLongObject *result = long_alloc(size); if (result == NULL) { - PyErr_NoMemory(); return NULL; } _PyLong_SetSignAndDigitCount(result, sign, size);