File indexing completed on 2026-09-09 08:18:04
0001
0002
0003 from pathlib import Path
0004 import os
0005 import argparse
0006 from fnmatch import fnmatch
0007 import re
0008 import sys
0009
0010 math_constants = [
0011 ("M_PI", "std::numbers::pi"),
0012 ("M_PI_2", "std::numbers::pi / 2."),
0013 ("M_PI_4", "std::numbers::pi / 4."),
0014 ("M_1_PI", "std::numbers::inv_pi"),
0015 ("M_2_PI", "2. * std::numbers::inv_pi"),
0016 ("M_2_SQRTPI", "2. * std::numbers::inv_sqrtpi"),
0017 ("M_E", "std::numbers::e"),
0018 ("M_LOG2E", "std::numbers::log2e"),
0019 ("M_LOG10E", "std::numbers::log10e"),
0020 ("M_LN2", "std::numbers::ln2"),
0021 ("M_LN10", "std::numbers::ln10"),
0022 ("M_SQRT2", "std::numbers::sqrt2"),
0023 ("M_SQRT1_2", "1. / std::numbers::sqrt2"),
0024 ("M_SQRT3", "std::numbers::sqrt3"),
0025 ("M_INV_SQRT3", "std::numbers::inv_sqrt3"),
0026 ("M_EGAMMA", "std::numbers::egamma"),
0027 ("M_PHI", "std::numbers::phi"),
0028 ]
0029
0030
0031 github = "GITHUB_ACTIONS" in os.environ
0032
0033
0034 def handle_file(
0035 file: Path, fix: bool, math_const: tuple[str, str]
0036 ) -> list[tuple[int, str]]:
0037 ex = re.compile(rf"(?<!\w){math_const[0]}(?!\w)")
0038
0039 content = file.read_text()
0040 lines = content.splitlines()
0041
0042 changed_lines = []
0043
0044 for i, oline in enumerate(lines):
0045 line, n_subs = ex.subn(rf"{math_const[1]}", oline)
0046 lines[i] = line
0047 if n_subs > 0:
0048 changed_lines.append((i, oline))
0049
0050 if fix and len(changed_lines) > 0:
0051 file.write_text("\n".join(lines) + "\n")
0052
0053 return changed_lines
0054
0055
0056 def main():
0057 p = argparse.ArgumentParser()
0058 p.add_argument("input", nargs="+")
0059 p.add_argument("--fix", action="store_true", help="Attempt to fix M_* macros.")
0060 p.add_argument("--exclude", "-e", action="append", default=[])
0061
0062 args = p.parse_args()
0063
0064 exit_code = 0
0065
0066 inputs = []
0067
0068 if len(args.input) == 1 and os.path.isdir(args.input[0]):
0069
0070 for root, _, files in os.walk(args.input[0]):
0071 root = Path(root)
0072 for filename in files:
0073
0074 filepath = root / filename
0075 if filepath.suffix not in (
0076 ".hpp",
0077 ".cpp",
0078 ".ipp",
0079 ".h",
0080 ".C",
0081 ".c",
0082 ".cu",
0083 ".cuh",
0084 ):
0085 continue
0086
0087 if any([fnmatch(str(filepath), e) for e in args.exclude]):
0088 continue
0089
0090 inputs.append(filepath)
0091 else:
0092 for file in args.input:
0093 inputs.append(Path(file))
0094
0095 for filepath in inputs:
0096 for math_const in math_constants:
0097 changed_lines = handle_file(
0098 file=filepath, fix=args.fix, math_const=math_const
0099 )
0100 if len(changed_lines) > 0:
0101 exit_code = 1
0102 print()
0103 print(filepath)
0104 for i, oline in changed_lines:
0105 print(f"{i}: {oline}")
0106
0107 if github:
0108 print(
0109 f"::error file={filepath},line={i+1},title=Do not use macro {math_const[0]}::Replace {math_const[0]} with std::{math_const[1]}"
0110 )
0111
0112 if exit_code == 1 and github:
0113 print(f"::info You will need in each flagged file #include <numbers>")
0114
0115 return exit_code
0116
0117
0118 if "__main__" == __name__:
0119 sys.exit(main())