[llvm-branch-commits] [libcxx] [libc++][format][3/7] Improves std::format performance. (PR #101817)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Sat Aug 3 04:31:54 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: Mark de Wever (mordante)

<details>
<summary>Changes</summary>

This changes the __output_buffer to a new structure. Since the other formatting fucntions std::format_to, std::format_to_n, and std::formatted_size still use the old codepaths the class is in a transition state. At the end of the series the class should be in its final state.

write_double_comparison:

Before
----------------------------------------------------------------------------------------
Benchmark                                              Time             CPU   Iterations
----------------------------------------------------------------------------------------
BM_sprintf                                           197 ns          196 ns      3550000
BM_to_string                                         218 ns          218 ns      3214000
BM_to_chars                                         42.4 ns         42.3 ns     16575000
BM_to_chars_as_string                               48.2 ns         48.1 ns     14542000
BM_format                                            175 ns          175 ns      4000000
BM_format_to_back_inserter<std::string>              175 ns          175 ns      3995000
BM_format_to_back_inserter<std::vector<char>>        207 ns          206 ns      3393000
BM_format_to_back_inserter<std::list<char>>          752 ns          750 ns       931000
BM_format_to_iterator/<std::array>                   161 ns          161 ns      4345000
BM_format_to_iterator/<std::string>                  161 ns          161 ns      4344000
BM_format_to_iterator/<std::vector>                  162 ns          161 ns      4344000

After
----------------------------------------------------------------------------------------
Benchmark                                              Time             CPU   Iterations
----------------------------------------------------------------------------------------
BM_sprintf                                           197 ns          197 ns      3550000
BM_to_string                                         219 ns          219 ns      3199000
BM_to_chars                                         42.4 ns         42.4 ns     16554000
BM_to_chars_as_string                               48.1 ns         48.1 ns     14569000
BM_format                                            167 ns          167 ns      4203000
BM_format_to_back_inserter<std::string>              179 ns          179 ns      3920000
BM_format_to_back_inserter<std::vector<char>>        214 ns          214 ns      3274000
BM_format_to_back_inserter<std::list<char>>          751 ns          751 ns       930000
BM_format_to_iterator/<std::array>                   164 ns          164 ns      4258000
BM_format_to_iterator/<std::string>                  165 ns          164 ns      4247000
BM_format_to_iterator/<std::vector>                  165 ns          165 ns      4248000


Comparison
Benchmark                                                       Time             CPU      Time Old      Time New       CPU Old       CPU New
--------------------------------------------------------------------------------------------------------------------------------------------
BM_sprintf                                                   +0.0013         +0.0028           197           197           196           197
BM_to_string                                                 +0.0023         +0.0038           218           219           218           219
BM_to_chars                                                  +0.0014         +0.0030            42            42            42            42
BM_to_chars_as_string                                        -0.0025         -0.0010            48            48            48            48
BM_format                                                    -0.0476         -0.0462           175           167           175           167
BM_format_to_back_inserter<std::string>                      +0.0190         +0.0205           175           179           175           179
BM_format_to_back_inserter<std::vector<char>>                +0.0348         +0.0363           207           214           206           214
BM_format_to_back_inserter<std::list<char>>                  -0.0013         +0.0005           752           751           750           751
BM_format_to_iterator/<std::array>                           +0.0188         +0.0203           161           164           161           164
BM_format_to_iterator/<std::string>                          +0.0207         +0.0226           161           165           161           164
BM_format_to_iterator/<std::vector>                          +0.0197         +0.0212           162           165           161           165
OVERALL_GEOMEAN                                              +0.0058         +0.0074             0             0             0             0


write_int_comparison:

Before
----------------------------------------------------------------------------------------
Benchmark                                              Time             CPU   Iterations
----------------------------------------------------------------------------------------
BM_sprintf                                          79.6 ns         79.5 ns      8739000
BM_to_string                                        14.9 ns         14.9 ns     46713000
BM_to_chars                                         5.68 ns         5.67 ns    120614000
BM_to_chars_as_string                               14.2 ns         14.1 ns     49513000
BM_format                                           69.3 ns         69.2 ns     10105000
BM_format_to_back_inserter<std::string>             69.2 ns         69.1 ns     10138000
BM_format_to_back_inserter<std::vector<char>>       90.6 ns         90.5 ns      7728000
BM_format_to_back_inserter<std::list<char>>          234 ns          234 ns      2986000
BM_format_to_iterator/<std::array>                  59.3 ns         59.3 ns     11805000
BM_format_to_iterator/<std::string>                 58.7 ns         58.6 ns     11943000
BM_format_to_iterator/<std::vector>                 60.1 ns         60.1 ns     11670000

After
----------------------------------------------------------------------------------------
Benchmark                                              Time             CPU   Iterations
----------------------------------------------------------------------------------------
BM_sprintf                                          80.2 ns         80.2 ns      8670000
BM_to_string                                        15.0 ns         15.0 ns     46559000
BM_to_chars                                         4.93 ns         4.93 ns    138016000
BM_to_chars_as_string                               15.4 ns         15.4 ns     45415000
BM_format                                           62.1 ns         62.0 ns     11316000
BM_format_to_back_inserter<std::string>             70.2 ns         70.2 ns      9962000
BM_format_to_back_inserter<std::vector<char>>       92.8 ns         92.8 ns      7544000
BM_format_to_back_inserter<std::list<char>>          240 ns          240 ns      2917000
BM_format_to_iterator/<std::array>                  60.5 ns         60.5 ns     11572000
BM_format_to_iterator/<std::string>                 60.2 ns         60.2 ns     11653000
BM_format_to_iterator/<std::vector>                 60.1 ns         60.1 ns     11659000


Comparison
Benchmark                                                       Time             CPU      Time Old      Time New       CPU Old       CPU New
--------------------------------------------------------------------------------------------------------------------------------------------
BM_sprintf                                                   +0.0072         +0.0081            80            80            80            80
BM_to_string                                                 +0.0043         +0.0053            15            15            15            15
BM_to_chars                                                  -0.1324         -0.1316             6             5             6             5
BM_to_chars_as_string                                        +0.0895         +0.0906            14            15            14            15
BM_format                                                    -0.1047         -0.1040            69            62            69            62
BM_format_to_back_inserter<std::string>                      +0.0148         +0.0157            69            70            69            70
BM_format_to_back_inserter<std::vector<char>>                +0.0241         +0.0251            91            93            90            93
BM_format_to_back_inserter<std::list<char>>                  +0.0222         +0.0232           234           240           234           240
BM_format_to_iterator/<std::array>                           +0.0196         +0.0205            59            60            59            60
BM_format_to_iterator/<std::string>                          +0.0266         +0.0275            59            60            59            60
BM_format_to_iterator/<std::vector>                          -0.0004         +0.0005            60            60            60            60
OVERALL_GEOMEAN                                              -0.0045         -0.0036             0             0             0             0


write_string_comparison:

Before
---------------------------------------------------------------------------------------------------------------
Benchmark                                                                     Time             CPU   Iterations
---------------------------------------------------------------------------------------------------------------
BM_sprintf/C string len = 6                                                4.82 ns         4.82 ns    145548481
BM_format/C string len = 6                                                 55.1 ns         55.1 ns     12713693
BM_format_to_back_inserter<std::string>/C string len = 6                   55.1 ns         55.1 ns     12690821
BM_format_to_back_inserter<std::vector<char>>/C string len = 6             71.5 ns         71.5 ns      9805550
BM_format_to_back_inserter<std::deque<char>>/C string len = 6               154 ns          154 ns      4536256
BM_format_to_back_inserter<std::list<char>>/C string len = 6                130 ns          130 ns      5348845
BM_format_to_iterator/<std::array> C string len = 6                        44.9 ns         44.9 ns     15556175
BM_format_to_iterator/<std::string> C string len = 6                       45.8 ns         45.8 ns     15290662
BM_format_to_iterator/<std::vector> C string len = 6                       44.4 ns         44.4 ns     15807704
BM_format_to_iterator/<std::deque> C string len = 6                        50.0 ns         50.0 ns     13973893
BM_format/string len = 6                                                   54.7 ns         54.7 ns     12793406
BM_format_to_back_inserter<std::string>/string len = 6                     55.5 ns         55.5 ns     12620370
BM_format_to_back_inserter<std::vector<char>>/string len = 6               70.4 ns         70.4 ns      9936490
BM_format_to_back_inserter<std::deque<char>>/string len = 6                 155 ns          155 ns      4521357
BM_format_to_back_inserter<std::list<char>>/string len = 6                  135 ns          135 ns      5201519
BM_format_to_iterator/<std::array> string len = 6                          44.6 ns         44.6 ns     15703872
BM_format_to_iterator/<std::string> string len = 6                         45.0 ns         45.0 ns     15545182
BM_format_to_iterator/<std::vector> string len = 6                         45.0 ns         45.0 ns     15539130
BM_format_to_iterator/<std::deque> string len = 6                          50.5 ns         50.5 ns     13846916
BM_format/string_view len = 6                                              54.6 ns         54.6 ns     12821301
BM_format_to_back_inserter<std::string>/string_view len = 6                54.6 ns         54.6 ns     12827673
BM_format_to_back_inserter<std::vector<char>>/string_view len = 6          69.9 ns         69.9 ns      9958365
BM_format_to_back_inserter<std::deque<char>>/string_view len = 6            157 ns          157 ns      4462445
BM_format_to_back_inserter<std::list<char>>/string_view len = 6             134 ns          134 ns      5232155
BM_format_to_iterator/<std::array> string_view len = 6                     44.2 ns         44.2 ns     15871362
BM_format_to_iterator/<std::string> string_view len = 6                    45.0 ns         45.0 ns     15582582
BM_format_to_iterator/<std::vector> string_view len = 6                    45.1 ns         45.1 ns     15539906
BM_format_to_iterator/<std::deque> string_view len = 6                     50.5 ns         50.5 ns     13896524
BM_sprintf/C string len = 60                                               4.15 ns         4.15 ns    168165776
BM_format/C string len = 60                                                73.8 ns         73.8 ns      9498291
BM_format_to_back_inserter<std::string>/C string len = 60                  73.6 ns         73.6 ns      9535890
BM_format_to_back_inserter<std::vector<char>>/C string len = 60            83.1 ns         83.1 ns      8428154
BM_format_to_back_inserter<std::deque<char>>/C string len = 60              281 ns          281 ns      2490093
BM_format_to_back_inserter<std::list<char>>/C string len = 60              1157 ns         1157 ns       605227
BM_format_to_iterator/<std::array> C string len = 60                       44.9 ns         44.9 ns     15604442
BM_format_to_iterator/<std::string> C string len = 60                      45.8 ns         45.8 ns     15272196
BM_format_to_iterator/<std::vector> C string len = 60                      44.6 ns         44.7 ns     15683193
BM_format_to_iterator/<std::deque> C string len = 60                       50.6 ns         50.6 ns     13698382
BM_format/string len = 60                                                  72.3 ns         72.3 ns      9648955
BM_format_to_back_inserter<std::string>/string len = 60                    72.0 ns         72.0 ns      9738373
BM_format_to_back_inserter<std::vector<char>>/string len = 60              82.3 ns         82.3 ns      8517896
BM_format_to_back_inserter<std::deque<char>>/string len = 60                280 ns          280 ns      2496054
BM_format_to_back_inserter<std::list<char>>/string len = 60                1162 ns         1162 ns       602383
BM_format_to_iterator/<std::array> string len = 60                         44.5 ns         44.5 ns     15727799
BM_format_to_iterator/<std::string> string len = 60                        49.6 ns         49.6 ns     14096012
BM_format_to_iterator/<std::vector> string len = 60                        49.8 ns         49.8 ns     14053734
BM_format_to_iterator/<std::deque> string len = 60                         50.8 ns         50.8 ns     13801448
BM_format/string_view len = 60                                             72.5 ns         72.5 ns      9653638
BM_format_to_back_inserter<std::string>/string_view len = 60               72.7 ns         72.7 ns      9598203
BM_format_to_back_inserter<std::vector<char>>/string_view len = 60         81.9 ns         81.9 ns      8522306
BM_format_to_back_inserter<std::deque<char>>/string_view len = 60           283 ns          283 ns      2475014
BM_format_to_back_inserter<std::list<char>>/string_view len = 60           1162 ns         1162 ns       600924
BM_format_to_iterator/<std::array> string_view len = 60                    44.1 ns         44.1 ns     15858951
BM_format_to_iterator/<std::string> string_view len = 60                   44.9 ns         44.9 ns     15579340
BM_format_to_iterator/<std::vector> string_view len = 60                   44.9 ns         44.9 ns     15586711
BM_format_to_iterator/<std::deque> string_view len = 60                    50.0 ns         50.0 ns     13980804
BM_sprintf/C string len = 6000                                              116 ns          116 ns      6051541
BM_format/C string len = 6000                                              1000 ns         1000 ns       698647
BM_format_to_back_inserter<std::string>/C string len = 6000                1002 ns         1002 ns       701440
BM_format_to_back_inserter<std::vector<char>>/C string len = 6000           956 ns          956 ns       727585
BM_format_to_back_inserter<std::deque<char>>/C string len = 6000          14898 ns        14898 ns        46994
BM_format_to_back_inserter<std::list<char>>/C string len = 6000          114860 ns       114859 ns         6106
BM_format_to_iterator/<std::array> C string len = 6000                      158 ns          158 ns      4425133
BM_format_to_iterator/<std::string> C string len = 6000                     161 ns          161 ns      4335471
BM_format_to_iterator/<std::vector> C string len = 6000                     157 ns          157 ns      4444174
BM_format_to_iterator/<std::deque> C string len = 6000                      445 ns          445 ns      1574120
BM_format/string len = 6000                                                 929 ns          929 ns       753630
BM_format_to_back_inserter<std::string>/string len = 6000                   930 ns          930 ns       752888
BM_format_to_back_inserter<std::vector<char>>/string len = 6000             910 ns          910 ns       771111
BM_format_to_back_inserter<std::deque<char>>/string len = 6000            14875 ns        14876 ns        47221
BM_format_to_back_inserter<std::list<char>>/string len = 6000            114937 ns       114936 ns         6092
BM_format_to_iterator/<std::array> string len = 6000                        118 ns          118 ns      5963643
BM_format_to_iterator/<std::string> string len = 6000                       106 ns          106 ns      6584711
BM_format_to_iterator/<std::vector> string len = 6000                       106 ns          106 ns      6583118
BM_format_to_iterator/<std::deque> string len = 6000                        391 ns          391 ns      1790538
BM_format/string_view len = 6000                                            935 ns          935 ns       744348
BM_format_to_back_inserter<std::string>/string_view len = 6000              934 ns          934 ns       742039
BM_format_to_back_inserter<std::vector<char>>/string_view len = 6000        895 ns          895 ns       783527
BM_format_to_back_inserter<std::deque<char>>/string_view len = 6000       14864 ns        14865 ns        47122
BM_format_to_back_inserter<std::list<char>>/string_view len = 6000       115042 ns       115044 ns         6091
BM_format_to_iterator/<std::array> string_view len = 6000                   115 ns          115 ns      6070197
BM_format_to_iterator/<std::string> string_view len = 6000                  116 ns          116 ns      6035109
BM_format_to_iterator/<std::vector> string_view len = 6000                  115 ns          115 ns      6067683
BM_format_to_iterator/<std::deque> string_view len = 6000                   387 ns          387 ns      1803466

After
---------------------------------------------------------------------------------------------------------------
Benchmark                                                                     Time             CPU   Iterations
---------------------------------------------------------------------------------------------------------------
BM_sprintf/C string len = 6                                                3.56 ns         3.56 ns    196337806
BM_format/C string len = 6                                                 49.1 ns         49.1 ns     14241174
BM_format_to_back_inserter<std::string>/C string len = 6                   56.8 ns         56.8 ns     12341483
BM_format_to_back_inserter<std::vector<char>>/C string len = 6             72.9 ns         72.9 ns      9610864
BM_format_to_back_inserter<std::deque<char>>/C string len = 6               155 ns          155 ns      4528719
BM_format_to_back_inserter<std::list<char>>/C string len = 6                137 ns          137 ns      5103340
BM_format_to_iterator/<std::array> C string len = 6                        46.4 ns         46.4 ns     15081626
BM_format_to_iterator/<std::string> C string len = 6                       47.0 ns         47.0 ns     14893458
BM_format_to_iterator/<std::vector> C string len = 6                       45.9 ns         45.9 ns     15243762
BM_format_to_iterator/<std::deque> C string len = 6                        52.6 ns         52.6 ns     13323560
BM_format/string len = 6                                                   49.3 ns         49.3 ns     14181485
BM_format_to_back_inserter<std::string>/string len = 6                     55.4 ns         55.4 ns     12644078
BM_format_to_back_inserter<std::vector<char>>/string len = 6               72.7 ns         72.7 ns      9618696
BM_format_to_back_inserter<std::deque<char>>/string len = 6                 154 ns          154 ns      4540873
BM_format_to_back_inserter<std::list<char>>/string len = 6                  134 ns          134 ns      5220153
BM_format_to_iterator/<std::array> string len = 6                          46.5 ns         46.5 ns     15064445
BM_format_to_iterator/<std::string> string len = 6                         47.3 ns         47.3 ns     14786851
BM_format_to_iterator/<std::vector> string len = 6                         46.5 ns         46.5 ns     15069381
BM_format_to_iterator/<std::deque> string len = 6                          52.9 ns         52.9 ns     13207437
BM_format/string_view len = 6                                              47.6 ns         47.6 ns     14688449
BM_format_to_back_inserter<std::string>/string_view len = 6                56.1 ns         56.1 ns     12514239
BM_format_to_back_inserter<std::vector<char>>/string_view len = 6          72.0 ns         72.0 ns      9705591
BM_format_to_back_inserter<std::deque<char>>/string_view len = 6            152 ns          152 ns      4607470
BM_format_to_back_inserter<std::list<char>>/string_view len = 6             134 ns          134 ns      5233005
BM_format_to_iterator/<std::array> string_view len = 6                     46.0 ns         46.0 ns     15205542
BM_format_to_iterator/<std::string> string_view len = 6                    46.5 ns         46.5 ns     15067775
BM_format_to_iterator/<std::vector> string_view len = 6                    46.5 ns         46.5 ns     15057288
BM_format_to_iterator/<std::deque> string_view len = 6                     51.8 ns         51.8 ns     13564649
BM_sprintf/C string len = 60                                               4.83 ns         4.83 ns    145020116
BM_format/C string len = 60                                                72.3 ns         72.3 ns      9665555
BM_format_to_back_inserter<std::string>/C string len = 60                  85.0 ns         85.0 ns      8249050
BM_format_to_back_inserter<std::vector<char>>/C string len = 60            94.7 ns         94.7 ns      7398143
BM_format_to_back_inserter<std::deque<char>>/C string len = 60              286 ns          286 ns      2452225
BM_format_to_back_inserter<std::list<char>>/C string len = 60              1179 ns         1179 ns       595011
BM_format_to_iterator/<std::array> C string len = 60                       46.1 ns         46.1 ns     15157525
BM_format_to_iterator/<std::string> C string len = 60                      47.0 ns         47.0 ns     14899863
BM_format_to_iterator/<std::vector> C string len = 60                      45.8 ns         45.8 ns     15272542
BM_format_to_iterator/<std::deque> C string len = 60                       58.7 ns         58.7 ns     11958910
BM_format/string len = 60                                                  61.7 ns         61.7 ns     11308865
BM_format_to_back_inserter<std::string>/string len = 60                    74.2 ns         74.2 ns      9401855
BM_format_to_back_inserter<std::vector<char>>/string len = 60              86.6 ns         86.6 ns      8079197
BM_format_to_back_inserter<std::deque<char>>/string len = 60                278 ns          278 ns      2519254
BM_format_to_back_inserter<std::list<char>>/string len = 60                1169 ns         1170 ns       597703
BM_format_to_iterator/<std::array> string len = 60                         46.4 ns         46.4 ns     15074759
BM_format_to_iterator/<std::string> string len = 60                        47.3 ns         47.3 ns     14801107
BM_format_to_iterator/<std::vector> string len = 60                        46.3 ns         46.4 ns     15085548
BM_format_to_iterator/<std::deque> string len = 60                         52.2 ns         52.2 ns     13331015
BM_format/string_view len = 60                                             65.0 ns         65.0 ns     10756847
BM_format_to_back_inserter<std::string>/string_view len = 60               78.5 ns         78.5 ns      9051370
BM_format_to_back_inserter<std::vector<char>>/string_view len = 60         87.9 ns         87.9 ns      7946825
BM_format_to_back_inserter<std::deque<char>>/string_view len = 60           280 ns          280 ns      2505999
BM_format_to_back_inserter<std::list<char>>/string_view len = 60           1174 ns         1174 ns       594829
BM_format_to_iterator/<std::array> string_view len = 60                    46.3 ns         46.3 ns     15149785
BM_format_to_iterator/<std::string> string_view len = 60                   46.7 ns         46.7 ns     15002678
BM_format_to_iterator/<std::vector> string_view len = 60                   46.7 ns         46.7 ns     14996445
BM_format_to_iterator/<std::deque> string_view len = 60                    52.6 ns         52.6 ns     13255470
BM_sprintf/C string len = 6000                                             77.1 ns         77.1 ns      9099121
BM_format/C string len = 6000                                               350 ns          350 ns      2013049
BM_format_to_back_inserter<std::string>/C string len = 6000                 992 ns          992 ns       709093
BM_format_to_back_inserter<std::vector<char>>/C string len = 6000          1016 ns         1016 ns       694784
BM_format_to_back_inserter<std::deque<char>>/C string len = 6000          15158 ns        15159 ns        46125
BM_format_to_back_inserter<std::list<char>>/C string len = 6000          115703 ns       115705 ns         6055
BM_format_to_iterator/<std::array> C string len = 6000                      166 ns          166 ns      4224749
BM_format_to_iterator/<std::string> C string len = 6000                     153 ns          153 ns      4573034
BM_format_to_iterator/<std::vector> C string len = 6000                     150 ns          150 ns      4678898
BM_format_to_iterator/<std::deque> C string len = 6000                      465 ns          465 ns      1506323
BM_format/string len = 6000                                                 281 ns          281 ns      2462572
BM_format_to_back_inserter<std::string>/string len = 6000                   935 ns          935 ns       745376
BM_format_to_back_inserter<std::vector<char>>/string len = 6000             939 ns          939 ns       747498
BM_format_to_back_inserter<std::deque<char>>/string len = 6000            15069 ns        15069 ns        46429
BM_format_to_back_inserter<std::list<char>>/string len = 6000            115537 ns       115539 ns         6063
BM_format_to_iterator/<std::array> string len = 6000                        120 ns          120 ns      5849159
BM_format_to_iterator/<std::string> string len = 6000                       108 ns          108 ns      6482306
BM_format_to_iterator/<std::vector> string len = 6000                       107 ns          107 ns      6547915
BM_format_to_iterator/<std::deque> string len = 6000                        397 ns          397 ns      1763729
BM_format/string_view len = 6000                                            282 ns          282 ns      2490133
BM_format_to_back_inserter<std::string>/string_view len = 6000              927 ns          927 ns       750931
BM_format_to_back_inserter<std::vector<char>>/string_view len = 6000        946 ns          946 ns       735544
BM_format_to_back_inserter<std::deque<char>>/string_view len = 6000       15028 ns        15029 ns        46612
BM_format_to_back_inserter<std::list<char>>/string_view len = 6000       115153 ns       115153 ns         6057
BM_format_to_iterator/<std::array> string_view len = 6000                   122 ns          122 ns      5753940
BM_format_to_iterator/<std::string> string_view len = 6000                  108 ns          108 ns      6507555
BM_format_to_iterator/<std::vector> string_view len = 6000                  107 ns          107 ns      6510450
BM_format_to_iterator/<std::deque> string_view len = 6000                   398 ns          398 ns      1762517

Comparison
Benchmark                                                                              Time             CPU      Time Old      Time New       CPU Old       CPU New
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
BM_sprintf/C string len = 6                                                         -0.2599         -0.2599             5             4             5             4
BM_format/C string len = 6                                                          -0.1094         -0.1095            55            49            55            49
BM_format_to_back_inserter<std::string>/C string len = 6                            +0.0316         +0.0316            55            57            55            57
BM_format_to_back_inserter<std::vector<char>>/C string len = 6                      +0.0204         +0.0204            71            73            71            73
BM_format_to_back_inserter<std::deque<char>>/C string len = 6                       +0.0023         +0.0023           154           155           154           155
BM_format_to_back_inserter<std::list<char>>/C string len = 6                        +0.0521         +0.0520           130           137           130           137
BM_format_to_iterator/<std::array> C string len = 6                                 +0.0317         +0.0317            45            46            45            46
BM_format_to_iterator/<std::string> C string len = 6                                +0.0265         +0.0265            46            47            46            47
BM_format_to_iterator/<std::vector> C string len = 6                                +0.0345         +0.0345            44            46            44            46
BM_format_to_iterator/<std::deque> C string len = 6                                 +0.0511         +0.0511            50            53            50            53
BM_format/string len = 6                                                            -0.0981         -0.0981            55            49            55            49
BM_format_to_back_inserter<std::string>/string len = 6                              -0.0028         -0.0028            56            55            56            55
BM_format_to_back_inserter<std::vector<char>>/string len = 6                        +0.0331         +0.0331            70            73            70            73
BM_format_to_back_inserter<std::deque<char>>/string len = 6                         -0.0040         -0.0040           155           154           155           154
BM_format_to_back_inserter<std::list<char>>/string len = 6                          -0.0019         -0.0019           135           134           135           134
BM_format_to_iterator/<std::array> string len = 6                                   +0.0427         +0.0427            45            46            45            46
BM_format_to_iterator/<std::string> string len = 6                                  +0.0515         +0.0515            45            47            45            47
BM_format_to_iterator/<std::vector> string len = 6                                  +0.0316         +0.0316            45            46            45            46
BM_format_to_iterator/<std::deque> string len = 6                                   +0.0475         +0.0475            51            53            51            53
BM_format/string_view len = 6                                                       -0.1267         -0.1267            55            48            55            48
BM_format_to_back_inserter<std::string>/string_view len = 6                         +0.0283         +0.0283            55            56            55            56
BM_format_to_back_inserter<std::vector<char>>/string_view len = 6                   +0.0291         +0.0291            70            72            70            72
BM_format_to_back_inserter<std::deque<char>>/string_view len = 6                    -0.0305         -0.0306           157           152           157           152
BM_format_to_back_inserter<std::list<char>>/string_view len = 6                     -0.0012         -0.0012           134           134           134           134
BM_format_to_iterator/<std::array> string_view len = 6                              +0.0426         +0.0426            44            46            44            46
BM_format_to_iterator/<std::string> string_view len = 6                             +0.0322         +0.0322            45            46            45            46
BM_format_to_iterator/<std::vector> string_view len = 6                             +0.0309         +0.0309            45            46            45            46
BM_format_to_iterator/<std::deque> string_view len = 6                              +0.0248         +0.0248            51            52            51            52
BM_sprintf/C string len = 60                                                        +0.1633         +0.1633             4             5             4             5
BM_format/C string len = 60                                                         -0.0203         -0.0203            74            72            74            72
BM_format_to_back_inserter<std::string>/C string len = 60                           +0.1548         +0.1548            74            85            74            85
BM_format_to_back_inserter<std::vector<char>>/C string len = 60                     +0.1395         +0.1395            83            95            83            95
BM_format_to_back_inserter<std::deque<char>>/C string len = 60                      +0.0157         +0.0157           281           286           281           286
BM_format_to_back_inserter<std::list<char>>/C string len = 60                       +0.0191         +0.0191          1157          1179          1157          1179
BM_format_to_iterator/<std::array> C string len = 60                                +0.0283         +0.0283            45            46            45            46
BM_format_to_iterator/<std::string> C string len = 60                               +0.0251         +0.0252            46            47            46            47
BM_format_to_iterator/<std::vector> C string len = 60                               +0.0263         +0.0263            45            46            45            46
BM_format_to_iterator/<std::deque> C string len = 60                                +0.1592         +0.1591            51            59            51            59
BM_format/string len = 60                                                           -0.1466         -0.1466            72            62            72            62
BM_format_to_back_inserter<std::string>/string len = 60                             +0.0299         +0.0299            72            74            72            74
BM_format_to_back_inserter<std::vector<char>>/string len = 60                       +0.0522         +0.0522            82            87            82            87
BM_format_to_back_inserter<std::deque<char>>/string len = 60                        -0.0099         -0.0099           280           278           280           278
BM_format_to_back_inserter<std::list<char>>/string len = 60                         +0.0062         +0.0062          1162          1169          1162          1170
BM_format_to_iterator/<std::array> string len = 60                                  +0.0430         +0.0430            45            46            45            46
BM_format_to_iterator/<std::string> string len = 60                                 -0.0466         -0.0466            50            47            50            47
BM_format_to_iterator/<std::vector> string len = 60                                 -0.0693         -0.0693            50            46            50            46
BM_format_to_iterator/<std::deque> string len = 60                                  +0.0275         +0.0275            51            52            51            52
BM_format/string_view len = 60                                                      -0.1034         -0.1034            73            65            73            65
BM_format_to_back_inserter<std::string>/string_view len = 60                        +0.0790         +0.0790            73            78            73            78
BM_format_to_back_inserter<std::vector<char>>/string_view len = 60                  +0.0735         +0.0735            82            88            82            88
BM_format_to_back_inserter<std::deque<char>>/string_view len = 60                   -0.0103         -0.0104           283           280           283           280
BM_format_to_back_inserter<std::list<char>>/string_view len = 60                    +0.0101         +0.0101          1162          1174          1162          1174
BM_format_to_iterator/<std::array> string_view len = 60                             +0.0484         +0.0484            44            46            44            46
BM_format_to_iterator/<std::string> string_view len = 60                            +0.0387         +0.0387            45            47            45            47
BM_format_to_iterator/<std::vector> string_view len = 60                            +0.0402         +0.0402            45            47            45            47
BM_format_to_iterator/<std::deque> string_view len = 60                             +0.0508         +0.0508            50            53            50            53
BM_sprintf/C string len = 6000                                                      -0.3337         -0.3337           116            77           116            77
BM_format/C string len = 6000                                                       -0.6500         -0.6500          1000           350          1000           350
BM_format_to_back_inserter<std::string>/C string len = 6000                         -0.0104         -0.0105          1002           992          1002           992
BM_format_to_back_inserter<std::vector<char>>/C string len = 6000                   +0.0630         +0.0630           956          1016           956          1016
BM_format_to_back_inserter<std::deque<char>>/C string len = 6000                    +0.0175         +0.0175         14898         15158         14898         15159
BM_format_to_back_inserter<std::list<char>>/C string len = 6000                     +0.0073         +0.0074        114860        115703        114859        115705
BM_format_to_iterator/<std::array> C string len = 6000                              +0.0504         +0.0504           158           166           158           166
BM_format_to_iterator/<std::string> C string len = 6000                             -0.0486         -0.0486           161           153           161           153
BM_format_to_iterator/<std::vector> C string len = 6000                             -0.0483         -0.0483           157           150           157           150
BM_format_to_iterator/<std::deque> C string len = 6000                              +0.0459         +0.0459           445           465           445           465
BM_format/string len = 6000                                                         -0.6975         -0.6975           929           281           929           281
BM_format_to_back_inserter<std::string>/string len = 6000                           +0.0050         +0.0050           930           935           930           935
BM_format_to_back_inserter<std::vector<char>>/string len = 6000                     +0.0321         +0.0322           910           939           910           939
BM_format_to_back_inserter<std::deque<char>>/string len = 6000                      +0.0130         +0.0130         14875         15069         14876         15069
BM_format_to_back_inserter<std::list<char>>/string len = 6000                       +0.0052         +0.0052        114937        115537        114936        115539
BM_format_to_iterator/<std::array> string len = 6000                                +0.0211         +0.0211           118           120           118           120
BM_format_to_iterator/<std::string> string len = 6000                               +0.0146         +0.0146           106           108           106           108
BM_format_to_iterator/<std::vector> string len = 6000                               +0.0048         +0.0048           106           107           106           107
BM_format_to_iterator/<std::deque> string len = 6000                                +0.0150         +0.0150           391           397           391           397
BM_format/string_view len = 6000                                                    -0.6989         -0.6989           935           282           935           282
BM_format_to_back_inserter<std::string>/string_view len = 6000                      -0.0083         -0.0083           934           927           934           927
BM_format_to_back_inserter<std::vector<char>>/string_view len = 6000                +0.0566         +0.0566           895           946           895           946
BM_format_to_back_inserter<std::deque<char>>/string_view len = 6000                 +0.0111         +0.0110         14864         15028         14865         15029
BM_format_to_back_inserter<std::list<char>>/string_view len = 6000                  +0.0010         +0.0009        115042        115153        115044        115153
BM_format_to_iterator/<std::array> string_view len = 6000                           +0.0560         +0.0560           115           122           115           122
BM_format_to_iterator/<std::string> string_view len = 6000                          -0.0693         -0.0693           116           108           116           108
BM_format_to_iterator/<std::vector> string_view len = 6000                          -0.0703         -0.0703           115           107           115           107
BM_format_to_iterator/<std::deque> string_view len = 6000                           +0.0271         +0.0271           387           398           387           398
OVERALL_GEOMEAN                                                                     -0.0350         -0.0350             0             0             0             0


format:
Before
--------------------------------------------------------------------------------------------
Benchmark                                  Time             CPU   Iterations UserCounters...
--------------------------------------------------------------------------------------------
BM_format_string<char>/1                55.5 ns         55.5 ns     12463288 bytes_per_second=17.187Mi/s
BM_format_string<char>/2                27.6 ns         27.6 ns     25421994 bytes_per_second=69.1874Mi/s
BM_format_string<char>/4                14.0 ns         14.0 ns     49785656 bytes_per_second=271.524Mi/s
BM_format_string<char>/8                7.07 ns         7.07 ns     99247048 bytes_per_second=1.05444Gi/s
BM_format_string<char>/16               3.53 ns         3.53 ns    198072224 bytes_per_second=4.21726Gi/s
BM_format_string<char>/32               2.31 ns         2.31 ns    302771136 bytes_per_second=12.9138Gi/s
BM_format_string<char>/64               1.15 ns         1.15 ns    606646976 bytes_per_second=51.7527Gi/s
BM_format_string<char>/128             0.597 ns        0.597 ns   1172263936 bytes_per_second=199.688Gi/s
BM_format_string<char>/256             0.327 ns        0.327 ns   2148927744 bytes_per_second=728.678Gi/s
BM_format_string<char>/512             0.248 ns        0.248 ns   2821635584 bytes_per_second=1.8779Ti/s
BM_format_string<char>/1024            0.203 ns        0.203 ns   3433579520 bytes_per_second=4.57798Ti/s
BM_format_string<char>/2048            0.164 ns        0.164 ns   4277524480 bytes_per_second=11.3793Ti/s
BM_format_string<char>/4096            0.137 ns        0.137 ns   5122269184 bytes_per_second=27.2589Ti/s
BM_format_string<char>/8192            0.126 ns        0.126 ns   5564243968 bytes_per_second=59.2812Ti/s
BM_format_string<char>/16384           0.136 ns        0.136 ns   5153013760 bytes_per_second=109.492Ti/s
BM_format_string<char>/32768           0.135 ns        0.135 ns   5165088768 bytes_per_second=219.985Ti/s
BM_format_string<char>/65536           0.243 ns        0.242 ns   2930180096 bytes_per_second=246.57Ti/s
BM_format_string<char>/131072          0.490 ns        0.489 ns   1437990912 bytes_per_second=243.75Ti/s
BM_format_string<char>/262144          0.593 ns        0.592 ns   1183055872 bytes_per_second=402.931Ti/s
BM_format_string<char>/524288          0.643 ns        0.641 ns   1092616192 bytes_per_second=743.445Ti/s
BM_format_string<char>/1048576         0.669 ns        0.668 ns   1045430272 bytes_per_second=1.39478Pi/s
BM_format_string<wchar_t>/1             56.0 ns         55.9 ns     12511543 bytes_per_second=68.2628Mi/s
BM_format_string<wchar_t>/2             28.0 ns         27.9 ns     25062366 bytes_per_second=273.519Mi/s
BM_format_string<wchar_t>/4             14.0 ns         14.0 ns     50257068 bytes_per_second=1.06742Gi/s
BM_format_string<wchar_t>/8             9.24 ns         9.21 ns     76118616 bytes_per_second=3.23473Gi/s
BM_format_string<wchar_t>/16            4.66 ns         4.65 ns    151420352 bytes_per_second=12.8261Gi/s
BM_format_string<wchar_t>/32            2.35 ns         2.35 ns    298417600 bytes_per_second=50.7972Gi/s
BM_format_string<wchar_t>/64            1.35 ns         1.34 ns    521608704 bytes_per_second=177.502Gi/s
BM_format_string<wchar_t>/128           1.03 ns         1.03 ns    680946304 bytes_per_second=463.91Gi/s
BM_format_string<wchar_t>/256          0.849 ns        0.847 ns    825871104 bytes_per_second=1.09901Ti/s
BM_format_string<wchar_t>/512          0.681 ns        0.679 ns   1033245696 bytes_per_second=2.74383Ti/s
BM_format_string<wchar_t>/1024         0.576 ns        0.575 ns   1219777536 bytes_per_second=6.48343Ti/s
BM_format_string<wchar_t>/2048         0.515 ns        0.514 ns   1361629184 bytes_per_second=14.4881Ti/s
BM_format_string<wchar_t>/4096         0.546 ns        0.545 ns   1285427200 bytes_per_second=27.3342Ti/s
BM_format_string<wchar_t>/8192         0.550 ns        0.548 ns   1277042688 bytes_per_second=54.3343Ti/s
BM_format_string<wchar_t>/16384        0.583 ns        0.581 ns   1203879936 bytes_per_second=102.544Ti/s
BM_format_string<wchar_t>/32768        0.640 ns        0.638 ns   1095139328 bytes_per_second=186.82Ti/s
BM_format_string<wchar_t>/65536        0.642 ns        0.640 ns   1093337088 bytes_per_second=372.283Ti/s
BM_format_string<wchar_t>/131072       0.655 ns        0.654 ns   1070596096 bytes_per_second=729.428Ti/s
BM_format_string<wchar_t>/262144        2.68 ns         2.67 ns    262406144 bytes_per_second=357.446Ti/s
BM_format_string<wchar_t>/524288        2.13 ns         2.13 ns    330301440 bytes_per_second=897.574Ti/s
BM_format_string<wchar_t>/1048576       2.44 ns         2.43 ns    288358400 bytes_per_second=1.53149Pi/s

After
--------------------------------------------------------------------------------------------
Benchmark                                  Time             CPU   Iterations UserCounters...
--------------------------------------------------------------------------------------------
BM_format_string<char>/1                49.3 ns         49.1 ns     14230742 bytes_per_second=19.4054Mi/s
BM_format_string<char>/2                24.8 ns         24.8 ns     28253114 bytes_per_second=77.0465Mi/s
BM_format_string<char>/4                12.4 ns         12.4 ns     56381440 bytes_per_second=307.462Mi/s
BM_format_string<char>/8                6.23 ns         6.21 ns    112951232 bytes_per_second=1.19924Gi/s
BM_format_string<char>/16               3.10 ns         3.09 ns    225822496 bytes_per_second=4.81566Gi/s
BM_format_string<char>/32               1.98 ns         1.98 ns    354208192 bytes_per_second=15.0825Gi/s
BM_format_string<char>/64              0.990 ns        0.987 ns    714296384 bytes_per_second=60.3689Gi/s
BM_format_string<char>/128             0.504 ns        0.503 ns   1399988480 bytes_per_second=237.144Gi/s
BM_format_string<char>/256             0.335 ns        0.334 ns   2084828928 bytes_per_second=712.859Gi/s
BM_format_string<char>/512             0.187 ns        0.186 ns   3760082432 bytes_per_second=2.50102Ti/s
BM_format_string<char>/1024            0.109 ns        0.108 ns   6455339008 bytes_per_second=8.59552Ti/s
BM_format_string<char>/2048            0.080 ns        0.080 ns   8754006016 bytes_per_second=23.2731Ti/s
BM_format_string<char>/4096            0.051 ns        0.051 ns   13786701824 bytes_per_second=73.4088Ti/s
BM_format_string<char>/8192            0.042 ns        0.042 ns   16851435520 bytes_per_second=178.737Ti/s
BM_format_string<char>/16384           0.122 ns        0.122 ns   5746589696 bytes_per_second=122.029Ti/s
BM_format_string<char>/32768           0.107 ns        0.106 ns   6571687936 bytes_per_second=280.122Ti/s
BM_format_string<char>/65536           0.102 ns        0.102 ns   6876626944 bytes_per_second=584.381Ti/s
BM_format_string<char>/131072          0.106 ns        0.105 ns   6643122176 bytes_per_second=1.10413Pi/s
BM_format_string<char>/262144          0.589 ns        0.587 ns   1189609472 bytes_per_second=406.438Ti/s
BM_format_string<char>/524288          0.644 ns        0.642 ns   1088946176 bytes_per_second=743.064Ti/s
BM_format_string<char>/1048576         0.672 ns        0.670 ns   1039138816 bytes_per_second=1.38968Pi/s
BM_format_string<wchar_t>/1             48.7 ns         48.6 ns     14423178 bytes_per_second=78.5263Mi/s
BM_format_string<wchar_t>/2             24.4 ns         24.3 ns     28831748 bytes_per_second=313.869Mi/s
BM_format_string<wchar_t>/4             12.2 ns         12.2 ns     57661220 bytes_per_second=1.2253Gi/s
BM_format_string<wchar_t>/8             7.81 ns         7.79 ns     89887592 bytes_per_second=3.82675Gi/s
BM_format_string<wchar_t>/16            3.88 ns         3.87 ns    180450176 bytes_per_second=15.418Gi/s
BM_format_string<wchar_t>/32            1.98 ns         1.98 ns    354046112 bytes_per_second=60.3262Gi/s
BM_format_string<wchar_t>/64            1.02 ns         1.01 ns    689511680 bytes_per_second=234.906Gi/s
BM_format_string<wchar_t>/128          0.577 ns        0.576 ns   1215361408 bytes_per_second=828.297Gi/s
BM_format_string<wchar_t>/256          0.804 ns        0.802 ns    872249088 bytes_per_second=1.16111Ti/s
BM_format_string<wchar_t>/512          0.642 ns        0.641 ns   1093858304 bytes_per_second=2.90766Ti/s
BM_format_string<wchar_t>/1024         0.517 ns        0.516 ns   1354798080 bytes_per_second=7.21845Ti/s
BM_format_string<wchar_t>/2048         0.469 ns        0.467 ns   1491910656 bytes_per_second=15.9386Ti/s
BM_format_string<wchar_t>/4096         0.794 ns        0.792 ns    883822592 bytes_per_second=18.8156Ti/s
BM_format_string<wchar_t>/8192         0.722 ns        0.720 ns    971718656 bytes_per_second=41.3996Ti/s
BM_format_string<wchar_t>/16384        0.703 ns        0.701 ns    998031360 bytes_per_second=85.0369Ti/s
BM_format_string<wchar_t>/32768        0.724 ns        0.720 ns    971538432 bytes_per_second=165.467Ti/s
BM_format_string<wchar_t>/65536        0.745 ns        0.744 ns    941228032 bytes_per_second=320.665Ti/s
BM_format_string<wchar_t>/131072       0.742 ns        0.740 ns    945422336 bytes_per_second=644.032Ti/s
BM_format_string<wchar_t>/262144        2.99 ns         2.98 ns    234881024 bytes_per_second=319.75Ti/s
BM_format_string<wchar_t>/524288        3.31 ns         3.30 ns    212860928 bytes_per_second=578.085Ti/s
BM_format_string<wchar_t>/1048576       2.69 ns         2.68 ns    260046848 bytes_per_second=1.39081Pi/s

Comparison
Benchmark                                           Time             CPU      Time Old      Time New       CPU Old       CPU New
--------------------------------------------------------------------------------------------------------------------------------
BM_format_string<char>/1                         -0.1122         -0.1143            55            49            55            49
BM_format_string<char>/2                         -0.0999         -0.1020            28            25            28            25
BM_format_string<char>/4                         -0.1148         -0.1169            14            12            14            12
BM_format_string<char>/8                         -0.1186         -0.1207             7             6             7             6
BM_format_string<char>/16                        -0.1222         -0.1243             4             3             4             3
BM_format_string<char>/32                        -0.1417         -0.1438             2             2             2             2
BM_format_string<char>/64                        -0.1407         -0.1427             1             1             1             1
BM_format_string<char>/128                       -0.1559         -0.1579             1             1             1             1
BM_format_string<char>/256                       +0.0249         +0.0222             0             0             0             0
BM_format_string<char>/512                       -0.2473         -0.2491             0             0             0             0
BM_format_string<char>/1024                      -0.4661         -0.4674             0             0             0             0
BM_format_string<char>/2048                      -0.5096         -0.5111             0             0             0             0
BM_format_string<char>/4096                      -0.6278         -0.6287             0             0             0             0
BM_format_string<char>/8192                      -0.6674         -0.6683             0             0             0             0
BM_format_string<char>/16384                     -0.1005         -0.1027             0             0             0             0
BM_format_string<char>/32768                     -0.2127         -0.2147             0             0             0             0
BM_format_string<char>/65536                     -0.5796         -0.5781             0             0             0             0
BM_format_string<char>/131072                    -0.7844         -0.7844             0             0             0             0
BM_format_string<char>/262144                    -0.0073         -0.0086             1             1             1             1
BM_format_string<char>/524288                    +0.0017         +0.0005             1             1             1             1
BM_format_string<char>/1048576                   +0.0039         +0.0037             1             1             1             1
BM_format_string<wchar_t>/1                      -0.1304         -0.1307            56            49            56            49
BM_format_string<wchar_t>/2                      -0.1285         -0.1286            28            24            28            24
BM_format_string<wchar_t>/4                      -0.1288         -0.1288            14            12            14            12
BM_format_string<wchar_t>/8                      -0.1547         -0.1547             9             8             9             8
BM_format_string<wchar_t>/16                     -0.1681         -0.1681             5             4             5             4
BM_format_string<wchar_t>/32                     -0.1579         -0.1580             2             2             2             2
BM_format_string<wchar_t>/64                     -0.2443         -0.2444             1             1             1             1
BM_format_string<wchar_t>/128                    -0.4400         -0.4399             1             1             1             1
BM_format_string<wchar_t>/256                    -0.0535         -0.0535             1             1             1             1
BM_format_string<wchar_t>/512                    -0.0563         -0.0563             1             1             1             1
BM_format_string<wchar_t>/1024                   -0.1018         -0.1018             1             1             1             1
BM_format_string<wchar_t>/2048                   -0.0910         -0.0910             1             0             1             0
BM_format_string<wchar_t>/4096                   +0.4528         +0.4527             1             1             1             1
BM_format_string<wchar_t>/8192                   +0.3121         +0.3124             1             1             1             1
BM_format_string<wchar_t>/16384                  +0.2059         +0.2059             1             1             1             1
BM_format_string<wchar_t>/32768                  +0.1316         +0.1290             1             1             1             1
BM_format_string<wchar_t>/65536                  +0.1604         +0.1610             1             1             1             1
BM_format_string<wchar_t>/131072                 +0.1326         +0.1326             1             1             1             1
BM_format_string<wchar_t>/262144                 +0.1181         +0.1179             3             3             3             3
BM_format_string<wchar_t>/524288                 +0.5515         +0.5527             2             3             2             3
BM_format_string<wchar_t>/1048576                +0.1007         +0.1011             2             3             2             3
OVERALL_GEOMEAN                                  -0.1685         -0.1693             0             0             0             0

---
Full diff: https://github.com/llvm/llvm-project/pull/101817.diff


2 Files Affected:

- (modified) libcxx/include/__format/buffer.h (+237-18) 
- (modified) libcxx/include/__format/format_functions.h (+12-12) 


``````````diff
diff --git a/libcxx/include/__format/buffer.h b/libcxx/include/__format/buffer.h
index 8598f0a1c0395..1f26bfa923a6a 100644
--- a/libcxx/include/__format/buffer.h
+++ b/libcxx/include/__format/buffer.h
@@ -58,23 +58,156 @@ namespace __format {
 /// This helper is used together with the @ref back_insert_iterator to offer
 /// type-erasure for the formatting functions. This reduces the number to
 /// template instantiations.
+///
+/// The design of the class is being changed to improve performance and do some
+/// code cleanups.
+/// The original design (as shipped up to LLVM-19) uses the following design:
+/// - There is an external object that connects the buffer to the output.
+/// - The class constructor stores a function pointer to a grow function and a
+///   type-erased pointer to the object that does the grow.
+/// - When writing data to the buffer would exceed the external buffer's
+///   capacity it requests the external buffer to flush its contents.
+///
+/// The new design tries to solve some issues with the current design:
+/// - The buffer used is a fixed-size buffer, benchmarking shows that using a
+///   dynamic allocated buffer has performance benefits.
+/// - Implementing P3107R5 "Permit an efficient implementation of std::print"
+///   is not trivial with the current buffers. Using the code from this series
+///   makes it trivial.
+///
+/// This class is ABI-tagged, still the new design does not change the size of
+/// objects of this class.
+///
+/// The new design contains information regarding format_to_n changes, these
+/// will be implemented in follow-up patch.
+///
+/// The new design is the following.
+/// - There is an external object that connects the buffer to the output.
+/// - This buffer object:
+///   - inherits publicly from this class.
+///   - has a static or dynamic buffer.
+///   - has a static member function to make space in its buffer write
+///     operations. This can be done by increasing the size of the internal
+///     buffer or by writing the contents of the buffer to the output iterator.
+///
+///     This member function is a constructor argument, so its name is not
+///     fixed. The code uses the name __prepare_write.
+/// - The number of output code units can be limited by a __max_output_size
+///   object. This is used in format_to_n This object:
+///   - Contains the maximum number of code units to be written.
+///   - Contains the number of code units that are requested to be written.
+///     This number is returned to the user of format_to_n.
+///   - The write functions call objects __request_write member function.
+///     This function:
+///     - Updates the number of code units that are requested to be written.
+///     - Returns the number of code units that can be written without
+///       exceeding the maximum number of code units to be written.
+///
+/// Documentation for the buffer usage members:
+/// - __ptr_ the start of the buffer.
+/// - __capacity_ the number of code units that can be written.
+///   This means [__ptr_, __ptr_ + __capacity_) is a valid range to write to.
+/// - __size_ the number of code units written in the buffer. The next code
+///   unit will be written at __ptr_ + __size_. This __size_ may NOT contain
+///   the total number of code units written by the __output_buffer. Whether or
+///   not it does depends on the sub-class used. Typically the total number of
+///   code units written is not interesting. It is interesting for format_to_n
+///   which has its own way to track this number.
+///
+/// Documentation for the buffer changes function:
+/// The subclasses have a function with the following signature:
+///
+///   static void __prepare_write(
+///     __output_buffer<_CharT>& __buffer, size_t __code_units);
+///
+/// This function is called when a write function writes more code units than
+/// the buffer' available space. When an __max_output_size object is provided
+/// the number of code units is the number of code units returned from
+/// __max_output_size::__request_write function.
+///
+/// - The __buffer contains *this. Since the class containing this function
+///   inherits from __output_buffer it's save to cast it to the subclass being
+///   used.
+/// - The __code_units is the number of code units the caller will write + 1.
+///   - This value does not take the avaiable space of the buffer into account.
+///   - The push_back function is more efficient when writing before resizing,
+///     this means the buffer should always have room for one code unit. Hence
+///     the + 1 is the size.
+/// - When the function returns there is room for at least one code unit. There
+///   is no requirement there is room for __code_units code units:
+///   - The class has some "bulk" operations. For example, __copy which copies
+///     the contents of a basic_string_view to the output. If the sub-class has
+///     a fixed size buffer the size of the basic_string_view may be larger
+///     than the buffer. In that case it's impossible to honor the requested
+///     size.
+///   - The at least one code unit makes sure the entire output can be written.
+///     (Obviously making room one code unit at a time is slow and
+///     it's recommended to return a larger available space.)
+///   - When the buffer has room for at least one code unit the function may be
+///     a no-op.
+/// - When the function makes space for more code units it uses one for these
+///   functions to signal the change:
+///   - __buffer_flushed()
+///     - This function is typically used for a fixed sized buffer.
+///     - The current contents of [__ptr_, __ptr_ + __size_) have been
+///       processed.
+///     - __ptr_ remains unchanged.
+///     - __capacity_ remains unchanged.
+///     - __size_ will be set to 0.
+///   - __buffer_moved(_CharT* __ptr, size_t __capacity)
+///     - This function is typically used for a dynamic sized buffer. There the
+///       location of the buffer changes due to reallocations.
+///     - __ptr_ will be set to __ptr. (This value may be the old value of
+///       __ptr_).
+///     - __capacity_ will be set to __capacity. (This value may be the old
+///       value of       __capacity_).
+///     - __size_ remains unchanged,
+///     - The range [__ptr, __ptr + __size_) contains the original data of the
+///       range  [__ptr_, __ptr_ + __size_).
+///
+/// The push_back function expects a valid buffer and a capacity of at least 1.
+/// This means:
+/// - The class is constructed with a valid buffer,
+/// - __buffer_moved is called with a valid buffer is used before the first
+///   write operation,
+/// - no write function is ever called, or
+/// - the class is constructed with a __max_output_size object with __max_size 0.
+///
+/// The latter option allows formatted_size to use the output buffer without
+/// ever writing anything to the buffer.
 template <__fmt_char_type _CharT>
 class _LIBCPP_TEMPLATE_VIS __output_buffer {
 public:
-  using value_type = _CharT;
+  using value_type           = _CharT;
+  using __prepare_write_type = void (*)(__output_buffer<_CharT>&, size_t);
 
-  template <class _Tp>
+  template <class _Tp> // Deprecated LLVM-19 function.
   _LIBCPP_HIDE_FROM_ABI explicit __output_buffer(_CharT* __ptr, size_t __capacity, _Tp* __obj)
       : __ptr_(__ptr),
         __capacity_(__capacity),
         __flush_([](_CharT* __p, size_t __n, void* __o) { static_cast<_Tp*>(__o)->__flush(__p, __n); }),
         __obj_(__obj) {}
 
+  // New LLVM-20 function.
+  [[nodiscard]]
+  _LIBCPP_HIDE_FROM_ABI explicit __output_buffer(_CharT* __ptr, size_t __capacity, __prepare_write_type __prepare_write)
+      : __ptr_(__ptr), __capacity_(__capacity), __prepare_write_(__prepare_write), __obj_(nullptr) {}
+
+  // Deprecated LLVM-19 function.
   _LIBCPP_HIDE_FROM_ABI void __reset(_CharT* __ptr, size_t __capacity) {
     __ptr_      = __ptr;
     __capacity_ = __capacity;
   }
 
+  // New LLVM-20 function.
+  _LIBCPP_HIDE_FROM_ABI void __buffer_flused() { __size_ = 0; }
+
+  // New LLVM-20 function.
+  _LIBCPP_HIDE_FROM_ABI void __buffer_moved(_CharT* __ptr, size_t __capacity) {
+    __ptr_      = __ptr;
+    __capacity_ = __capacity;
+  }
+
   _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return std::back_insert_iterator{*this}; }
 
   // Used in std::back_insert_iterator.
@@ -84,7 +217,7 @@ class _LIBCPP_TEMPLATE_VIS __output_buffer {
     // Profiling showed flushing after adding is more efficient than flushing
     // when entering the function.
     if (__size_ == __capacity_)
-      __flush();
+      __flush(0);
   }
 
   /// Copies the input __str to the buffer.
@@ -107,7 +240,7 @@ class _LIBCPP_TEMPLATE_VIS __output_buffer {
     size_t __n = __str.size();
 
     __flush_on_overflow(__n);
-    if (__n < __capacity_) { //  push_back requires the buffer to have room for at least one character (so use <).
+    if (__n < __capacity_) { // push_back requires the buffer to have room for at least one character (so use <).
       std::copy_n(__str.data(), __n, std::addressof(__ptr_[__size_]));
       __size_ += __n;
       return;
@@ -118,12 +251,12 @@ class _LIBCPP_TEMPLATE_VIS __output_buffer {
     _LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
     const _InCharT* __first = __str.data();
     do {
-      size_t __chunk = std::min(__n, __capacity_);
+      size_t __chunk = std::min(__n, __capacity_ - __size_);
       std::copy_n(__first, __chunk, std::addressof(__ptr_[__size_]));
       __size_ = __chunk;
       __first += __chunk;
       __n -= __chunk;
-      __flush();
+      __flush(__n);
     } while (__n);
   }
 
@@ -148,12 +281,12 @@ class _LIBCPP_TEMPLATE_VIS __output_buffer {
     // Transform the data in "__capacity_" sized chunks.
     _LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
     do {
-      size_t __chunk = std::min(__n, __capacity_);
+      size_t __chunk = std::min(__n, __capacity_ - __size_);
       std::transform(__first, __first + __chunk, std::addressof(__ptr_[__size_]), __operation);
       __size_ = __chunk;
       __first += __chunk;
       __n -= __chunk;
-      __flush();
+      __flush(__n);
     } while (__n);
   }
 
@@ -174,20 +307,36 @@ class _LIBCPP_TEMPLATE_VIS __output_buffer {
       std::fill_n(std::addressof(__ptr_[__size_]), __chunk, __value);
       __size_ = __chunk;
       __n -= __chunk;
-      __flush();
+      __flush(__n);
     } while (__n);
   }
 
-  _LIBCPP_HIDE_FROM_ABI void __flush() {
-    __flush_(__ptr_, __size_, __obj_);
-    __size_ = 0;
+  _LIBCPP_HIDE_FROM_ABI void __flush(size_t __size_hint) {
+    if (__obj_) {
+      // LLVM-19 code path
+      __flush_(__ptr_, __size_, __obj_);
+      __size_ = 0;
+    } else {
+      // LLVM-20 code path
+      __prepare_write_(*this, __size_hint + 1); // + 1 to always have space for the next time
+    }
   }
 
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t __capacity() const { return __capacity_; }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t __size() const { return __size_; }
+
 private:
   _CharT* __ptr_;
   size_t __capacity_;
   size_t __size_{0};
-  void (*__flush_)(_CharT*, size_t, void*);
+  union {
+    // LLVM-19 member
+    void (*__flush_)(_CharT*, size_t, void*);
+    // LLVM-20 member
+    void (*__prepare_write_)(__output_buffer<_CharT>&, size_t);
+  };
+  static_assert(sizeof(__flush_) == sizeof(__prepare_write_), "The union is an ABI break.");
+  static_assert(alignof(decltype(__flush_)) == alignof(decltype(__prepare_write_)), "The union is an ABI break.");
   void* __obj_;
 
   /// Flushes the buffer when the output operation would overflow the buffer.
@@ -224,11 +373,14 @@ class _LIBCPP_TEMPLATE_VIS __output_buffer {
   /// the buffers. This would make the code more complex and \ref format_to_n is
   /// not the most common use case. Therefore the optimization isn't done.
   _LIBCPP_HIDE_FROM_ABI void __flush_on_overflow(size_t __n) {
-    if (__size_ + __n >= __capacity_)
-      __flush();
+    __n += __size_;
+    if (__n >= __capacity_)
+      __flush(__n - __capacity_ + 1);
   }
 };
 
+// ***** ***** ***** LLVM-19 classes ***** ***** *****
+
 /// A storage using an internal buffer.
 ///
 /// This storage is used when writing a single element to the output iterator
@@ -373,7 +525,7 @@ class _LIBCPP_TEMPLATE_VIS __format_buffer {
   _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) { __writer_.__flush(__ptr, __n); }
 
   _LIBCPP_HIDE_FROM_ABI _OutIt __out_it() && {
-    __output_.__flush();
+    __output_.__flush(0);
     return std::move(__writer_).__out_it();
   }
 
@@ -395,7 +547,7 @@ class _LIBCPP_TEMPLATE_VIS __formatted_size_buffer {
   _LIBCPP_HIDE_FROM_ABI void __flush(const _CharT*, size_t __n) { __size_ += __n; }
 
   _LIBCPP_HIDE_FROM_ABI size_t __result() && {
-    __output_.__flush();
+    __output_.__flush(0);
     return __size_;
   }
 
@@ -499,11 +651,78 @@ struct _LIBCPP_TEMPLATE_VIS __format_to_n_buffer final
   _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return this->__output_.__make_output_iterator(); }
 
   _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> __result() && {
-    this->__output_.__flush();
+    this->__output_.__flush(0);
     return {std::move(this->__writer_).__out_it(), this->__size_};
   }
 };
 
+// ***** ***** ***** LLVM-20 classes ***** ***** *****
+
+// A dynamically growing buffer.
+template <__fmt_char_type _CharT>
+class _LIBCPP_TEMPLATE_VIS __allocating_buffer : public __output_buffer<_CharT> {
+public:
+  __allocating_buffer(const __allocating_buffer&)            = delete;
+  __allocating_buffer& operator=(const __allocating_buffer&) = delete;
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __allocating_buffer()
+      : __output_buffer<_CharT>{__buffer_, __buffer_size_, __prepare_write} {}
+
+  _LIBCPP_HIDE_FROM_ABI ~__allocating_buffer() {
+    if (__ptr_ != __buffer_) {
+      ranges::destroy_n(__ptr_, this->__size());
+      allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, this->__capacity());
+    }
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI basic_string_view<_CharT> __view() { return {__ptr_, this->__size()}; }
+
+private:
+  // At the moment the allocator is hard-code. There might be reasons to have
+  // an allocator trait in the future. This ensures forward compatibility.
+  using _Alloc = allocator<_CharT>;
+  _LIBCPP_NO_UNIQUE_ADDRESS _Alloc __alloc_;
+
+  // Since allocating is expensive the class has a small internal buffer. When
+  // its capacity is exceeded a dynamic buffer will be allocated.
+  static constexpr size_t __buffer_size_ = 256;
+  _CharT __buffer_[__buffer_size_];
+  _CharT* __ptr_{__buffer_};
+
+  _LIBCPP_HIDE_FROM_ABI void __grow_buffer(size_t __capacity) {
+    if (__capacity < __buffer_size_)
+      return;
+
+    _LIBCPP_ASSERT_INTERNAL(__capacity > this->__capacity(), "the buffer must grow");
+    auto __result = std::__allocate_at_least(__alloc_, __capacity);
+    auto __guard  = std::__make_exception_guard([&] {
+      allocator_traits<_Alloc>::deallocate(__alloc_, __result.ptr, __result.count);
+    });
+    // This shouldn't throw, but just to be safe. Note that at -O1 this
+    // guard is optimized away so there is no runtime overhead.
+    new (__result.ptr) _CharT[__result.count];
+    std::copy_n(__ptr_, this->__size(), __result.ptr);
+    __guard.__complete();
+    if (__ptr_ != __buffer_) {
+      ranges::destroy_n(__ptr_, this->__capacity());
+      allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, this->__capacity());
+    }
+
+    __ptr_ = __result.ptr;
+    this->__buffer_moved(__ptr_, __result.count);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI void __prepare_write(size_t __size_hint) {
+    __grow_buffer(std::max<size_t>(this->__capacity() + __size_hint, this->__capacity() * 1.6));
+  }
+
+  _LIBCPP_HIDE_FROM_ABI static void __prepare_write(__output_buffer<_CharT>& __buffer, size_t __size_hint) {
+    static_cast<__allocating_buffer<_CharT>&>(__buffer).__prepare_write(__size_hint);
+  }
+};
+
+// ***** ***** ***** LLVM-19 and LLVM-20 class ***** ***** *****
+
 // A dynamically growing buffer intended to be used for retargeting a context.
 //
 // P2286 Formatting ranges adds range formatting support. It allows the user to
diff --git a/libcxx/include/__format/format_functions.h b/libcxx/include/__format/format_functions.h
index d14b49aff1495..a5c63bd4db70f 100644
--- a/libcxx/include/__format/format_functions.h
+++ b/libcxx/include/__format/format_functions.h
@@ -452,9 +452,9 @@ format_to(_OutIt __out_it, wformat_string<_Args...> __fmt, _Args&&... __args) {
 // fires too eagerly, see http://llvm.org/PR61563.
 template <class = void>
 [[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI string vformat(string_view __fmt, format_args __args) {
-  string __res;
-  std::vformat_to(std::back_inserter(__res), __fmt, __args);
-  return __res;
+  __format::__allocating_buffer<char> __buffer;
+  std::vformat_to(__buffer.__make_output_iterator(), __fmt, __args);
+  return string{__buffer.__view()};
 }
 
 #  ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
@@ -463,9 +463,9 @@ template <class = void>
 template <class = void>
 [[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI wstring
 vformat(wstring_view __fmt, wformat_args __args) {
-  wstring __res;
-  std::vformat_to(std::back_inserter(__res), __fmt, __args);
-  return __res;
+  __format::__allocating_buffer<wchar_t> __buffer;
+  std::vformat_to(__buffer.__make_output_iterator(), __fmt, __args);
+  return wstring{__buffer.__view()};
 }
 #  endif
 
@@ -585,9 +585,9 @@ format_to(_OutIt __out_it, locale __loc, wformat_string<_Args...> __fmt, _Args&&
 template <class = void>
 [[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI string
 vformat(locale __loc, string_view __fmt, format_args __args) {
-  string __res;
-  std::vformat_to(std::back_inserter(__res), std::move(__loc), __fmt, __args);
-  return __res;
+  __format::__allocating_buffer<char> __buffer;
+  std::vformat_to(__buffer.__make_output_iterator(), std::move(__loc), __fmt, __args);
+  return string{__buffer.__view()};
 }
 
 #    ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
@@ -596,9 +596,9 @@ vformat(locale __loc, string_view __fmt, format_args __args) {
 template <class = void>
 [[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI wstring
 vformat(locale __loc, wstring_view __fmt, wformat_args __args) {
-  wstring __res;
-  std::vformat_to(std::back_inserter(__res), std::move(__loc), __fmt, __args);
-  return __res;
+  __format::__allocating_buffer<wchar_t> __buffer;
+  std::vformat_to(__buffer.__make_output_iterator(), std::move(__loc), __fmt, __args);
+  return wstring{__buffer.__view()};
 }
 #    endif
 

``````````

</details>


https://github.com/llvm/llvm-project/pull/101817


More information about the llvm-branch-commits mailing list