Skip to content

Commit 093606a

Browse files
committed
feat: omit system includes from expanded headers by default
1 parent de85776 commit 093606a

8 files changed

Lines changed: 97 additions & 39 deletions

File tree

AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
- 回答・説明は日本語で簡潔かつ丁寧に行う。
66
- このディレクトリは競技プログラミング用 C++ ライブラリ `cpp-lib` である。
77
- 既存の構成・文体・整形を優先し、勝手に別方式へ変更しない。
8+
- 単純な仕様に、既存の例外を救済する自動判定やフォールバックを勝手に追加しない。例外は報告に留める。
89
- 次は生成物なので手で編集しない(正典は `.gitignore`)。`bundled/``site/``docsrc/verify/`(配下すべて)、`docsrc/library/index.md``docsrc/note/index.md`
910
- 説明文では受動態を避ける。ライブラリは機能を提供する側なので、「〜される」より「〜する」「〜を返す」「〜を管理する」のように書く。
1011

scripts/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
- `verify.py`
88
Verify コードの登録・検証状況の最新化を行う CLI です。Verify 運用を回すときに使用します。
99
- `combine.py`
10-
提出用の `submit.cpp` を生成し、必要ならクリップボードへコピーします。ライブラリ管理や docs 生成には不要です
10+
提出用の `submit.cpp` を生成し、必要ならクリップボードへコピーします。展開したライブラリ内の標準 `#include` はデフォルトで省略し、`--keep-system-includes` を指定すると残します
1111

1212
## `verify.py`
1313

@@ -29,15 +29,15 @@ uv run scripts/verify.py mark --all
2929
## 内部処理
3030

3131
- `mkdocs_hooks.py`
32-
MkDocs のフック本体です。nav 差し替え、`bundled/` 生成、`docsrc/library/` / `docsrc/verify/` の自動生成を行います。
32+
MkDocs のフック本体です。nav 差し替え、`bundled/` 生成、`docsrc/library/` / `docsrc/verify/` の自動生成を行います。ライブラリ単体の bundle では標準 `#include` を残し、コピペだけで利用できる形にします。
3333
- `_internal/docs_catalog.py`
3434
Library / Note のスキャン、nav / index 生成、ライブラリページ末尾の管理セクション生成を担当します。
3535
- `_internal/verify_docs.py`
3636
Verify ページ、Verify index、Verify nav の生成を担当します。
3737
- `_internal/verify_data.py`
3838
`verify/status.json` の読み書き、ハッシュ計算、judge URL 解決など Verify 系の共通処理です。
3939
- `bundle_header.py`
40-
`#include` を展開して `bundled/` の単一ファイルを生成します。
40+
`#include` を展開して `bundled/` の単一ファイルを生成します。展開したローカルヘッダ内の標準 `#include` はデフォルトで省略し、`--keep-system-includes` を指定すると残します。
4141
- `_internal/docs_common.py`
4242
タイトル読取や `write_if_changed` など、docs 系の小さい共通処理です。
4343
- `_internal/project_paths.py`

scripts/bundle_header.py

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99

1010
INCLUDE_RE = re.compile(r'^\s*#\s*include\s*"([^"]+)"\s*$')
11+
SYSTEM_INCLUDE_RE = re.compile(r"^\s*#\s*include\s*<[^>]+>\s*$")
1112

1213

