This is v2 of the patch series to eliminate temporary std::string
allocations in chrono operator<< overloads.

Changes from v1:

- Dropped the format_to/ostreambuf_iterator approach and the
  _Iter_sink<ostreambuf_iterator> specialization.  The format_to
  approach bypasses the stream sentry mechanism and loses width/fill
  alignment — since operator<< is required to behave as a formatted
  output function, this is a correctness issue.  Jonathan Wakely noted
  that v1 also incorrectly used badbit (should be failbit) and that
  error state on a temporary stream was not propagated to the caller.
  Tomasz Kaminski noted that the _Iter_sink approach had
  exception-safety concerns and unclear API boundaries on
  ostreambuf_iterator.

- New approach: __detail::__chrono_write formats into a 128-byte
  stack buffer via __do_vformat_to_n and writes through
  __ostream_insert, which correctly handles sentry construction and
  width/fill padding.  Error propagation and failbit semantics are
  handled by the standard sentry mechanism — no manual state
  management needed.  Exception safety is preserved because all
  formatting completes into the stack buffer before any characters
  are written to the stream, so there is no risk of partial output.
  If output exceeds the buffer, it falls back to std::vformat with
  dynamic allocation.

- __detail::__empty_fmt bridges _S_empty_fs() through
  basic_format_string to get a basic_string_view.  Types whose
  formatters already handle empty spec (day, month, year, weekday,
  year_month_day) use this to skip format-string validation and
  manual ok() checks.  This follows Tomasz's observation that
  _S_empty_fs() can replace hand-rolled format strings for these
  types.

- weekday_indexed and weekday_last now use __chrono_write directly,
  per [time.cal.wdidx.nonmembers] and [time.cal.wdlast.nonmembers].
  The standard defines these operator<< as equivalent to
    os << format(os.getloc(), "...", wdi.weekday(), ...)
  so no special failbit handling is needed.  This eliminates the
  temporary basic_stringstream allocations for these types.

- Patch 1 (tests) verifies formatted output function semantics:
  sentry construction (badbit check, tied stream flush), width/fill
  with all three alignment modes, width reset, locale-aware output,
  weekday_indexed content, and wchar_t smoke test.

Performance (x86_64, GCC 17, -O2):

  Chrono operator<< latency:
    year_month_day    266 -> 203 ns  (1.31x)
    weekday           303 -> 251 ns  (1.20x)
    sys_info         1162 -> 986 ns  (1.18x)
    day               252 -> 217 ns  (1.16x)
    sys_time          437 -> 410 ns  (1.07x)
    zoned_time        591 -> 571 ns  (1.03x)
    hh_mm_ss          268 -> 261 ns  (1.03x)

  Multi-threaded throughput (sys_time): 1.07x-1.11x across 1-8 threads.
  Instruction count reduction: -2.8% to -22.8% across all types.
  No regressions in IPC, cache misses, or branch prediction.

Tested on x86_64-linux-gnu.  libstdc++ testsuite (std/time/*) clean.
Smoke test: all chrono operator<< outputs verified byte-identical.

Anlai Lu (2):
  libstdc++: Add stream state tests for chrono operator<<
  libstdc++: Use __chrono_write and __empty_fmt for chrono ostream
    insertion

 libstdc++-v3/include/bits/chrono_io.h         | 202 ++++++++++--------
 .../testsuite/std/time/ostream_insert.cc      | 163 ++++++++++++++
 2 files changed, 278 insertions(+), 87 deletions(-)
 create mode 100644 libstdc++-v3/testsuite/std/time/ostream_insert.cc

-- 
2.34.1

Reply via email to