Sparse-checkout from NVIDIA/cccl main branch to complete cccl_upstream: Added: - python/cuda_cccl/ (226 files) — Python bindings for device-level algorithms Critical for muh toolchain: cuda.compute.reduce_into, scan, radix_sort, etc. Includes 204 .py files with full test coverage for all 27 algorithms - ci/ (163 files) — Build/test infrastructure build_cub.sh, test_cub.sh, build_and_test_targets.sh, matrix.yaml Directly maps to our [INFRA-CI] and [INFRA-BUILD] items - .agent/skills/ (7 files) — NVIDIA's own agent skills for CCCL cccl-style/SKILL.md, cccl-test/SKILL.md, sass-diff/SKILL.md - docs/ (491 files) — Official CCCL documentation CI references, CMake guides, Python compute docs, libcudacxx PTX docs - test/ (12 files) — Top-level integration tests (cuda_smoke, stdpar) - Root configs: .clang-format, .clang-tidy, CONTRIBUTING.md, pyproject.toml - CLAUDE.md symlink → AGENTS.md (NVIDIA's standard) cccl_upstream now mirrors full NVIDIA/cccl structure: Before: 42M (cub + thrust + libcudacxx + cudax + c + examples + benchmarks) After: 53M (+python +ci +docs +.agent +test +configs) This completes the CCCL base needed for: - [muh-bench] items: ci/util/build_and_test_targets.sh for targeted builds - [CCCL-verify] items: python/cuda_cccl/tests/ as reference implementations - [CCCL-test] items: ci/test_cub.sh, ci/test_thrust.sh - Agent workflow: .agent/skills/ for consistent style and test patterns
95 lines
3.1 KiB
Python
Executable File
95 lines
3.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
#
|
|
# strip_unprintable.py - Remove invisible / unprintable characters from text files.
|
|
import re
|
|
import sys
|
|
from argparse import ArgumentParser, Namespace, RawDescriptionHelpFormatter
|
|
|
|
# Canonical definition of what gets removed. One row per range group:
|
|
# (regex character-class fragment, human description)
|
|
# The compiled character class and the --help listing are both derived from this
|
|
# table, so adding or removing a range only needs to happen here. TAB (U+0009),
|
|
# LF (U+000A), and CR (U+000D) are deliberately excluded from the C0 range. The
|
|
# fragments use \x/\u escapes so the source file itself stays free of the very
|
|
# characters this script removes.
|
|
RANGES = (
|
|
(
|
|
r"\x00-\x08\x0b\x0c\x0e-\x1f\x7f",
|
|
"C0 controls / DEL (TAB, LF, CR preserved)",
|
|
),
|
|
(r"\x80-\x9f", "C1 controls"),
|
|
(r"\xa0", "no-break space"),
|
|
(r"\u200b-\u200f", "zero-width space/joiners, bidi marks"),
|
|
(r"\u202a-\u202e", "bidi embedding/override"),
|
|
(r"\u2060-\u2064", "word joiner, invisible operators"),
|
|
(r"\ufeff", "BOM / zero-width no-break space"),
|
|
)
|
|
|
|
# Character class assembled from column 1 of the ranges table.
|
|
BAD_RE = re.compile("[" + "".join(frag for frag, _ in RANGES) + "]")
|
|
|
|
|
|
def parse_args() -> Namespace:
|
|
removed = "\n".join(f" {frag}\t{desc}" for frag, desc in RANGES)
|
|
parser = ArgumentParser(
|
|
description=(
|
|
"Remove invisible / unprintable characters from text files, in place, "
|
|
"while preserving ordinary whitespace (TAB U+0009, LF U+000A, "
|
|
"CR U+000D)."
|
|
),
|
|
epilog=f"Removed characters:\n{removed}",
|
|
formatter_class=RawDescriptionHelpFormatter,
|
|
)
|
|
parser.add_argument(
|
|
"--check",
|
|
action="store_true",
|
|
help=(
|
|
"Report offending files and their line/column locations; make no "
|
|
"edits. Exits non-zero if any unprintable characters are found."
|
|
),
|
|
)
|
|
parser.add_argument("files", nargs="+", metavar="FILE")
|
|
return parser.parse_args()
|
|
|
|
|
|
def check(files: list[str]) -> int:
|
|
ret = 0
|
|
for f in files:
|
|
with open(f, encoding="utf-8", errors="surrogateescape") as fd:
|
|
for lineno, line in enumerate(fd, start=1):
|
|
for m in BAD_RE.finditer(line):
|
|
print(f"{f}:{lineno}:{m.start() + 1}: U+{ord(m.group()):04X}")
|
|
ret = 1
|
|
|
|
return ret
|
|
|
|
|
|
def strip(files: list[str]) -> int:
|
|
ret = 0
|
|
for f in files:
|
|
with open(f, encoding="utf-8", errors="surrogateescape") as fd:
|
|
original = fd.read()
|
|
stripped = BAD_RE.sub("", original)
|
|
if stripped != original:
|
|
with open(
|
|
f, "w", encoding="utf-8", errors="surrogateescape", newline=""
|
|
) as fd:
|
|
fd.write(stripped)
|
|
ret = 1
|
|
|
|
return ret
|
|
|
|
|
|
def main() -> int:
|
|
args = parse_args()
|
|
if args.check:
|
|
return check(args.files)
|
|
return strip(args.files)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|