1314
def resolve_include(
@@ -28,6 +29,8 @@ def bundle_file(
2829
include_dirs: list[Path],
2930
visited: set[Path],
3031
out_lines: list[str],
32+
keep_system_includes: bool = False,
33+
is_entry: bool = False,
3134
) -> None:
3235
path = path.resolve()
3336
if path in visited:
@@ -43,14 +46,25 @@ def bundle_file(
4346
for line in path.read_text(encoding="utf-8").splitlines():
4447
if line.strip() == "#pragma once":
4548
continue
49+
# Keep includes written in the entry file (for example bits/stdc++.h),
50+
# but omit redundant system includes from expanded local headers by default.
51+
if SYSTEM_INCLUDE_RE.match(line) and not (is_entry or keep_system_includes):
52+
continue
4653
m = INCLUDE_RE.match(line)
4754
if m:
4855
inc = m.group(1)
4956
inc_path = resolve_include(inc, path.parent, include_dirs)
5057
if inc_path is None:
5158
out_lines.append(line)
5259
else:
53-
bundle_file(inc_path, project_root, include_dirs, visited, out_lines)
60+
bundle_file(
61+
inc_path,
62+
project_root,
63+
include_dirs,
64+
visited,
65+
out_lines,
66+
keep_system_includes,
67+
)
5468
continue
5569
out_lines.append(line)
5670

@@ -61,6 +75,7 @@ def _bundle_to_string(
6175
input_path: Path,
6276
include_dirs: list[Path] | None = None,
6377
project_root: Path | None = None,
78+
keep_system_includes: bool = False,
6479
) -> str:
6580
"""Bundle input_path and return the result as a string."""
6681
script_dir = Path(__file__).resolve().parent
@@ -78,7 +93,15 @@ def _bundle_to_string(
7893
out_lines: list[str] = []
7994
out_lines.append("// bundled by scripts/bundle_header.py")
8095
out_lines.append("")
81-
bundle_file(input_path, project_root, include_dirs, set(), out_lines)
96+
bundle_file(
97+
input_path,
98+
project_root,
99+
include_dirs,
100+
set(),
101+
out_lines,
102+
keep_system_includes,
103+
is_entry=True,
104+
)
82105
return "\n".join(out_lines).rstrip() + "\n"
83106

84107

@@ -91,8 +114,14 @@ def bundle_header(
91114
output_path: Path,
92115
include_dirs: list[Path] | None = None,
93116
project_root: Path | None = None,
117+
keep_system_includes: bool = False,
94118
) -> None:
95-
out_text = _bundle_to_string(input_path, include_dirs, project_root)
119+
out_text = _bundle_to_string(
120+
input_path,
121+
include_dirs,
122+
project_root,
123+
keep_system_includes,
124+
)
96125

97126
output_path.parent.mkdir(parents=True, exist_ok=True)
98127
# Avoid touching timestamps when generated content is unchanged.
@@ -114,11 +143,21 @@ def main() -> int:
114143
default=[],
115144
help="additional include directories (repeatable)",
116145
)
146+
parser.add_argument(
147+
"--keep-system-includes",
148+
action="store_true",
149+
help="keep system includes from expanded local headers",
150+
)
117151
args = parser.parse_args()
118152

119153
include_dirs = [d.resolve() for d in args.include_dir]
120154
try:
121-
bundle_header(args.input, args.output, include_dirs)
155+
bundle_header(
156+
args.input,
157+
args.output,
158+
include_dirs,
159+
keep_system_includes=args.keep_system_includes,
160+
)
122161
except FileNotFoundError:
123162
print(f"input not found: {args.input}", file=sys.stderr)
124163
return 1

scripts/combine.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,22 @@ def main() -> int:
6565
default=[],
6666
help="additional include directories (repeatable)",
6767
)
68+
parser.add_argument(
69+
"--keep-system-includes",
70+
action="store_true",
71+
help="keep system includes from expanded library headers",
72+
)
6873
args = parser.parse_args()
6974

7075
include_dirs: list[Path] = [DEFAULT_INCLUDE_DIR, *args.include_dir]
7176

7277
try:
73-
bundle_header(args.input, args.output, include_dirs=include_dirs)
78+
bundle_header(
79+
args.input,
80+
args.output,
81+
include_dirs=include_dirs,
82+
keep_system_includes=args.keep_system_includes,
83+
)
7484
except FileNotFoundError as e:
7585
print(f"input not found: {e}", file=sys.stderr)
7686
return 1

scripts/mkdocs_hooks.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,12 @@ def _refresh_nav(config, status: dict) -> None:
7070

7171
def _bundle_generated_sources() -> None:
7272
for path in INCLUDE_ROOT.rglob("*.hpp"):
73-
bundle_header(path, BUNDLE_ROOT / path.relative_to(INCLUDE_ROOT), include_dirs=[INCLUDE_ROOT])
73+
bundle_header(
74+
path,
75+
BUNDLE_ROOT / path.relative_to(INCLUDE_ROOT),
76+
include_dirs=[INCLUDE_ROOT],
77+
keep_system_includes=True,
78+
)
7479
for path in VERIFY_ROOT.rglob("*.cpp"):
7580
bundle_header(
7681
path,

verify/atcoder/abc453_g_copy_query.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
#include "data_structure/persistent_segtree.hpp"
21
#include <bits/stdc++.h>
32
using namespace std;
43
typedef long long ll;
54

5+
#include "data_structure/persistent_segtree.hpp"
6+
67
ll op(ll a, ll b) { return a + b; }
78
ll e() { return 0; }
89

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,28 @@
1-
#include <iostream>
1+
#include <bits/stdc++.h>
2+
using namespace std;
3+
typedef long long ll;
24

35
#include "tree/lowest_common_ancestor.hpp"
46

57
int main() {
6-
std::ios::sync_with_stdio(false);
7-
std::cin.tie(nullptr);
8+
ios::sync_with_stdio(false);
9+
cin.tie(nullptr);
810

911
int n, q;
10-
std::cin >> n >> q;
12+
cin >> n >> q;
1113

1214
LowestCommonAncestor lca(n);
1315
for (int i = 1; i < n; ++i) {
1416
int p;
15-
std::cin >> p;
17+
cin >> p;
1618
lca.add_edge(i, p);
1719
}
1820
lca.build(0);
1921

2022
while (q--) {
2123
int u, v;
22-
std::cin >> u >> v;
23-
std::cout << lca.lca(u, v) << '\n';
24+
cin >> u >> v;
25+
cout << lca.lca(u, v) << '\n';
2426
}
2527
return 0;
2628
}

verify/status.json

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,67 @@
11
{
22
"verify/library_checker/lowest_common_ancestor.cpp": {
3-
"bundled_hash": "sha256:31b110d1af977ec86883ef1a5b027a300eb177158bf0461fdda946425804ac90",
4-
"verified_at": "2026-06-30T09:24:34+09:00",
3+
"bundled_hash": "sha256:2caac6244953b2ec99079a6b9adae5fe580022ef1c52855cac95042f9b218363",
4+
"verified_at": "2026-07-22T10:08:32+09:00",
55
"judge_url": "https://judge.yosupo.jp/problem/lca",
66
"title": "Lowest Common Ancestor"
77
},
88
"verify/aizu/aoj_3327_beam_beam_beam.cpp": {
9-
"bundled_hash": "sha256:424fdd7da609915c3a8166e07560ff5577cd518c42d7bc4c7bae517e021f164c",
10-
"verified_at": "2026-06-29T14:43:46+09:00",
9+
"bundled_hash": "sha256:a0622055debfb49440a8fc5eb2bd61ceeca24f659cc717d92a17de63114412ed",
10+
"verified_at": "2026-07-22T10:02:57+09:00",
1111
"judge_url": "https://onlinejudge.u-aizu.ac.jp/challenges/sources/VPC/HUPC/3327?year=2023",
1212
"title": "AOJ 3327 - Beam Beam Beam"
1313
},
1414
"verify/library_checker/binomial_coefficient_prime_mod.cpp": {
15-
"bundled_hash": "sha256:cc1226803487d6398f2f5840d7f4057b2933db02286e5afe23ba075d8d826cc3",
16-
"verified_at": "2026-06-29T14:43:46+09:00",
15+
"bundled_hash": "sha256:285e7e4b236a7feea0500bbfcf6c3125ae3fb07ede063ae6804350f337a372b2",
16+
"verified_at": "2026-07-22T10:02:57+09:00",
1717
"judge_url": "https://judge.yosupo.jp/problem/binomial_coefficient_prime_mod",
1818
"title": "Binomial Coefficient (Prime Mod)"
1919
},
2020
"verify/library_checker/z_algorithm.cpp": {
21-
"bundled_hash": "sha256:aaebf3c90bad89ac77b9c50dce3c01a9b2ba4dc9fee3de85fae06ee3968a0ecf",
22-
"verified_at": "2026-04-03T16:57:44+09:00",
21+
"bundled_hash": "sha256:fc3edcef3c4798fb3bce9bdb09ecfbf122002ecd15967e5a58f3f7ab6543bb6c",
22+
"verified_at": "2026-07-22T10:02:57+09:00",
2323
"judge_url": "https://judge.yosupo.jp/problem/zalgorithm",
2424
"title": "Z Algorithm"
2525
},
2626
"verify/atcoder/abc451_g_minimum_xor_walk.cpp": {
27-
"bundled_hash": "sha256:e08a909c7ef0970814f07dacec87e4941d303961d25cf2927a26cca3ce149352",
28-
"verified_at": "2026-07-06T11:32:44+09:00",
27+
"bundled_hash": "sha256:b48d5a49509d6aa4a6ac61dad98a2cf5be4cacefba94701281965a173fed009a",
28+
"verified_at": "2026-07-22T10:02:57+09:00",
2929
"judge_url": "https://atcoder.jp/contests/abc451/tasks/abc451_g",
3030
"title": "ABC451 G - Minimum XOR Walk"
3131
},
3232
"verify/atcoder/abc453_g_copy_query.cpp": {
33-
"bundled_hash": "sha256:26d4aa988ac1d9f8d3a5fa7021f50eca0dd0d8b5e0d9ecf4d41b7966421adb48",
34-
"verified_at": "2026-06-29T14:43:46+09:00",
33+
"bundled_hash": "sha256:9e60728dc55e55ad305ef77c38fd356009cdbf00f90a483714c695a96e5dc36a",
34+
"verified_at": "2026-07-22T10:02:57+09:00",
3535
"judge_url": "https://atcoder.jp/contests/abc453/tasks/abc453_g",
3636
"title": "ABC453 G - Copy Query"
3737
},
3838
"verify/atcoder/abc458_d_chalkboard_median.cpp": {
39-
"bundled_hash": "sha256:d4e5b6ce9758d0d7635f9b8c2648e2c951a798017f6c5e402daae7b7cdb1fec8",
40-
"verified_at": "2026-07-06T11:32:44+09:00",
39+
"bundled_hash": "sha256:7bf5b5119178cff56b7c00be6c3f3d52f5b0915953124d6e6e528d7c7a9918dd",
40+
"verified_at": "2026-07-22T10:02:57+09:00",
4141
"judge_url": "https://atcoder.jp/contests/abc458/tasks/abc458_d",
4242
"title": "ABC458 D - Chalkboard Median"
4343
},
4444
"verify/library_checker/primality_test.cpp": {
45-
"bundled_hash": "sha256:183fcbdb3ffd04390c7035a4e5c8fd1d496f92f58238cd17e144b0c138246390",
46-
"verified_at": "2026-06-29T14:43:46+09:00",
45+
"bundled_hash": "sha256:5abc343080e6b2489927cf08f55e39941a23f2190bd33b722999519ab06e622d",
46+
"verified_at": "2026-07-22T10:02:57+09:00",
4747
"judge_url": "https://judge.yosupo.jp/problem/primality_test",
4848
"title": "Primality Test"
4949
},
5050
"verify/library_checker/factorize.cpp": {
51-
"bundled_hash": "sha256:760b9e0fd093a07214fe777313eadf3b2fcfba59d69c07f3391ba8418c4baf50",
52-
"verified_at": "2026-06-29T14:43:46+09:00",
51+
"bundled_hash": "sha256:518a7501b3505f278c9813c76b86154deb29b916efb9103f081b175265029d2e",
52+
"verified_at": "2026-07-22T10:02:57+09:00",
5353
"judge_url": "https://judge.yosupo.jp/problem/factorize",
5454
"title": "Factorize"
5555
},
5656
"verify/qoj/petrozavodsk_camp_summer_2019_day2_b_bitwise_xor.cpp": {
57-
"bundled_hash": "sha256:65a16b5e46419d16337a90ed90a11b46f9cd65a0520841d40b3d3d99a8c93e76",
58-
"verified_at": "2026-07-06T11:27:04+09:00",
57+
"bundled_hash": "sha256:fc11aeaf5371d942fa1c287d186bc71a506fc8b7f9c7c54b330d4ce8a7719028",
58+
"verified_at": "2026-07-22T10:02:57+09:00",
5959
"judge_url": "https://qoj.ac/contest/1357/problem/7411",
6060
"title": "Petrozavodsk Camp Summer 2019 Day2 B - Bitwise Xor"
6161
},
6262
"verify/library_checker/range_affine_point_get.cpp": {
63-
"bundled_hash": "sha256:d8a8d0c803c5be087c4cf08d9f067b08a5d9a51f2b24660dee7de569290d9455",
64-
"verified_at": "2026-07-22T09:26:40+09:00",
63+
"bundled_hash": "sha256:859dad4ecde63c4793aaa5e3f091f2e92beba46b6436d50484ca11fc6c58111d",
64+
"verified_at": "2026-07-22T10:02:57+09:00",
6565
"judge_url": "https://judge.yosupo.jp/problem/range_affine_point_get",
6666
"title": "Range Affine Point Get"
6767
}

0 commit comments

Comments
 (0)