@@ -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+
21282219class 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+
25582714def 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
25772737if __name__ == "__main__" :
25782738 main ()
0 commit comments