Skip to content

Commit 31408dd

Browse files
committed
[libc++] Implements the new FTM documentation generator.
The new documentation will look like https://discourse.llvm.org/t/rfc-improving-the-feature-test-macro-status-page/78327/5?u=mordante
1 parent 446fd9c commit 31408dd

File tree

2 files changed

+348
-1
lines changed

2 files changed

+348
-1
lines changed
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
# ===----------------------------------------------------------------------===##
2+
#
3+
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
# See https://llvm.org/LICENSE.txt for license information.
5+
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
#
7+
# ===----------------------------------------------------------------------===##
8+
9+
# RUN: %{python} %s %{libcxx-dir}/utils %{libcxx-dir}/test/libcxx/feature_test_macro/test_data.json
10+
11+
import sys
12+
import unittest
13+
14+
UTILS = sys.argv[1]
15+
TEST_DATA = sys.argv[2]
16+
del sys.argv[1:3]
17+
18+
sys.path.append(UTILS)
19+
from generate_feature_test_macro_components import FeatureTestMacros
20+
21+
22+
class Test(unittest.TestCase):
23+
def setUp(self):
24+
self.ftm = FeatureTestMacros(TEST_DATA, ["charconv"])
25+
self.maxDiff = None # This causes the diff to be printed when the test fails
26+
27+
def test_implementeation(self):
28+
expected = """\
29+
.. _FeatureTestMacroTable:
30+
31+
==========================
32+
Feature Test Macro Support
33+
==========================
34+
35+
.. contents::
36+
:local:
37+
38+
Overview
39+
========
40+
41+
This page documents libc++'s implementation status of the Standard library
42+
feature test macros. This page does not list all details, that information can
43+
be found at the `isoccp
44+
<https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations#library-feature-test-macros>`__.
45+
46+
.. _feature-status:
47+
48+
Status
49+
======
50+
51+
.. list-table:: Current Status
52+
:widths: auto
53+
:header-rows: 1
54+
:align: left
55+
56+
* - Macro Name
57+
- Libc++ Value
58+
- Standard Value
59+
-
60+
- Paper
61+
* - | **C++17**
62+
- |
63+
- |
64+
- |
65+
- |
66+
* - | ``__cpp_lib_any``
67+
- | 201606L
68+
- | 201606L
69+
- | ✅
70+
- |
71+
* - | ``__cpp_lib_clamp``
72+
- | 201603L
73+
- | 201603L
74+
- | ✅
75+
- |
76+
* - | ``__cpp_lib_parallel_algorithm``
77+
- | 201603L
78+
- | 201603L
79+
- | ✅
80+
- |
81+
* - | ``__cpp_lib_to_chars``
82+
- | *unimplemented*
83+
- | 201611L
84+
- | ❌
85+
- |
86+
* - | ``__cpp_lib_variant``
87+
- | 202102L
88+
- | 202102L
89+
- | ✅
90+
- | ``std::visit`` for classes derived from ``std::variant``
91+
* - | ``__cpp_lib_zz_missing_FTM_in_older_standard``
92+
- | *unimplemented*
93+
- | 2017L
94+
- | ❌
95+
- | Some FTM missing a paper in an older Standard mode, which should result in the FTM never being defined.
96+
* - | **C++20**
97+
- |
98+
- |
99+
- |
100+
- |
101+
* - | ``__cpp_lib_barrier``
102+
- | 201907L
103+
- | 201907L
104+
- | ✅
105+
- |
106+
* - | ``__cpp_lib_format``
107+
|
108+
|
109+
|
110+
|
111+
- | *unimplemented*
112+
|
113+
|
114+
|
115+
|
116+
- | 201907L
117+
|
118+
| 202106L
119+
| 202110L
120+
|
121+
- | ✅
122+
| ❌
123+
| ✅
124+
| ❌
125+
| ✅
126+
- | `P0645R10 <https://wg21.link/P0645R10>`__ Text Formatting
127+
| `P1361R2 <https://wg21.link/P1361R2>`__ Integration of chrono with text formatting
128+
| `P2216R3 <https://wg21.link/P2216R3>`__ std::format improvements
129+
| `P2372R3 <https://wg21.link/P2372R3>`__ Fixing locale handling in chrono formatters
130+
| `P2418R2 <https://wg21.link/P2418R2>`__ FAdd support for std::generator-like types to std::format
131+
* - | ``__cpp_lib_variant``
132+
- | *unimplemented*
133+
- | 202106L
134+
- | ❌
135+
- | Fully constexpr ``std::variant``
136+
* - | ``__cpp_lib_zz_missing_FTM_in_older_standard``
137+
- | *unimplemented*
138+
- | 2020L
139+
- | ✅
140+
- |
141+
* - | **C++23**
142+
- |
143+
- |
144+
- |
145+
- |
146+
* - | ``__cpp_lib_format``
147+
- | *unimplemented*
148+
- | 202207L
149+
- | ❌
150+
- | `P2419R2 <https://wg21.link/P2419R2>`__ Clarify handling of encodings in localized formatting of chrono types
151+
* - | **C++26**
152+
- |
153+
- |
154+
- |
155+
- |
156+
* - | ``__cpp_lib_barrier``
157+
- | 299900L
158+
- | 299900L
159+
- | ✅
160+
- |
161+
* - | ``__cpp_lib_format``
162+
|
163+
- | *unimplemented*
164+
|
165+
- | 202306L
166+
| 202311L
167+
- | ✅
168+
| ✅
169+
- | `P2637R3 <https://wg21.link/P2637R3>`__ Member Visit
170+
| `P2918R2 <https://wg21.link/P2918R2>`__ Runtime format strings II
171+
* - | ``__cpp_lib_variant``
172+
- | *unimplemented*
173+
- | 202306L
174+
- | ✅
175+
- | Member visit
176+
* - | ``__cpp_lib_zz_missing_FTM_in_older_standard``
177+
- | *unimplemented*
178+
- | 2026L
179+
- | ✅
180+
- |
181+
182+
"""
183+
self.assertEqual(self.ftm.documentation, expected)
184+
185+
186+
if __name__ == "__main__":
187+
unittest.main()

