]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - libstdc++-v3/include/std/sstream
Update copyright years.
[thirdparty/gcc.git] / libstdc++-v3 / include / std / sstream
index 33a00486606ccbd3b32516e7e5900a0e6f757498..dda7096afe407f19c36a20d7d3460309531fe1b7 100644 (file)
@@ -1,6 +1,6 @@
 // String based streams -*- C++ -*-
 
-// Copyright (C) 1997-2020 Free Software Foundation, Inc.
+// Copyright (C) 1997-2024 Free Software Foundation, Inc.
 //
 // This file is part of the GNU ISO C++ Library.  This library is free
 // software; you can redistribute it and/or modify it under the
 
 #pragma GCC system_header
 
+#include <bits/requires_hosted.h> // iostream
+
 #include <istream>
 #include <ostream>
+#include <bits/alloc_traits.h> // allocator_traits, __allocator_like
+
+#if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
+# define _GLIBCXX_LVAL_REF_QUAL &
+# define _GLIBCXX_SSTREAM_ALWAYS_INLINE
+#else
+# define _GLIBCXX_LVAL_REF_QUAL
+// For symbols that are not exported from libstdc++.so for the COW string ABI.
+# define _GLIBCXX_SSTREAM_ALWAYS_INLINE [[__gnu__::__always_inline__]]
+#endif
+
+
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
@@ -65,6 +79,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
     class basic_stringbuf : public basic_streambuf<_CharT, _Traits>
     {
       struct __xfer_bufptrs;
+
+#if __cplusplus >= 201103L
+      using allocator_traits = std::allocator_traits<_Alloc>;
+      using _Noexcept_swap
+       = __or_<typename allocator_traits::propagate_on_container_swap,
+               typename allocator_traits::is_always_equal>;
+#endif
+
     public:
       // Types:
       typedef _CharT                                   char_type;
@@ -134,40 +156,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       : basic_stringbuf(std::move(__rhs), __xfer_bufptrs(__rhs, this))
       { __rhs._M_sync(const_cast<char_type*>(__rhs._M_string.data()), 0, 0); }
 
-      // 27.8.2.2 Assign and swap:
-
-      basic_stringbuf&
-      operator=(const basic_stringbuf&) = delete;
-
-      basic_stringbuf&
-      operator=(basic_stringbuf&& __rhs)
-      {
-       __xfer_bufptrs __st{__rhs, this};
-       const __streambuf_type& __base = __rhs;
-       __streambuf_type::operator=(__base);
-       this->pubimbue(__rhs.getloc());
-       _M_mode = __rhs._M_mode;
-       _M_string = std::move(__rhs._M_string);
-       __rhs._M_sync(const_cast<char_type*>(__rhs._M_string.data()), 0, 0);
-       return *this;
-      }
-
-      void
-      swap(basic_stringbuf& __rhs)
-      {
-       __xfer_bufptrs __l_st{*this, std::__addressof(__rhs)};
-       __xfer_bufptrs __r_st{__rhs, this};
-       __streambuf_type& __base = __rhs;
-       __streambuf_type::swap(__base);
-       __rhs.pubimbue(this->pubimbue(__rhs.getloc()));
-       std::swap(_M_mode, __rhs._M_mode);
-       std::swap(_M_string, __rhs._M_string);
-      }
-#endif
-
 #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
-      using __sv_type = basic_string_view<char_type, traits_type>;
-
+      explicit
       basic_stringbuf(const allocator_type& __a)
       : basic_stringbuf(ios_base::in | std::ios_base::out, __a)
       { }
@@ -179,29 +169,29 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 
       explicit
       basic_stringbuf(__string_type&& __s,
-                     ios_base::openmode __mode = ios_base::in
-                                                 | ios_base::out )
+                     ios_base::openmode __mode = ios_base::in
+                                                 | ios_base::out)
       : __streambuf_type(), _M_mode(__mode), _M_string(std::move(__s))
       { _M_stringbuf_init(__mode); }
 
       template<typename _SAlloc>
