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()`.
This commit is contained in:
Neil Schemenauer 2025-03-03 19:00:50 -08:00 committed by GitHub
parent bbf197913c
commit 813bc5694b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 133 additions and 25 deletions

View file

@ -0,0 +1,75 @@
#!/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()