Skip to content

Commit 890a5c8

Browse files
committed
[libc++][format][3/7] Improves std::format performance.
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
1 parent f46ff67 commit 890a5c8

File tree

2 files changed

+249
-30
lines changed

2 files changed

+249
-30
lines changed

libcxx/include/__format/buffer.h

Lines changed: 237 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -58,23 +58,156 @@ namespace __format {
5858
/// This helper is used together with the @ref back_insert_iterator to offer
5959
/// type-erasure for the formatting functions. This reduces the number to
6060
/// template instantiations.
61+
///
62+
/// The design of the class is being changed to improve performance and do some
63+
/// code cleanups.
64+
/// The original design (as shipped up to LLVM-19) uses the following design:
65+
/// - There is an external object that connects the buffer to the output.
66+
/// - The class constructor stores a function pointer to a grow function and a
67+
/// type-erased pointer to the object that does the grow.
68+
/// - When writing data to the buffer would exceed the external buffer's
69+
/// capacity it requests the external buffer to flush its contents.
70+
///
71+
/// The new design tries to solve some issues with the current design:
72+
/// - The buffer used is a fixed-size buffer, benchmarking shows that using a
73+
/// dynamic allocated buffer has performance benefits.
74+
/// - Implementing P3107R5 "Permit an efficient implementation of std::print"
75+
/// is not trivial with the current buffers. Using the code from this series
76+
/// makes it trivial.
77+
///
78+
/// This class is ABI-tagged, still the new design does not change the size of
79+
/// objects of this class.
80+
///
81+
/// The new design contains information regarding format_to_n changes, these
82+
/// will be implemented in follow-up patch.
83+
///
84+
/// The new design is the following.
85+
/// - There is an external object that connects the buffer to the output.
86+
/// - This buffer object:
87+
/// - inherits publicly from this class.
88+
/// - has a static or dynamic buffer.
89+
/// - has a static member function to make space in its buffer write
90+
/// operations. This can be done by increasing the size of the internal
91+
/// buffer or by writing the contents of the buffer to the output iterator.
92+
///
93+
/// This member function is a constructor argument, so its name is not
94+
/// fixed. The code uses the name __prepare_write.
95+
/// - The number of output code units can be limited by a __max_output_size
96+
/// object. This is used in format_to_n This object:
97+
/// - Contains the maximum number of code units to be written.
98+
/// - Contains the number of code units that are requested to be written.
99+
/// This number is returned to the user of format_to_n.
100+
/// - The write functions call objects __request_write member function.
101+
/// This function:
102+
/// - Updates the number of code units that are requested to be written.
103+
/// - Returns the number of code units that can be written without
104+
/// exceeding the maximum number of code units to be written.
105+
///
106+
/// Documentation for the buffer usage members:
107+
/// - __ptr_ the start of the buffer.
108+
/// - __capacity_ the number of code units that can be written.
109+
/// This means [__ptr_, __ptr_ + __capacity_) is a valid range to write to.
110+
/// - __size_ the number of code units written in the buffer. The next code
111+
/// unit will be written at __ptr_ + __size_. This __size_ may NOT contain
112+
/// the total number of code units written by the __output_buffer. Whether or
113+
/// not it does depends on the sub-class used. Typically the total number of
114+
/// code units written is not interesting. It is interesting for format_to_n
115+
/// which has its own way to track this number.
116+
///
117+
/// Documentation for the buffer changes function:
118+
/// The subclasses have a function with the following signature:
119+
///
120+
/// static void __prepare_write(
121+
/// __output_buffer<_CharT>& __buffer, size_t __code_units);
122+
///
123+
/// This function is called when a write function writes more code units than
124+
/// the buffer' available space. When an __max_output_size object is provided
125+
/// the number of code units is the number of code units returned from
126+
/// __max_output_size::__request_write function.
127+
///
128+
/// - The __buffer contains *this. Since the class containing this function
129+
/// inherits from __output_buffer it's save to cast it to the subclass being
130+
/// used.
131+
/// - The __code_units is the number of code units the caller will write + 1.
132+
/// - This value does not take the avaiable space of the buffer into account.
133+
/// - The push_back function is more efficient when writing before resizing,
134+
/// this means the buffer should always have room for one code unit. Hence
135+
/// the + 1 is the size.
136+
/// - When the function returns there is room for at least one code unit. There
137+
/// is no requirement there is room for __code_units code units:
138+
/// - The class has some "bulk" operations. For example, __copy which copies
139+
/// the contents of a basic_string_view to the output. If the sub-class has
140+
/// a fixed size buffer the size of the basic_string_view may be larger
141+
/// than the buffer. In that case it's impossible to honor the requested
142+
/// size.
143+
/// - The at least one code unit makes sure the entire output can be written.
144+
/// (Obviously making room one code unit at a time is slow and
145+
/// it's recommended to return a larger available space.)
146+
/// - When the buffer has room for at least one code unit the function may be
147+
/// a no-op.
148+
/// - When the function makes space for more code units it uses one for these
149+
/// functions to signal the change:
150+
/// - __buffer_flushed()
151+
/// - This function is typically used for a fixed sized buffer.
152+
/// - The current contents of [__ptr_, __ptr_ + __size_) have been
153+
/// processed.
154+
/// - __ptr_ remains unchanged.
155+
/// - __capacity_ remains unchanged.
156+
/// - __size_ will be set to 0.
157+
/// - __buffer_moved(_CharT* __ptr, size_t __capacity)
158+
/// - This function is typically used for a dynamic sized buffer. There the
159+
/// location of the buffer changes due to reallocations.
160+
/// - __ptr_ will be set to __ptr. (This value may be the old value of
161+
/// __ptr_).
162+
/// - __capacity_ will be set to __capacity. (This value may be the old
163+
/// value of __capacity_).
164+
/// - __size_ remains unchanged,
165+
/// - The range [__ptr, __ptr + __size_) contains the original data of the
166+
/// range [__ptr_, __ptr_ + __size_).
167+
///
168+
/// The push_back function expects a valid buffer and a capacity of at least 1.
169+
/// This means:
170+
/// - The class is constructed with a valid buffer,
171+
/// - __buffer_moved is called with a valid buffer is used before the first
172+
/// write operation,
173+
/// - no write function is ever called, or
174+
/// - the class is constructed with a __max_output_size object with __max_size 0.
175+
///
176+
/// The latter option allows formatted_size to use the output buffer without
177+
/// ever writing anything to the buffer.
61178
template <__fmt_char_type _CharT>
62179
class _LIBCPP_TEMPLATE_VIS __output_buffer {
63180
public:
64-
using value_type = _CharT;
181+
using value_type = _CharT;
182+
using __prepare_write_type = void (*)(__output_buffer<_CharT>&, size_t);
65183

66-
template <class _Tp>
184+
template <class _Tp> // Deprecated LLVM-19 function.
67185
_LIBCPP_HIDE_FROM_ABI explicit __output_buffer(_CharT* __ptr, size_t __capacity, _Tp* __obj)
68186
: __ptr_(__ptr),
69187
__capacity_(__capacity),
70188
__flush_([](_CharT* __p, size_t __n, void* __o) { static_cast<_Tp*>(__o)->__flush(__p, __n); }),
71189
__obj_(__obj) {}
72190

191+
// New LLVM-20 function.
192+
[[nodiscard]]
193+
_LIBCPP_HIDE_FROM_ABI explicit __output_buffer(_CharT* __ptr, size_t __capacity, __prepare_write_type __prepare_write)
194+
: __ptr_(__ptr), __capacity_(__capacity), __prepare_write_(__prepare_write), __obj_(nullptr) {}
195+
196+
// Deprecated LLVM-19 function.
73197
_LIBCPP_HIDE_FROM_ABI void __reset(_CharT* __ptr, size_t __capacity) {
74198
__ptr_ = __ptr;
75199
__capacity_ = __capacity;
76200
}
77201

202+
// New LLVM-20 function.
203+
_LIBCPP_HIDE_FROM_ABI void __buffer_flused() { __size_ = 0; }
204+
205+
// New LLVM-20 function.
206+
_LIBCPP_HIDE_FROM_ABI void __buffer_moved(_CharT* __ptr, size_t __capacity) {
207+
__ptr_ = __ptr;
208+
__capacity_ = __capacity;
209+
}
210+
78211
_LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return std::back_insert_iterator{*this}; }
79212

80213
// Used in std::back_insert_iterator.
@@ -84,7 +217,7 @@ class _LIBCPP_TEMPLATE_VIS __output_buffer {
84217
// Profiling showed flushing after adding is more efficient than flushing
85218
// when entering the function.
86219
if (__size_ == __capacity_)
87-
__flush();
220+
__flush(0);
88221
}
89222

90223
/// Copies the input __str to the buffer.
@@ -107,7 +240,7 @@ class _LIBCPP_TEMPLATE_VIS __output_buffer {
107240
size_t __n = __str.size();
108241

109242
__flush_on_overflow(__n);
110-
if (__n < __capacity_) { // push_back requires the buffer to have room for at least one character (so use <).
243+
if (__n < __capacity_) { // push_back requires the buffer to have room for at least one character (so use <).
111244
std::copy_n(__str.data(), __n, std::addressof(__ptr_[__size_]));
112245
__size_ += __n;
113246
return;
@@ -118,12 +251,12 @@ class _LIBCPP_TEMPLATE_VIS __output_buffer {
118251
_LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
119252
const _InCharT* __first = __str.data();
120253
do {
121-
size_t __chunk = std::min(__n, __capacity_);
254+
size_t __chunk = std::min(__n, __capacity_ - __size_);
122255
std::copy_n(__first, __chunk, std::addressof(__ptr_[__size_]));
123256
__size_ = __chunk;
124257
__first += __chunk;
125258
__n -= __chunk;
126-
__flush();
259+
__flush(__n);
127260
} while (__n);
128261
}
129262

@@ -148,12 +281,12 @@ class _LIBCPP_TEMPLATE_VIS __output_buffer {
148281
// Transform the data in "__capacity_" sized chunks.
149282
_LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
150283
do {
151-
size_t __chunk = std::min(__n, __capacity_);
284+
size_t __chunk = std::min(__n, __capacity_ - __size_);
152285
std::transform(__first, __first + __chunk, std::addressof(__ptr_[__size_]), __operation);
153286
__size_ = __chunk;
154287
__first += __chunk;
155288
__n -= __chunk;
156-
__flush();
289+
__flush(__n);
157290
} while (__n);
158291
}
159292

@@ -174,20 +307,36 @@ class _LIBCPP_TEMPLATE_VIS __output_buffer {
174307
std::fill_n(std::addressof(__ptr_[__size_]), __chunk, __value);
175308
__size_ = __chunk;
176309
__n -= __chunk;
177-
__flush();
310+
__flush(__n);
178311
} while (__n);
179312
}
180313

181-
_LIBCPP_HIDE_FROM_ABI void __flush() {
182-
__flush_(__ptr_, __size_, __obj_);
183-
__size_ = 0;
314+
_LIBCPP_HIDE_FROM_ABI void __flush(size_t __size_hint) {
315+
if (__obj_) {
316+
// LLVM-19 code path
317+
__flush_(__ptr_, __size_, __obj_);
318+
__size_ = 0;
319+
} else {
320+
// LLVM-20 code path
321+
__prepare_write_(*this, __size_hint + 1); // + 1 to always have space for the next time
322+
}
184323
}
185324

325+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t __capacity() const { return __capacity_; }
326+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t __size() const { return __size_; }
327+
186328
private:
187329
_CharT* __ptr_;
188330
size_t __capacity_;
189331
size_t __size_{0};
190-
void (*__flush_)(_CharT*, size_t, void*);
332+
union {
333+
// LLVM-19 member
334+
void (*__flush_)(_CharT*, size_t, void*);
335+
// LLVM-20 member
336+
void (*__prepare_write_)(__output_buffer<_CharT>&, size_t);
337+
};
338+
static_assert(sizeof(__flush_) == sizeof(__prepare_write_), "The union is an ABI break.");
339+
static_assert(alignof(decltype(__flush_)) == alignof(decltype(__prepare_write_)), "The union is an ABI break.");
191340
void* __obj_;
192341

193342
/// Flushes the buffer when the output operation would overflow the buffer.
@@ -224,11 +373,14 @@ class _LIBCPP_TEMPLATE_VIS __output_buffer {
224373
/// the buffers. This would make the code more complex and \ref format_to_n is
225374
/// not the most common use case. Therefore the optimization isn't done.
226375
_LIBCPP_HIDE_FROM_ABI void __flush_on_overflow(size_t __n) {
227-
if (__size_ + __n >= __capacity_)
228-
__flush();
376+
__n += __size_;
377+
if (__n >= __capacity_)
378+
__flush(__n - __capacity_ + 1);
229379
}
230380
};
231381

382+
// ***** ***** ***** LLVM-19 classes ***** ***** *****
383+
232384
/// A storage using an internal buffer.
233385
///
234386
/// This storage is used when writing a single element to the output iterator
@@ -373,7 +525,7 @@ class _LIBCPP_TEMPLATE_VIS __format_buffer {
373525
_LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) { __writer_.__flush(__ptr, __n); }
374526

375527
_LIBCPP_HIDE_FROM_ABI _OutIt __out_it() && {
376-
__output_.__flush();
528+
__output_.__flush(0);
377529
return std::move(__writer_).__out_it();
378530
}
379531

@@ -395,7 +547,7 @@ class _LIBCPP_TEMPLATE_VIS __formatted_size_buffer {
395547
_LIBCPP_HIDE_FROM_ABI void __flush(const _CharT*, size_t __n) { __size_ += __n; }
396548

397549
_LIBCPP_HIDE_FROM_ABI size_t __result() && {
398-
__output_.__flush();
550+
__output_.__flush(0);
399551
return __size_;
400552
}
401553

@@ -499,11 +651,78 @@ struct _LIBCPP_TEMPLATE_VIS __format_to_n_buffer final
499651
_LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return this->__output_.__make_output_iterator(); }
500652

501653
_LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> __result() && {
502-
this->__output_.__flush();
654+
this->__output_.__flush(0);
503655
return {std::move(this->__writer_).__out_it(), this->__size_};
504656
}
505657
};
506658

659+
// ***** ***** ***** LLVM-20 classes ***** ***** *****
660+
661+
// A dynamically growing buffer.
662+
template <__fmt_char_type _CharT>
663+
class _LIBCPP_TEMPLATE_VIS __allocating_buffer : public __output_buffer<_CharT> {
664+
public:
665+
__allocating_buffer(const __allocating_buffer&) = delete;
666+
__allocating_buffer& operator=(const __allocating_buffer&) = delete;
667+
668+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI __allocating_buffer()
669+
: __output_buffer<_CharT>{__buffer_, __buffer_size_, __prepare_write} {}
670+
671+
_LIBCPP_HIDE_FROM_ABI ~__allocating_buffer() {
672+
if (__ptr_ != __buffer_) {
673+
ranges::destroy_n(__ptr_, this->__size());
674+
allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, this->__capacity());
675+
}
676+
}
677+
678+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI basic_string_view<_CharT> __view() { return {__ptr_, this->__size()}; }
679+
680+
private:
681+
// At the moment the allocator is hard-code. There might be reasons to have
682+
// an allocator trait in the future. This ensures forward compatibility.
683+
using _Alloc = allocator<_CharT>;
684+
_LIBCPP_NO_UNIQUE_ADDRESS _Alloc __alloc_;
685+
686+
// Since allocating is expensive the class has a small internal buffer. When
687+
// its capacity is exceeded a dynamic buffer will be allocated.
688+
static constexpr size_t __buffer_size_ = 256;
689+
_CharT __buffer_[__buffer_size_];
690+
_CharT* __ptr_{__buffer_};
691+
692+
_LIBCPP_HIDE_FROM_ABI void __grow_buffer(size_t __capacity) {
693+
if (__capacity < __buffer_size_)
694+
return;
695+
696+
_LIBCPP_ASSERT_INTERNAL(__capacity > this->__capacity(), "the buffer must grow");
697+
auto __result = std::__allocate_at_least(__alloc_, __capacity);
698+
auto __guard = std::__make_exception_guard([&] {
699+
allocator_traits<_Alloc>::deallocate(__alloc_, __result.ptr, __result.count);
700+
});
701+
// This shouldn't throw, but just to be safe. Note that at -O1 this
702+
// guard is optimized away so there is no runtime overhead.
703+
new (__result.ptr) _CharT[__result.count];
704+
std::copy_n(__ptr_, this->__size(), __result.ptr);
705+
__guard.__complete();
706+
if (__ptr_ != __buffer_) {
707+
ranges::destroy_n(__ptr_, this->__capacity());
708+
allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, this->__capacity());
709+
}
710+
711+
__ptr_ = __result.ptr;
712+
this->__buffer_moved(__ptr_, __result.count);
713+
}
714+
715+
_LIBCPP_HIDE_FROM_ABI void __prepare_write(size_t __size_hint) {
716+
__grow_buffer(std::max<size_t>(this->__capacity() + __size_hint, this->__capacity() * 1.6));
717+
}
718+
719+
_LIBCPP_HIDE_FROM_ABI static void __prepare_write(__output_buffer<_CharT>& __buffer, size_t __size_hint) {
720+
static_cast<__allocating_buffer<_CharT>&>(__buffer).__prepare_write(__size_hint);
721+
}
722+
};
723+
724+
// ***** ***** ***** LLVM-19 and LLVM-20 class ***** ***** *****
725+
507726
// A dynamically growing buffer intended to be used for retargeting a context.
508727
//
509728
// P2286 Formatting ranges adds range formatting support. It allows the user to

0 commit comments

Comments
 (0)