-      basic_stringbuf(const basic_string<_CharT, _Traits, _SAlloc>& __s,
-                     const allocator_type& __a )
-      : basic_stringbuf(__s, ios_base::in | std::ios_base::out, __a )
-      { }
+       basic_stringbuf(const basic_string<_CharT, _Traits, _SAlloc>& __s,
+                       const allocator_type& __a)
+       : basic_stringbuf(__s, ios_base::in | std::ios_base::out, __a)
+       { }
 
       template<typename _SAlloc>
-      basic_stringbuf(const basic_string<_CharT, _Traits, _SAlloc>& __s,
-                     ios_base::openmode __mode,
-                     const allocator_type& __a)
-      : __streambuf_type(), _M_mode(__mode),
-      _M_string(static_cast<__sv_type>(__s), __a)
-      { }
+       basic_stringbuf(const basic_string<_CharT, _Traits, _SAlloc>& __s,
+                       ios_base::openmode __mode,
+                       const allocator_type& __a)
+       : __streambuf_type(), _M_mode(__mode),
+         _M_string(__s.data(), __s.size(), __a)
+       { _M_stringbuf_init(__mode); }
 
       template<typename _SAlloc>
        explicit
        basic_stringbuf(const basic_string<_CharT, _Traits, _SAlloc>& __s,
-                       ios_base::openmode __mode = ios_base::in
+                       ios_base::openmode __mode = ios_base::in
                                                    | ios_base::out)
        : basic_stringbuf(__s, __mode, allocator_type{})
        { }
@@ -212,9 +202,41 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 
       allocator_type get_allocator() const noexcept
       { return _M_string.get_allocator(); }
-#endif
+#endif // C++20
+
+      // 27.8.2.2 Assign and swap:
+
+      basic_stringbuf&
+      operator=(const basic_stringbuf&) = delete;
+
+      basic_stringbuf&
+      operator=(basic_stringbuf&& __rhs)
+      {
+       __xfer_bufptrs __st{__rhs, this};
+       const __streambuf_type& __base = __rhs;
+       __streambuf_type::operator=(__base);
+       this->pubimbue(__rhs.getloc());
+       _M_mode = __rhs._M_mode;
+       _M_string = std::move(__rhs._M_string);
+       __rhs._M_sync(const_cast<char_type*>(__rhs._M_string.data()), 0, 0);
+       return *this;
+      }
+
+      void
+      swap(basic_stringbuf& __rhs) noexcept(_Noexcept_swap::value)
+      {
+       __xfer_bufptrs __l_st{*this, std::__addressof(__rhs)};
+       __xfer_bufptrs __r_st{__rhs, this};
+       __streambuf_type& __base = __rhs;
+       __streambuf_type::swap(__base);
+       __rhs.pubimbue(this->pubimbue(__rhs.getloc()));
+       std::swap(_M_mode, __rhs._M_mode);
+       std::swap(_M_string, __rhs._M_string); // XXX not exception safe
+      }
+#endif // C++11
+
+      // Getters and setters:
 
-      // Get and set:
       /**
        *  @brief  Copying out the string buffer.
        *  @return  A copy of one of the underlying sequences.
@@ -224,23 +246,54 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
        *  is equal to the output sequence.</em> [27.7.1.2]/1
       */
       __string_type
-      str() const
+      str() const _GLIBCXX_LVAL_REF_QUAL
       {
        __string_type __ret(_M_string.get_allocator());
-       if (char_type* __pptr = this->pptr())
-         {
-           char_type* __egptr = this->egptr();
-           // The current egptr() may not be the actual string end.
-           if (!__egptr || __pptr > __egptr)
-             __ret.assign(this->pbase(), __pptr);
-           else
-             __ret.assign(this->pbase(), __egptr);
-         }
+       if (char_type* __hi = _M_high_mark())
+         __ret.assign(this->pbase(), __hi);
        else
          __ret = _M_string;
        return __ret;
       }
 
