Skip to content

Commit a191357

Browse files
committed
Add PyLongWriter API
1 parent 4353581 commit a191357

File tree

2 files changed

+96
-10
lines changed

2 files changed

+96
-10
lines changed

Include/cpython/longintrepr.h

+11
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,17 @@ PyAPI_FUNC(int) PyUnstable_Long_Export(
181181
PyAPI_FUNC(void) PyUnstable_Long_ReleaseExport(
182182
PyUnstable_Long_DigitArray *array);
183183

184+
185+
/* --- PyLongWriter API --------------------------------------------------- */
186+
187+
typedef struct PyLongWriter PyLongWriter;
188+
189+
PyAPI_FUNC(PyLongWriter*) PyLongWriter_Create(void);
190+
PyAPI_FUNC(Py_digit*) PyLongWriter_AllocDigits(PyLongWriter *writer, size_t ndigits);
191+
PyAPI_FUNC(void) PyLongWriter_SetSign(PyLongWriter *writer, int sign);
192+
PyAPI_FUNC(PyObject*) PyLongWriter_Finish(PyLongWriter *writer);
193+
PyAPI_FUNC(void) PyLongWriter_Discard(PyLongWriter *writer);
194+
184195
#ifdef __cplusplus
185196
}
186197
#endif

Objects/longobject.c

+85-10
Original file line numberDiff line numberDiff line change
@@ -171,18 +171,26 @@ _PyLong_New(Py_ssize_t size)
171171
PyLongObject *
172172
_PyLong_FromDigits(int negative, Py_ssize_t digit_count, digit *digits)
173173
{
174-
assert(digit_count >= 0);
175-
if (digit_count == 0) {
176-
return (PyLongObject *)_PyLong_GetZero();
177-
}
178-
PyLongObject *result = _PyLong_New(digit_count);
179-
if (result == NULL) {
180-
PyErr_NoMemory();
174+
PyLongWriter *writer = PyLongWriter_Create();
175+
if (writer == NULL) {
181176
return NULL;
182177
}
183-
_PyLong_SetSignAndDigitCount(result, negative?-1:1, digit_count);
184-
memcpy(result->long_value.ob_digit, digits, digit_count * sizeof(digit));
185-
return result;
178+
179+
if (negative) {
180+
PyLongWriter_SetSign(writer, -1);
181+
}
182+
183+
Py_digit *writer_digits = PyLongWriter_AllocDigits(writer, digit_count);
184+
if (writer_digits == NULL) {
185+
goto error;
186+
}
187+
memcpy(writer_digits, digits, digit_count * sizeof(digit));
188+
189+
return (PyLongObject*)PyLongWriter_Finish(writer);
190+
191+
error:
192+
PyLongWriter_Discard(writer);
193+
return NULL;
186194
}
187195

188196
PyObject *
@@ -6729,3 +6737,70 @@ PyUnstable_Long_ReleaseExport(PyUnstable_Long_DigitArray *array)
67296737
array->ndigits = 0;
67306738
array->digits = NULL;
67316739
}
6740+
6741+
6742+
/* --- PyLongWriter API --------------------------------------------------- */
6743+
6744+
struct PyLongWriter {
6745+
PyLongObject *obj;
6746+
int sign;
6747+
};
6748+
6749+
PyLongWriter* PyLongWriter_Create(void)
6750+
{
6751+
PyLongWriter *writer = PyMem_Malloc(sizeof(PyLongWriter));
6752+
if (writer == NULL) {
6753+
PyErr_NoMemory();
6754+
return NULL;
6755+
}
6756+
writer->obj = NULL;
6757+
writer->sign = 1;
6758+
return writer;
6759+
}
6760+
6761+
Py_digit* PyLongWriter_AllocDigits(PyLongWriter *writer, size_t ndigits)
6762+
{
6763+
Py_CLEAR(writer->obj);
6764+
6765+
if (ndigits > (size_t)PY_SSIZE_T_MAX) {
6766+
PyErr_NoMemory();
6767+
return NULL;
6768+
}
6769+
6770+
writer->obj = _PyLong_New(ndigits);
6771+
if (writer->obj == NULL) {
6772+
return NULL;
6773+
}
6774+
6775+
return writer->obj->long_value.ob_digit;
6776+
}
6777+
6778+
void PyLongWriter_SetSign(PyLongWriter *writer, int sign)
6779+
{
6780+
writer->sign = sign;
6781+
}
6782+
6783+
PyObject* PyLongWriter_Finish(PyLongWriter *writer)
6784+
{
6785+
if (writer->obj) {
6786+
assert(Py_REFCNT(writer->obj) == 1);
6787+
6788+
if (writer->sign < 0 && _PyLong_IsPositive(writer->obj)) {
6789+
_PyLong_FlipSign(writer->obj);
6790+
}
6791+
6792+
writer->obj = maybe_small_long(long_normalize(writer->obj));
6793+
}
6794+
else {
6795+
writer->obj = (PyLongObject*)Py_NewRef(_PyLong_GetZero());
6796+
}
6797+
6798+
PyObject *res = (PyObject*)writer->obj;
6799+
PyMem_Free(writer);
6800+
return res;
6801+
}
6802+
6803+
void PyLongWriter_Discard(PyLongWriter *writer)
6804+
{
6805+
PyMem_Free(writer);
6806+
}

0 commit comments

Comments
 (0)