[gcc r12-6473] libstdc++: Optimize std::ostream inserters for single characters

Jonathan Wakely redi@gcc.gnu.org
Tue Jan 11 13:28:57 GMT 2022


https://gcc.gnu.org/g:e4fe6dba90b831dbd8f5e23041c5e0e8bdd75332

commit r12-6473-ge4fe6dba90b831dbd8f5e23041c5e0e8bdd75332
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Mon Jan 10 17:38:33 2022 +0000

    libstdc++: Optimize std::ostream inserters for single characters
    
    On the libsdc++ mailing list Lewis Hyatt pointed out the performance
    overhead of using sputn in stream inserters, rather than writing
    directly to the streambuf's put area:
    https://gcc.gnu.org/pipermail/libstdc++/2021-July/052877.html
    
    As Lewis noted, the standard explicitly requires a call to sputn for
    inserting a std::basic_string_view or std::basic_string.  But for
    inserting single characters or null-terminated strings it is more vague,
    and so we can improve performance by not using the __ostream_insert
    function.
    
    This is a minimal change that avoids __ostream_insert for single
    characters. We can use the unformatted basic_ostream::put(charT)
    function when we don't need the additional effects of a formatted output
    function (i.e. padding and resetting the width). The put function will
    insert into the buffer if possible, and only make a virtual call (to
    overflow) if the buffer is full.
    
    We could also avoid sputn when inserting null-terminated character
    strings, but that would require using a new function for inserting
    null-terminated strings, so the existing code using sputn is still used
    for basic_string and basic_string_view. My preference is to leave that
    for now, and try to improve the standard. We could either remove the
    requirement to call sputn, or allow sputn to write directly to the
    buffer instead of calling xsputn.
    
    libstdc++-v3/ChangeLog:
    
            * include/std/ostream (operator<<(basic_ostream&, charT)):
            Use unformatted input if no padding is needed.
            (operator<<(basic_ostream<char>&, char)): Likewise.

Diff:
---
 libstdc++-v3/include/std/ostream | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/libstdc++-v3/include/std/ostream b/libstdc++-v3/include/std/ostream
index f8073f2a9b7..291ea40b355 100644
--- a/libstdc++-v3/include/std/ostream
+++ b/libstdc++-v3/include/std/ostream
@@ -505,7 +505,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _CharT, typename _Traits>
     inline basic_ostream<_CharT, _Traits>&
     operator<<(basic_ostream<_CharT, _Traits>& __out, _CharT __c)
-    { return __ostream_insert(__out, &__c, 1); }
+    {
+      if (__out.width() != 0)
+	return __ostream_insert(__out, &__c, 1);
+      __out.put(__c);
+      return __out;
+    }
 
   template<typename _CharT, typename _Traits>
     inline basic_ostream<_CharT, _Traits>&
@@ -516,7 +521,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Traits>
     inline basic_ostream<char, _Traits>&
     operator<<(basic_ostream<char, _Traits>& __out, char __c)
-    { return __ostream_insert(__out, &__c, 1); }
+    {
+      if (__out.width() != 0)
+	return __ostream_insert(__out, &__c, 1);
+      __out.put(__c);
+      return __out;
+    }
 
   // Signed and unsigned
   template<typename _Traits>


More information about the Libstdc++-cvs mailing list