+#if __cplusplus > 201703L
+#if _GLIBCXX_USE_CXX11_ABI
+#if __cpp_concepts
+      template<__allocator_like _SAlloc>
+       basic_string<_CharT, _Traits, _SAlloc>
+       str(const _SAlloc& __sa) const
+       {
+         auto __sv = view();
+         return { __sv.data(), __sv.size(), __sa };
+       }
+#endif
+
+      __string_type
+      str() &&
+      {
+       if (char_type* __hi = _M_high_mark())
+         {
+           // Set length to end of character sequence and add null terminator.
+           _M_string._M_set_length(_M_high_mark() - this->pbase());
+         }
+       auto __str = std::move(_M_string);
+       _M_string.clear();
+       _M_sync(_M_string.data(), 0, 0);
+       return __str;
+      }
+#endif // cxx11 ABI
+
+      _GLIBCXX_SSTREAM_ALWAYS_INLINE
+      basic_string_view<char_type, traits_type>
+      view() const noexcept
+      {
+       if (char_type* __hi = _M_high_mark())
+         return { this->pbase(), __hi };
+       else
+         return _M_string;
+      }
+#endif // C++20
+
       /**
        *  @brief  Setting a new buffer.
        *  @param  __s  The string to use as a new sequence.
@@ -258,19 +311,22 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       }
 
 #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
-      __sv_type
-      view() const noexcept
+#if __cpp_concepts
+      template<__allocator_like _SAlloc>
+       requires (!is_same_v<_SAlloc, _Alloc>)
+       void
+       str(const basic_string<_CharT, _Traits, _SAlloc>& __s)
+       {
+         _M_string.assign(__s.data(), __s.size());
+         _M_stringbuf_init(_M_mode);
+       }
+#endif
+
+      void
+      str(__string_type&& __s)
       {
-       if (this->pptr())
-         {
-           // The current egptr() may not be the actual string end.
-           if (this->pptr() > this->egptr())
-             return __sv_type(this->pbase(), this->pptr());
-           else
-             return __sv_type(this->pbase(), this->egptr());
-         }
-       else
-         return static_cast<__sv_type>(_M_string);
+       _M_string = std::move(__s);
+       _M_stringbuf_init(_M_mode);
       }
 #endif
 
@@ -356,13 +412,16 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       void
       _M_update_egptr()
       {
-       const bool __testin = _M_mode & ios_base::in;
-       if (this->pptr() && this->pptr() > this->egptr())
+       if (char_type* __pptr = this->pptr())
          {
-           if (__testin)
-             this->setg(this->eback(), this->gptr(), this->pptr());
-           else
-             this->setg(this->pptr(), this->pptr(), this->pptr());
+           char_type* __egptr = this->egptr();
+           if (!__egptr || __pptr > __egptr)
+             {
+               if (_M_mode & ios_base::in)
+                 this->setg(this->eback(), this->gptr(), __pptr);
+               else
+                 this->setg(__pptr, __pptr, __pptr);
+             }
          }
       }
 
@@ -372,6 +431,25 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       _M_pbump(char_type* __pbeg, char_type* __pend, off_type __off);
 
     private:
+      // Return a pointer to the end of the underlying character sequence.
+      // This might not be the same character as _M_string.end() because
+      // basic_stringbuf::overflow might have written to unused capacity
+      // in _M_string without updating its length.
+      __attribute__((__always_inline__))
+      char_type*
+      _M_high_mark() const _GLIBCXX_NOEXCEPT
+      {
+       if (char_type* __pptr = this->pptr())
+         {
+           char_type* __egptr = this->egptr();
+           if (!__egptr || __pptr > __egptr)
+             return __pptr;  // Underlying sequence is [pbase, pptr).
+           else
+             return __egptr; // Underlying sequence is [pbase, egptr).
+         }
+       return 0; // Underlying character sequence is just _M_string.
+      }
+
 #if __cplusplus >= 201103L
 #if _GLIBCXX_USE_CXX11_ABI
       // This type captures the state of the gptr / pptr pointers as offsets
@@ -395,7 +473,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
              _M_poff[0] = __from.pbase() - __str;
              _M_poff[1] = __from.pptr() - __from.pbase();
              _M_poff[2] = __from.epptr() - __str;
-             if (__from.pptr() > __end)
+             if (!__end || __from.pptr() > __end)
                __end = __from.pptr();
            }
 
@@ -446,7 +524,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       _M_mode(__rhs._M_mode), _M_string(std::move(__rhs._M_string), __a)
       { }
 #endif
-#endif
+#endif // C++11
     };
 
 
@@ -556,27 +634,6 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       _M_stringbuf(std::move(__rhs._M_stringbuf))
       { __istream_type::set_rdbuf(&_M_stringbuf); }
 
-      // 27.8.3.2 Assign and swap:
-
-      basic_istringstream&
-      operator=(const basic_istringstream&) = delete;
-
-      basic_istringstream&
-      operator=(basic_istringstream&& __rhs)
-      {
-       __istream_type::operator=(std::move(__rhs));
-       _M_stringbuf = std::move(__rhs._M_stringbuf);
-       return *this;
-      }
-
-      void
-      swap(basic_istringstream& __rhs)
-      {
-       __istream_type::swap(__rhs);
-       _M_stringbuf.swap(__rhs._M_stringbuf);
-      }
-#endif
-
 #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
       basic_istringstream(ios_base::openmode __mode, const allocator_type& __a)
       : __istream_type(), _M_stringbuf(__mode | ios_base::in, __a)
@@ -584,7 +641,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 
       explicit
       basic_istringstream(__string_type&& __str,
-                         ios_base::openmode __mode = ios_base::in )
+                         ios_base::openmode __mode = ios_base::in)
       : __istream_type(), _M_stringbuf(std::move(__str), __mode | ios_base::in)
       { this->init(std::__addressof(_M_stringbuf)); }
 
@@ -598,18 +655,37 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
        basic_istringstream(const basic_string<_CharT, _Traits, _SAlloc>& __str,
                            ios_base::openmode __mode,
                            const allocator_type& __a)
-       : __istream_type(),
-       _M_stringbuf(__string_type(__str.data(), __str.size()),
-                    __mode | ios_base::in, __a)
+       : __istream_type(), _M_stringbuf(__str, __mode | ios_base::in, __a)
        { this->init(std::__addressof(_M_stringbuf)); }
 
       template<typename _SAlloc>
        explicit
        basic_istringstream(const basic_string<_CharT, _Traits, _SAlloc>& __str,
-                           ios_base::openmode __mode = ios_base::in)
+                           ios_base::openmode __mode = ios_base::in)
        : basic_istringstream(__str, __mode, allocator_type())
        { }
-#endif
+#endif // C++20
+
+      // 27.8.3.2 Assign and swap:
+
+      basic_istringstream&
+      operator=(const basic_istringstream&) = delete;
+
+      basic_istringstream&
+      operator=(basic_istringstream&& __rhs)
+      {
+       __istream_type::operator=(std::move(__rhs));
+       _M_stringbuf = std::move(__rhs._M_stringbuf);
+       return *this;
+      }
+
+      void
+      swap(basic_istringstream& __rhs)
+      {
+       __istream_type::swap(__rhs);
+       _M_stringbuf.swap(__rhs._M_stringbuf);
+      }
+#endif // C++11
 
       // Members:
       /**
@@ -627,9 +703,29 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
        *  @return  @c rdbuf()->str()
       */
       __string_type
