From 715127b63d19ed3b9a92d3e5f5007b36cc9834dd Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Thu, 7 Mar 2024 13:47:46 +0000 Subject: [PATCH] libstdc++: Use std::from_chars to speed up parsing subsecond durations With std::from_chars we can parse subsecond durations much faster than with std::num_get, as shown in the microbenchmarks below. We were using std::num_get and std::numpunct in order to parse a number with the locale's decimal point character. But we copy the chars from the input stream into a new buffer anyway, so we can replace the locale's decimal point with '.' in that buffer, and then we can use std::from_chars on it. Benchmark Time CPU Iterations ---------------------------------------------------------- from_chars_millisec 158 ns 158 ns 4524046 num_get_millisec 192 ns 192 ns 3644626 from_chars_microsec 164 ns 163 ns 4330627 num_get_microsec 205 ns 205 ns 3413452 from_chars_nanosec 173 ns 173 ns 4072653 num_get_nanosec 227 ns 227 ns 3105161 libstdc++-v3/ChangeLog: * include/bits/chrono_io.h (_Parser::operator()): Use std::from_chars to parse fractional seconds. --- libstdc++-v3/include/bits/chrono_io.h | 28 +++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/libstdc++-v3/include/bits/chrono_io.h b/libstdc++-v3/include/bits/chrono_io.h index b8f0657bee9..412e8b83fb7 100644 --- a/libstdc++-v3/include/bits/chrono_io.h +++ b/libstdc++-v3/include/bits/chrono_io.h @@ -37,6 +37,7 @@ #include // ostringstream #include // setw, setfill #include +#include // from_chars #include @@ -3597,13 +3598,17 @@ namespace __detail __err |= ios_base::eofbit; else { - auto& __np = use_facet>(__loc); - auto __dp = __np.decimal_point(); + _CharT __dp = '.'; + if (__loc != locale::classic()) + { + auto& __np = use_facet>(__loc); + __dp = __np.decimal_point(); + } _CharT __c = _Traits::to_char_type(__i); if (__c == __dp) { (void) __is.get(); - __buf.put(__c); + __buf.put('.'); int __prec = hh_mm_ss<_Duration>::fractional_width; do @@ -3618,14 +3623,17 @@ namespace __detail } } - if (!__is_failed(__err)) + if (!__is_failed(__err)) [[likely]] { - auto& __ng = use_facet>(__loc); - long double __val; - ios_base::iostate __err2{}; - __ng.get(__buf, {}, __buf, __err2, __val); - if (__is_failed(__err2)) [[unlikely]] - __err |= __err2; + long double __val{}; + string __str = std::move(__buf).str(); + auto __first = __str.data(); + auto __last = __first + __str.size(); + using enum chars_format; + auto [ptr, ec] = std::from_chars(__first, __last, + __val, fixed); + if ((bool)ec || ptr != __last) [[unlikely]] + __err |= ios_base::failbit; else { duration __fs(__val);