Replace `os << std::format(...)` with `std::format_to(ostreambuf_iterator, ...)`
in chrono operator<< overloads. This avoids creating a temporary std::string
for the formatted output, instead writing directly to the stream buffer.
This addresses the TODO in the chrono formatter about using format_to
instead of format for ostream insertion (PR libstdc++/111052). When
combined with a subsequent _Iter_sink<ostreambuf_iterator> specialization,
this also benefits from zero-copy writing directly to the streambuf's
put area.
libstdc++-v3/ChangeLog:
* include/bits/chrono_io.h (operator<<): Use format_to with
ostreambuf_iterator instead of os << format. Check for write
failure and set badbit on the stream.
Signed-off-by: Anlai Lu <[email protected]>
---
libstdc++-v3/include/bits/chrono_io.h | 102 +++++++++++++++++++++-----
1 file changed, 83 insertions(+), 19 deletions(-)
diff --git a/libstdc++-v3/include/bits/chrono_io.h
b/libstdc++-v3/include/bits/chrono_io.h
index f8bb485d1..2656bd9c4 100644
--- a/libstdc++-v3/include/bits/chrono_io.h
+++ b/libstdc++-v3/include/bits/chrono_io.h
@@ -3635,7 +3635,10 @@ namespace __detail
if (__d.ok())
__s = __s.substr(0, 6);
auto __u = (unsigned)__d;
- __os << std::vformat(__s, make_format_args<_Ctx>(__u));
+ auto __it = std::vformat_to(std::ostreambuf_iterator<_CharT>(__os),
+ __s, make_format_args<_Ctx>(__u));
+ if (__it.failed())
+ __os.setstate(ios_base::badbit);
return __os;
}
@@ -3661,12 +3664,21 @@ namespace __detail
using _Str = basic_string_view<_CharT>;
_Str __s = _GLIBCXX_WIDEN("{:L%b}{} is not a valid month");
if (__m.ok())
- __os << std::vformat(__os.getloc(), __s.substr(0, 6),
- make_format_args<_Ctx>(__m));
+ {
+ auto __it = std::vformat_to(std::ostreambuf_iterator<_CharT>(__os),
+ __os.getloc(), __s.substr(0, 6),
+ make_format_args<_Ctx>(__m));
+ if (__it.failed())
+ __os.setstate(ios_base::badbit);
+ }
else
{
auto __u = (unsigned)__m;
- __os << std::vformat(__s.substr(6), make_format_args<_Ctx>(__u));
+ auto __it = std::vformat_to(std::ostreambuf_iterator<_CharT>(__os),
+ __s.substr(6),
+ make_format_args<_Ctx>(__u));
+ if (__it.failed())
+ __os.setstate(ios_base::badbit);
}
return __os;
}
@@ -3699,7 +3711,11 @@ namespace __detail
__s.remove_prefix(1);
else
__i = -__i;
- __os << std::vformat(__s, make_format_args<_Ctx>(__i));
+ auto __it = std::vformat_to(std::ostreambuf_iterator<_CharT>(__os),
+ __s,
+ make_format_args<_Ctx>(__i));
+ if (__it.failed())
+ __os.setstate(ios_base::badbit);
return __os;
}
@@ -3725,12 +3741,21 @@ namespace __detail
using _Str = basic_string_view<_CharT>;
_Str __s = _GLIBCXX_WIDEN("{:L%a}{} is not a valid weekday");
if (__wd.ok())
- __os << std::vformat(__os.getloc(), __s.substr(0, 6),
- make_format_args<_Ctx>(__wd));
+ {
+ auto __it = std::vformat_to(std::ostreambuf_iterator<_CharT>(__os),
+ __os.getloc(), __s.substr(0, 6),
+ make_format_args<_Ctx>(__wd));
+ if (__it.failed())
+ __os.setstate(ios_base::badbit);
+ }
else
{
auto __c = __wd.c_encoding();
- __os << std::vformat(__s.substr(6), make_format_args<_Ctx>(__c));
+ auto __it = std::vformat_to(std::ostreambuf_iterator<_CharT>(__os),
+ __s.substr(6),
+ make_format_args<_Ctx>(__c));
+ if (__it.failed())
+ __os.setstate(ios_base::badbit);
}
return __os;
}
@@ -3764,7 +3789,10 @@ namespace __detail
basic_string_view<_CharT> __s
= _GLIBCXX_WIDEN("[ is not a valid index]");
__os2 << __s[0];
- __os2 << std::format(_GLIBCXX_WIDEN("{}"), __i);
+ auto __it_idx = std::format_to(std::ostreambuf_iterator<_CharT>(__os2),
+ _GLIBCXX_WIDEN("{}"), __i);
+ if (__it_idx.failed())
+ __os2.setstate(ios_base::badbit);
if (__i >= 1 && __i <= 5)
__os2 << __s.back();
else
@@ -3909,8 +3937,11 @@ namespace __detail
using _Ctx = __format::__format_context<_CharT>;
using _Str = basic_string_view<_CharT>;
_Str __s = _GLIBCXX_WIDEN("{:%F} is not a valid date");
- __os << std::vformat(__ymd.ok() ? __s.substr(0, 5) : __s,
- make_format_args<_Ctx>(__ymd));
+ auto __it = std::vformat_to(std::ostreambuf_iterator<_CharT>(__os),
+ __ymd.ok() ? __s.substr(0, 5) : __s,
+ make_format_args<_Ctx>(__ymd));
+ if (__it.failed())
+ __os.setstate(ios_base::badbit);
return __os;
}
@@ -3994,7 +4025,12 @@ namespace __detail
operator<<(basic_ostream<_CharT, _Traits>& __os,
const hh_mm_ss<_Duration>& __hms)
{
- return __os << format(__os.getloc(), _GLIBCXX_WIDEN("{:L%T}"), __hms);
+ auto __it = std::format_to(std::ostreambuf_iterator<_CharT>(__os),
+ __os.getloc(),
+ _GLIBCXX_WIDEN("{:L%T}"), __hms);
+ if (__it.failed())
+ __os.setstate(ios_base::badbit);
+ return __os;
}
#if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
@@ -4003,7 +4039,11 @@ namespace __detail
basic_ostream<_CharT, _Traits>&
operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_info& __i)
{
- return __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{}"), __i);
+ auto __it = std::format_to(std::ostreambuf_iterator<_CharT>(__os),
+ __os.getloc(), _GLIBCXX_WIDEN("{}"), __i);
+ if (__it.failed())
+ __os.setstate(ios_base::badbit);
+ return __os;
}
/// Writes a local_info object to an ostream in an unspecified format.
@@ -4033,7 +4073,11 @@ namespace __detail
operator<<(basic_ostream<_CharT, _Traits>& __os,
const zoned_time<_Duration, _TimeZonePtr>& __t)
{
- __os << format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T %Z}"), __t);
+ auto __it = std::format_to(std::ostreambuf_iterator<_CharT>(__os),
+ __os.getloc(),
+ _GLIBCXX_WIDEN("{:L%F %T %Z}"), __t);
+ if (__it.failed())
+ __os.setstate(ios_base::badbit);
return __os;
}
#endif
@@ -4045,7 +4089,11 @@ namespace __detail
operator<<(basic_ostream<_CharT, _Traits>& __os,
const sys_time<_Duration>& __tp)
{
- __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __tp);
+ auto __it = std::format_to(std::ostreambuf_iterator<_CharT>(__os),
+ __os.getloc(),
+ _GLIBCXX_WIDEN("{:L%F %T}"), __tp);
+ if (__it.failed())
+ __os.setstate(ios_base::badbit);
return __os;
}
@@ -4090,7 +4138,11 @@ namespace __detail
operator<<(basic_ostream<_CharT, _Traits>& __os,
const utc_time<_Duration>& __t)
{
- __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __t);
+ auto __it = std::format_to(std::ostreambuf_iterator<_CharT>(__os),
+ __os.getloc(),
+ _GLIBCXX_WIDEN("{:L%F %T}"), __t);
+ if (__it.failed())
+ __os.setstate(ios_base::badbit);
return __os;
}
@@ -4125,7 +4177,11 @@ namespace __detail
operator<<(basic_ostream<_CharT, _Traits>& __os,
const tai_time<_Duration>& __t)
{
- __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __t);
+ auto __it = std::format_to(std::ostreambuf_iterator<_CharT>(__os),
+ __os.getloc(),
+ _GLIBCXX_WIDEN("{:L%F %T}"), __t);
+ if (__it.failed())
+ __os.setstate(ios_base::badbit);
return __os;
}
@@ -4164,7 +4220,11 @@ namespace __detail
operator<<(basic_ostream<_CharT, _Traits>& __os,
const gps_time<_Duration>& __t)
{
- __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __t);
+ auto __it = std::format_to(std::ostreambuf_iterator<_CharT>(__os),
+ __os.getloc(),
+ _GLIBCXX_WIDEN("{:L%F %T}"), __t);
+ if (__it.failed())
+ __os.setstate(ios_base::badbit);
return __os;
}
@@ -4202,7 +4262,11 @@ namespace __detail
operator<<(basic_ostream<_CharT, _Traits>& __os,
const file_time<_Duration>& __t)
{
- __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __t);
+ auto __it = std::format_to(std::ostreambuf_iterator<_CharT>(__os),
+ __os.getloc(),
+ _GLIBCXX_WIDEN("{:L%F %T}"), __t);
+ if (__it.failed())
+ __os.setstate(ios_base::badbit);
return __os;
}
--
2.34.1