-      str() const
+      str() const _GLIBCXX_LVAL_REF_QUAL
       { return _M_stringbuf.str(); }
 
+#if __cplusplus > 201703L
+#if _GLIBCXX_USE_CXX11_ABI
+#if __cpp_concepts
+      template<__allocator_like _SAlloc>
+       basic_string<_CharT, _Traits, _SAlloc>
+       str(const _SAlloc& __sa) const
+       { return _M_stringbuf.str(__sa); }
+#endif
+
+      __string_type
+      str() &&
+      { return std::move(_M_stringbuf).str(); }
+#endif // cxx11 ABI
+
+      _GLIBCXX_SSTREAM_ALWAYS_INLINE
+      basic_string_view<char_type, traits_type>
+      view() const noexcept
+      { return _M_stringbuf.view(); }
+#endif // C++20
+
       /**
        *  @brief  Setting a new buffer.
        *  @param  __s  The string to use as a new sequence.
@@ -641,9 +737,17 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       { _M_stringbuf.str(__s); }
 
 #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
-      basic_string_view<char_type, traits_type>
-      view() const noexcept
-      { return _M_stringbuf.view(); }
+#if __cpp_concepts
+      template<__allocator_like _SAlloc>
+       requires (!is_same_v<_SAlloc, _Alloc>)
+       void
+       str(const basic_string<_CharT, _Traits, _SAlloc>& __s)
+       { _M_stringbuf.str(__s); }
+#endif
+
+      void
+      str(__string_type&& __s)
+      { _M_stringbuf.str(std::move(__s)); }
 #endif
     };
 
@@ -754,27 +858,6 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       _M_stringbuf(std::move(__rhs._M_stringbuf))
       { __ostream_type::set_rdbuf(&_M_stringbuf); }
 
-      // 27.8.3.2 Assign and swap:
-
-      basic_ostringstream&
-      operator=(const basic_ostringstream&) = delete;
-
-      basic_ostringstream&
-      operator=(basic_ostringstream&& __rhs)
-      {
-       __ostream_type::operator=(std::move(__rhs));
-       _M_stringbuf = std::move(__rhs._M_stringbuf);
-       return *this;
-      }
-
-      void
-      swap(basic_ostringstream& __rhs)
-      {
-       __ostream_type::swap(__rhs);
-       _M_stringbuf.swap(__rhs._M_stringbuf);
-      }
-#endif
-
 #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
       basic_ostringstream(ios_base::openmode __mode, const allocator_type& __a)
       : __ostream_type(), _M_stringbuf(__mode | ios_base::out, __a)
@@ -782,7 +865,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 
       explicit
       basic_ostringstream(__string_type&& __str,
-                         ios_base::openmode __mode = ios_base::out )
+                         ios_base::openmode __mode = ios_base::out)
       : __ostream_type(), _M_stringbuf(std::move(__str), __mode | ios_base::out)
       { this->init(std::__addressof(_M_stringbuf)); }
 
@@ -796,18 +879,37 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
        basic_ostringstream(const basic_string<_CharT, _Traits, _SAlloc>& __str,
                            ios_base::openmode __mode,
                            const allocator_type& __a)
-       : __ostream_type(),
-       _M_stringbuf(__string_type(__str.data(), __str.size()),
-                    __mode | ios_base::out, __a)
+       : __ostream_type(), _M_stringbuf(__str, __mode | ios_base::out, __a)
        { this->init(std::__addressof(_M_stringbuf)); }
 
       template<typename _SAlloc>
        explicit
        basic_ostringstream(const basic_string<_CharT, _Traits, _SAlloc>& __str,
-                           ios_base::openmode __mode = ios_base::out)
+                           ios_base::openmode __mode = ios_base::out)
        : basic_ostringstream(__str, __mode, allocator_type())
        { }
-#endif
+#endif // C++20
+
+      // 27.8.3.2 Assign and swap:
+
+      basic_ostringstream&
+      operator=(const basic_ostringstream&) = delete;
+
+      basic_ostringstream&
+      operator=(basic_ostringstream&& __rhs)
+      {
+       __ostream_type::operator=(std::move(__rhs));
+       _M_stringbuf = std::move(__rhs._M_stringbuf);
+       return *this;
+      }
+
+      void
+      swap(basic_ostringstream& __rhs)
+      {
+       __ostream_type::swap(__rhs);
+       _M_stringbuf.swap(__rhs._M_stringbuf);
+      }
+#endif // C++11
 
       // Members:
       /**
@@ -825,9 +927,29 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
        *  @return  @c rdbuf()->str()
       */
       __string_type