libcxx/utils/generate_feature_test_macro_components.py

Lines changed: 161 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2125,6 +2125,97 @@ def generate_version_header_implementation(
21252125
{tests}\
21262126
"""
21272127

2128+
#
2129+
# The templates used to create a FTM documentation
2130+
#
2131+
2132+
ftm_documentation = """.. _FeatureTestMacroTable:
2133+
2134+
==========================
2135+
Feature Test Macro Support
2136+
==========================
2137+
2138+
.. contents::
2139+
:local:
2140+
2141+
Overview
2142+
========
2143+
2144+
This page documents libc++'s implementation status of the Standard library
2145+
feature test macros. This page does not list all details, that information can
2146+
be found at the `isoccp
2147+
<https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations#library-feature-test-macros>`__.
2148+
2149+
.. _feature-status:
2150+
2151+
Status
2152+
======
2153+
2154+
.. list-table:: Current Status
2155+
:widths: auto
2156+
:header-rows: 1
2157+
:align: left
2158+
2159+
* - Macro Name
2160+
- Libc++ Value
2161+
- Standard Value
2162+
-
2163+
- Paper
2164+
{status_list_table}
2165+
"""
2166+
2167+
def create_table_row(data: List[List[str]]) -> str:
2168+
"""Creates an RST list-table row from the contents of `data`.
2169+
2170+
Data contains one or more elements for a single row for a RST list-table.
2171+
When the list contains more than one element, the data is considered to be
2172+
a multi-row entry. The for a table cell is stored like
2173+
cell = data[row][column].
2174+
2175+
All rows in the table need to have the same number of columns. (This also
2176+
holds true for the "Standard version header rows".)
2177+
2178+
A row for an RST list-table has the following structure:
2179+
* - column 1
2180+
- column 2
2181+
- column 3
2182+
2183+
Note the output is indented.
2184+
2185+
Alternatively it is possible to have cells that "span" multiple rows. This
2186+
is not a real span since all cells are created, however creating an empty
2187+
cell gives the wanted visual effect. These rows have the following
2188+
structure: A row for an RST list-table has the following structure:
2189+
* - | row 1, column 1
2190+
| row 2, column 1
2191+
- | row 1, column 2
2192+
| row 2, column 2
2193+
- | row 1, column 3
2194+
| row 2, column 3
2195+
2196+
Note it is allowed to use the following for a single row:
2197+
* - | column 1
2198+
- | column 2
2199+
- | column 3
2200+
2201+
However the algorithm does not do that.
2202+
"""
2203+
2204+
result = ""
2205+
2206+
cell = "*" # The marker for the first cell in the row
2207+
multi_row = "| " if len(data) > 0 else ""
2208+
# As described above the rows and columns are traversed column first.
2209+
for c in range(len(data[0])):
2210+
column = "-" # The marker for the columns
2211+
for r in range(len(data)):
2212+
result += f" {cell} {column} {multi_row}{data[r][c]}\n"
2213+
cell = " "
2214+
column = " "
2215+
2216+
return result
2217+
2218+
21282219
class FeatureTestMacros:
21292220
"""Provides all feature-test macro (FTM) output components.
21302221
@@ -2284,7 +2375,6 @@ def implemented_ftms(self) -> Dict[Ftm, Dict[Std, Optional[Value]]]:
22842375

22852376
return get_ftms(self.__data, self.std_dialects, True)
22862377

2287-
22882378
def is_implemented(self, ftm: Ftm, std: Std) -> bool:
22892379
"""Has the FTM `ftm` been implemented in the dialect `std`?"""
22902380

@@ -2555,6 +2645,72 @@ def generate_header_test_directory(self, path: os.path) -> None:
25552645
f.write(self.generate_header_test_file(header))
25562646

25572647

2648+
@functools.cached_property
2649+
def status_list_table(self) -> str:
2650+
"""Creates the rst status table using a list-table."""
2651+
2652+
result = ""
2653+
for std in self.std_dialects:
2654+
result += create_table_row(
2655+
[[f'**{std.replace("c++", "C++")}**', "", "", "", ""]]
2656+
)
2657+
2658+
for feature in self.__data:
2659+
if std not in feature["values"].keys():
2660+
continue
2661+
2662+
row = list()
2663+
2664+
ftm = feature["name"]
2665+
libcxx_value = (
2666+
f"{self.standard_ftms[ftm][std]}"
2667+
if self.is_implemented(ftm, std)
2668+
else "*unimplemented*"
2669+
)
2670+
2671+
values = feature["values"][std]
2672+
assert len(values) > 0, f"{feature['name']}[{std}] has no entries"
2673+
for value in values:
2674+
std_value = f"{value}L"
2675+
papers = list(values[value])
2676+
assert (
2677+
len(papers) > 0
2678+
), f"{feature['name']}[{std}][{value}] has no entries"
2679+
2680+
for paper in papers:
2681+
number = "" if not "number" in paper.keys() else paper["number"]
2682+
title = "" if not "title" in paper.keys() else paper["title"]
2683+
implemented = paper["implemented"]
2684+
2685+
row += [
2686+
[
2687+
f"``{ftm}``" if ftm else "",
2688+
libcxx_value,
2689+
std_value,
2690+
"✅" if implemented else "❌",
2691+
(
2692+
f"`{number} <https://wg21.link/{number}>`__ {title}"
2693+
if number
2694+
else f"{title}"
2695+
),
2696+
]
2697+
]
2698+
ftm = ""
2699+
libcxx_value = ""
2700+
std_value = ""
2701+
2702+
result += create_table_row(row)
2703+
2704+
return result
2705+
2706+
2707+
@functools.cached_property
2708+
def documentation(self) -> str:
2709+
"""Generates the FTM documentation."""
2710+
2711+
return ftm_documentation.format(status_list_table=self.status_list_table)
2712+
2713+
25582714
def main():
25592715
produce_version_header()
25602716
produce_tests()
@@ -2573,6 +2729,10 @@ def main():
25732729

25742730
ftm.generate_header_test_directory(macro_test_path)
25752731

2732+
documentation_path = os.path.join(docs_path, "FeatureTestMacroTable.rst")
2733+
with open(documentation_path, "w", newline="\n") as f:
2734+
f.write(ftm.documentation)
2735+
25762736

25772737
if __name__ == "__main__":
25782738
main()

0 commit comments

Comments
 (0)