cpython/Tools/scripts/long_conv_tables.py
Neil Schemenauer 813bc5694b
gh-130599: use static constants str-to-int conversion (gh-130714)
Avoid a data race in free-threaded builds due to mutating global arrays at
runtime.  Instead, compute the constants with an external Python script and
then define them as static global constant arrays.  These constants are
used by `long_from_non_binary_base()`.
2025-03-03 19:00:50 -08:00

75 lines
1.8 KiB
Python

#!/usr/bin/env python3
#
# Compute tables for longobject.c long_from_non_binary_base(). They are used
# for conversions of strings to integers with a non-binary base.
import math
import textwrap
def format_array(name, values):
values = [str(v) for v in values]
values = ', '.join(values)
result = f'{name} = {{{values}}};'
result = textwrap.wrap(
result,
initial_indent=' ' * 4,
subsequent_indent=' ' * 8,
)
return '\n'.join(result)
def conv_tables(long_bits):
PyLong_BASE = 1 << long_bits
log_base_BASE = [0.0] * 37
convmultmax_base = [0] * 37
convwidth_base = [0] * 37
for base in range(2, 37):
is_binary_base = (base & (base - 1)) == 0
if is_binary_base:
continue # don't need, leave as zero
convmax = base
i = 1
log_base_BASE[base] = math.log(base) / math.log(PyLong_BASE)
while True:
next = convmax * base
if next > PyLong_BASE:
break
convmax = next
i += 1
convmultmax_base[base] = convmax
assert i > 0
convwidth_base[base] = i
return '\n'.join(
[
format_array(
'static const double log_base_BASE[37]', log_base_BASE
),
format_array(
'static const int convwidth_base[37]', convwidth_base
),
format_array(
'static const twodigits convmultmax_base[37]',
convmultmax_base,
),
]
)
def main():
print(
f'''\
// Tables are computed by Tools/scripts/long_conv_tables.py
#if PYLONG_BITS_IN_DIGIT == 15
{conv_tables(15)}
#elif PYLONG_BITS_IN_DIGIT == 30
{conv_tables(30)}
#else
#error "invalid PYLONG_BITS_IN_DIGIT value"
#endif
'''
)
if __name__ == '__main__':
main()