-      str() const
+      str() const _GLIBCXX_LVAL_REF_QUAL
       { return _M_stringbuf.str(); }
 
+#if __cplusplus > 201703L
+#if _GLIBCXX_USE_CXX11_ABI
+#if __cpp_concepts
+      template<__allocator_like _SAlloc>
+       basic_string<_CharT, _Traits, _SAlloc>
+       str(const _SAlloc& __sa) const
+       { return _M_stringbuf.str(__sa); }
+#endif
+
+      __string_type
+      str() &&
+      { return std::move(_M_stringbuf).str(); }
+#endif // cxx11 ABI
+
+      _GLIBCXX_SSTREAM_ALWAYS_INLINE
+      basic_string_view<char_type, traits_type>
+      view() const noexcept
+      { return _M_stringbuf.view(); }
+#endif // C++20
+
       /**
        *  @brief  Setting a new buffer.
        *  @param  __s  The string to use as a new sequence.
@@ -839,9 +961,17 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       { _M_stringbuf.str(__s); }
 
 #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
-      basic_string_view<char_type, traits_type>
-      view() const noexcept
-      { return _M_stringbuf.view(); }
+#if __cpp_concepts
+      template<__allocator_like _SAlloc>
+       requires (!is_same_v<_SAlloc, _Alloc>)
+       void
+       str(const basic_string<_CharT, _Traits, _SAlloc>& __s)
+       { _M_stringbuf.str(__s); }
+#endif
+
+      void
+      str(__string_type&& __s)
+      { _M_stringbuf.str(std::move(__s)); }
 #endif
     };
 
@@ -948,27 +1078,6 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       _M_stringbuf(std::move(__rhs._M_stringbuf))
       { __iostream_type::set_rdbuf(&_M_stringbuf); }
 
-      // 27.8.3.2 Assign and swap:
-
-      basic_stringstream&
-      operator=(const basic_stringstream&) = delete;
-
-      basic_stringstream&
-      operator=(basic_stringstream&& __rhs)
-      {
-       __iostream_type::operator=(std::move(__rhs));
-       _M_stringbuf = std::move(__rhs._M_stringbuf);
-       return *this;
-      }
-
-      void
-      swap(basic_stringstream& __rhs)
-      {
-       __iostream_type::swap(__rhs);
-       _M_stringbuf.swap(__rhs._M_stringbuf);
-      }
-#endif
-
 #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
       basic_stringstream(ios_base::openmode __mode, const allocator_type& __a)
       : __iostream_type(), _M_stringbuf(__mode, __a)
@@ -976,7 +1085,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 
       explicit
       basic_stringstream(__string_type&& __str,
-                        ios_base::openmode __mode = ios_base::out
+                        ios_base::openmode __mode = ios_base::in
                                                     | ios_base::out)
       : __iostream_type(), _M_stringbuf(std::move(__str), __mode)
       { this->init(std::__addressof(_M_stringbuf)); }
@@ -989,19 +1098,40 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 
       template<typename _SAlloc>
        basic_stringstream(const basic_string<_CharT, _Traits, _SAlloc>& __str,
-                          ios_base::openmode __mode, const allocator_type& __a)
-       : __iostream_type(),
-       _M_stringbuf(__string_type(__str.data(), __str.size()), __mode, __a)
+                          ios_base::openmode __mode,
+                          const allocator_type& __a)
+       : __iostream_type(), _M_stringbuf(__str, __mode, __a)
        { this->init(std::__addressof(_M_stringbuf)); }
 
       template<typename _SAlloc>
        explicit
        basic_stringstream(const basic_string<_CharT, _Traits, _SAlloc>& __str,
-                          ios_base::openmode __mode = ios_base::in
+                          ios_base::openmode __mode = ios_base::in
                                                       | ios_base::out)
        : basic_stringstream(__str, __mode, allocator_type())
        { }
-#endif
+#endif // C++20
+
+      // 27.8.3.2 Assign and swap:
+
+      basic_stringstream&
+      operator=(const basic_stringstream&) = delete;
+
+      basic_stringstream&
+      operator=(basic_stringstream&& __rhs)
+      {
+       __iostream_type::operator=(std::move(__rhs));
+       _M_stringbuf = std::move(__rhs._M_stringbuf);
+       return *this;
+      }
+
+      void
+      swap(basic_stringstream& __rhs)
+      {
+       __iostream_type::swap(__rhs);
+       _M_stringbuf.swap(__rhs._M_stringbuf);
+      }
+#endif // C++11
 
       // Members:
       /**
@@ -1019,9 +1149,29 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
        *  @return  @c rdbuf()->str()
       */
       __string_type
