Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-130599: precompute conversion constants for long() #130714

Merged
merged 9 commits into from
Mar 4, 2025
1 change: 1 addition & 0 deletions Include/internal/pycore_long.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ extern "C" {

/* runtime lifecycle */

extern PyStatus _PyLong_InitRuntime(void);
extern PyStatus _PyLong_InitTypes(PyInterpreterState *);
extern void _PyLong_FiniTypes(PyInterpreterState *interp);

Expand Down
47 changes: 32 additions & 15 deletions Objects/longobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -2820,23 +2820,18 @@ that triggers it(!). Instead the code was tested by artificially allocating
just 1 digit at the start, so that the copying code was exercised for every
digit beyond the first.
***/
static int
long_from_non_binary_base(const char *start, const char *end, Py_ssize_t digits, int base, PyLongObject **res)
{
twodigits c; /* current input character */
Py_ssize_t size_z;
int i;
int convwidth;
twodigits convmultmax, convmult;
digit *pz, *pzstop;
PyLongObject *z;
const char *p;

static double log_base_BASE[37] = {0.0e0,};
static int convwidth_base[37] = {0,};
static twodigits convmultmax_base[37] = {0,};
static double log_base_BASE[37] = {0.0e0,};
static int convwidth_base[37] = {0,};
static twodigits convmultmax_base[37] = {0,};

if (log_base_BASE[base] == 0.0) {
static void
long_precompute_base_conv(void)
{
// These constants are quick to compute (likely less than 1 μs) and
// computing them at runtime avoids hard-coding a table dependant on
// PyLong_BASE.
for (int base = 2; base <= 36; base++) {
twodigits convmax = base;
int i = 1;

Expand All @@ -2854,6 +2849,21 @@ long_from_non_binary_base(const char *start, const char *end, Py_ssize_t digits,
assert(i > 0);
convwidth_base[base] = i;
}
}

static int
long_from_non_binary_base(const char *start, const char *end, Py_ssize_t digits, int base, PyLongObject **res)
{
twodigits c; /* current input character */
Py_ssize_t size_z;
int i;
int convwidth;
twodigits convmultmax, convmult;
digit *pz, *pzstop;
PyLongObject *z;
const char *p;

assert (log_base_BASE[base] != 0.0); // pre-computed by _PyLong_InitRuntime()

/* Create an int object that can contain the largest possible
* integer with this base and length. Note that there's no
Expand Down Expand Up @@ -6740,6 +6750,13 @@ PyLong_GetInfo(void)

/* runtime lifecycle */

PyStatus
_PyLong_InitRuntime(void)
{
long_precompute_base_conv();
return _PyStatus_OK();
}

PyStatus
_PyLong_InitTypes(PyInterpreterState *interp)
{
Expand Down
5 changes: 5 additions & 0 deletions Python/pylifecycle.c
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,11 @@ pycore_init_runtime(_PyRuntimeState *runtime,
return status;
}

status = _PyLong_InitRuntime();
if (_PyStatus_EXCEPTION(status)) {
return status;
}

status = _PyImport_Init();
if (_PyStatus_EXCEPTION(status)) {
return status;
Expand Down
Loading