@@ -2135,6 +2135,97 @@ def generate_version_header_implementation(
21352135{tests}\
21362136 """
21372137
2138+ #
2139+ # The templates used to create a FTM documentation
2140+ #
2141+
2142+ ftm_documentation = """.. _FeatureTestMacroTable:
2143+
2144+ ==========================
2145+ Feature Test Macro Support
2146+ ==========================
2147+
2148+ .. contents::
2149+ :local:
2150+
2151+ Overview
2152+ ========
2153+
2154+ This page documents libc++'s implementation status of the Standard library
2155+ feature test macros. This page does not list all details, that information can
2156+ be found at the `isoccp
2157+ <https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations#library-feature-test-macros>`__.
2158+
2159+ .. _feature-status:
2160+
2161+ Status
2162+ ======
2163+
2164+ .. list-table:: Current Status
2165+ :widths: auto
2166+ :header-rows: 1
2167+ :align: left
2168+
2169+ * - Macro Name
2170+ - Libc++ Value
2171+ - Standard Value
2172+ -
2173+ - Paper
2174+ {status_list_table}
2175+ """
2176+
2177+ def create_table_row (data : List [List [str ]]) -> str :
2178+ """Creates an RST list-table row from the contents of `data`.
2179+
2180+ Data contains one or more elements for a single row for a RST list-table.
2181+ When the list contains more than one element, the data is considered to be
2182+ a multi-row entry. The for a table cell is stored like
2183+ cell = data[row][column].
2184+
2185+ All rows in the table need to have the same number of columns. (This also
2186+ holds true for the "Standard version header rows".)
2187+
2188+ A row for an RST list-table has the following structure:
2189+ * - column 1
2190+ - column 2
2191+ - column 3
2192+
2193+ Note the output is indented.
2194+
2195+ Alternatively it is possible to have cells that "span" multiple rows. This
2196+ is not a real span since all cells are created, however creating an empty
2197+ cell gives the wanted visual effect. These rows have the following
2198+ structure: A row for an RST list-table has the following structure:
2199+ * - | row 1, column 1
2200+ | row 2, column 1
2201+ - | row 1, column 2
2202+ | row 2, column 2
2203+ - | row 1, column 3
2204+ | row 2, column 3
2205+
2206+ Note it is allowed to use the following for a single row:
2207+ * - | column 1
2208+ - | column 2
2209+ - | column 3
2210+
2211+ However the algorithm does not do that.
2212+ """
2213+
2214+ result = ""
2215+
2216+ cell = "*" # The marker for the first cell in the row
2217+ multi_row = "| " if len (data ) > 0 else ""
2218+ # As described above the rows and columns are traversed column first.
2219+ for c in range (len (data [0 ])):
2220+ column = "-" # The marker for the columns
2221+ for r in range (len (data )):
2222+ result += f" { cell } { column } { multi_row } { data [r ][c ]} \n "
2223+ cell = " "
2224+ column = " "
2225+
2226+ return result
2227+
2228+
21382229class FeatureTestMacros :
21392230 """Provides all feature-test macro (FTM) output components.
21402231
@@ -2294,7 +2385,6 @@ def implemented_ftms(self) -> Dict[Ftm, Dict[Std, Optional[Value]]]:
22942385
22952386 return get_ftms (self .__data , self .std_dialects , True )
22962387
2297-
22982388 def is_implemented (self , ftm : Ftm , std : Std ) -> bool :
22992389 """Has the FTM `ftm` been implemented in the dialect `std`?"""
23002390
@@ -2565,6 +2655,72 @@ def generate_header_test_directory(self, path: os.path) -> None:
25652655 f .write (self .generate_header_test_file (header ))
25662656
25672657
2658+ @functools .cached_property
2659+ def status_list_table (self ) -> str :
2660+ """Creates the rst status table using a list-table."""
2661+
2662+ result = ""
2663+ for std in self .std_dialects :
2664+ result += create_table_row (
2665+ [[f'**{ std .replace ("c++" , "C++" )} **' , "" , "" , "" , "" ]]
2666+ )
2667+
2668+ for feature in self .__data :
2669+ if std not in feature ["values" ].keys ():
2670+ continue
2671+
2672+ row = list ()
2673+
2674+ ftm = feature ["name" ]
2675+ libcxx_value = (
2676+ f"{ self .standard_ftms [ftm ][std ]} "
2677+ if self .is_implemented (ftm , std )
2678+ else "*unimplemented*"
2679+ )
2680+
2681+ values = feature ["values" ][std ]
2682+ assert len (values ) > 0 , f"{ feature ['name' ]} [{ std } ] has no entries"
2683+ for value in values :
2684+ std_value = f"{ value } L"
2685+ papers = list (values [value ])
2686+ assert (
2687+ len (papers ) > 0
2688+ ), f"{ feature ['name' ]} [{ std } ][{ value } ] has no entries"
2689+
2690+ for paper in papers :
2691+ number = "" if not "number" in paper .keys () else paper ["number" ]
2692+ title = "" if not "title" in paper .keys () else paper ["title" ]
2693+ implemented = paper ["implemented" ]
2694+
2695+ row += [
2696+ [
2697+ f"``{ ftm } ``" if ftm else "" ,
2698+ libcxx_value ,
2699+ std_value ,
2700+ "✅" if implemented else "❌" ,
2701+ (
2702+ f"`{ number } <https://wg21.link/{ number } >`__ { title } "
2703+ if number
2704+ else f"{ title } "
2705+ ),
2706+ ]
2707+ ]
2708+ ftm = ""
2709+ libcxx_value = ""
2710+ std_value = ""
2711+
2712+ result += create_table_row (row )
2713+
2714+ return result
2715+
2716+
2717+ @functools .cached_property
2718+ def documentation (self ) -> str :
2719+ """Generates the FTM documentation."""
2720+
2721+ return ftm_documentation .format (status_list_table = self .status_list_table )
2722+
2723+
25682724def main ():
25692725 produce_version_header ()
25702726 produce_tests ()
@@ -2583,6 +2739,10 @@ def main():
25832739
25842740 ftm .generate_header_test_directory (macro_test_path )
25852741
2742+ documentation_path = os .path .join (docs_path , "FeatureTestMacroTable.rst" )
2743+ with open (documentation_path , "w" , newline = "\n " ) as f :
2744+ f .write (ftm .documentation )
2745+
25862746
25872747if __name__ == "__main__" :
25882748 main ()
0 commit comments