-      str() const
+      str() const _GLIBCXX_LVAL_REF_QUAL
       { return _M_stringbuf.str(); }
 
+#if __cplusplus > 201703L
+#if _GLIBCXX_USE_CXX11_ABI
+#if __cpp_concepts
+      template<__allocator_like _SAlloc>
+       basic_string<_CharT, _Traits, _SAlloc>
+       str(const _SAlloc& __sa) const
+       { return _M_stringbuf.str(__sa); }
+#endif
+
+      __string_type
+      str() &&
+      { return std::move(_M_stringbuf).str(); }
+#endif // cxx11 ABI
+
+      _GLIBCXX_SSTREAM_ALWAYS_INLINE
+      basic_string_view<char_type, traits_type>
+      view() const noexcept
+      { return _M_stringbuf.view(); }
+#endif // C++20
+
       /**
        *  @brief  Setting a new buffer.
        *  @param  __s  The string to use as a new sequence.
@@ -1033,9 +1183,17 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       { _M_stringbuf.str(__s); }
 
 #if __cplusplus > 201703L && _GLIBCXX_USE_CXX11_ABI
-      basic_string_view<char_type, traits_type>
-      view() const noexcept
-      { return _M_stringbuf.view(); }
+#if __cpp_concepts
+      template<__allocator_like _SAlloc>
+       requires (!is_same_v<_SAlloc, _Alloc>)
+       void
+       str(const basic_string<_CharT, _Traits, _SAlloc>& __s)
+       { _M_stringbuf.str(__s); }
+#endif
+
+      void
+      str(__string_type&& __s)
+      { _M_stringbuf.str(std::move(__s)); }
 #endif
     };
 
@@ -1045,6 +1203,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
     inline void
     swap(basic_stringbuf<_CharT, _Traits, _Allocator>& __x,
         basic_stringbuf<_CharT, _Traits, _Allocator>& __y)
+    noexcept(noexcept(__x.swap(__y)))
     { __x.swap(__y); }
 
   /// Swap specialization for istringstreams.
@@ -1067,12 +1226,15 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
     swap(basic_stringstream<_CharT, _Traits, _Allocator>& __x,
         basic_stringstream<_CharT, _Traits, _Allocator>& __y)
     { __x.swap(__y); }
-#endif
+#endif // C++11
 
 _GLIBCXX_END_NAMESPACE_CXX11
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace
 
+#undef _GLIBCXX_SSTREAM_ALWAYS_INLINE
+#undef _GLIBCXX_LVAL_REF_QUAL
+
 #include <bits/sstream.tcc>
 
 #endif /* _GLIBCXX_SSTREAM */