On 14/11/14 15:43 +0000, Jonathan Wakely wrote:
This is the long-awaited ABI break for std::string, replacing our
venerable Copy-On-Write implementation with a C++11-conforming
Small-String-Optimization implementation (based on Paolo's vstring).

This patch fixes move construction and assignment in <sstream>.

I'm still trying to fix the locale facet instantiations.
diff --git a/libstdc++-v3/include/bits/basic_string.h 
b/libstdc++-v3/include/bits/basic_string.h
index 66560d2..ebcc462 100644
--- a/libstdc++-v3/include/bits/basic_string.h
+++ b/libstdc++-v3/include/bits/basic_string.h
@@ -471,7 +471,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
            _M_capacity(__str._M_allocated_capacity);
          }
 
-       _M_set_length(__str.length());
+       // Must use _M_length() here not _M_set_length() because
+       // basic_stringbuf relies on writing into unallocated capacity so
+       // we mess up the contents if we put a '\0' in the string.
+       _M_length(__str.length());
        __str._M_data(__str._M_local_data());
        __str._M_set_length(0);
       }
diff --git a/libstdc++-v3/include/std/sstream b/libstdc++-v3/include/std/sstream
index be44dae..1940ddd 100644
--- a/libstdc++-v3/include/std/sstream
+++ b/libstdc++-v3/include/std/sstream
@@ -64,6 +64,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     class _GLIBCXX_DEFAULT_ABI_TAG basic_stringbuf
     : public basic_streambuf<_CharT, _Traits>
     {
+      struct __xfer_bufptrs;
     public:
       // Types:
       typedef _CharT                                   char_type;
@@ -118,9 +119,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       basic_stringbuf(const basic_stringbuf&) = delete;
 
       basic_stringbuf(basic_stringbuf&& __rhs)
-      : __streambuf_type(static_cast<const __streambuf_type&>(__rhs)),
-      _M_mode(__rhs._M_mode), _M_string(std::move(__rhs._M_string))
-      { __rhs._M_stringbuf_init(__rhs._M_mode); }
+      : 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:
 
@@ -130,18 +130,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       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_stringbuf_init(__rhs._M_mode);
+       __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()));
@@ -288,6 +291,60 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       // interface of basic_streambuf, taking just an int.
       void
       _M_pbump(char_type* __pbeg, char_type* __pend, off_type __off);
+
+    private:
+#if __cplusplus >= 201103L
+#if _GLIBCXX_USE_CXX11_ABI
+      // This type captures the state of the gptr / pptr pointers as offsets
+      // so they can be restored in another object after moving the string.
+      struct __xfer_bufptrs
+      {
+       __xfer_bufptrs(const basic_stringbuf& __from, basic_stringbuf* __to)
+       : _M_to{__to}, _M_goff{-1, -1, -1}, _M_poff{-1, -1, -1}
+       {
+         const _CharT* __str = __from._M_string.data();
+         if (__from.eback())
+           {
+           _M_goff[0] = __from.eback() - __str;
+           _M_goff[1] = __from.gptr() - __str;
+           _M_goff[2] = __from.egptr() - __str;
+           }
+         if (__from.pbase())
+           {
+             _M_poff[0] = __from.pbase() - __str;
+             _M_poff[1] = __from.pptr() - __from.pbase();
+             _M_poff[2] = __from.epptr() - __str;
+           }
+       }
+
+       ~__xfer_bufptrs()
+       {
+         char_type* __str = const_cast<char_type*>(_M_to->_M_string.data());
+         if (_M_goff[0] != -1)
+           _M_to->setg(__str+_M_goff[0], __str+_M_goff[1], __str+_M_goff[2]);
+         if (_M_poff[0] != -1)
+           _M_to->_M_pbump(__str+_M_poff[0], __str+_M_poff[2], _M_poff[1]);
+       }
+
+       basic_stringbuf* _M_to;
+       off_type _M_goff[3];
+       off_type _M_poff[3];
+      };
+#else
+      // This type does nothing when using Copy-On-Write strings.
+      struct __xfer_bufptrs
+      {
+       __xfer_bufptrs(const basic_stringbuf&, basic_stringbuf*) { }
+      };
+#endif
+
+      // The move constructor initializes an __xfer_bufptrs temporary then
+      // delegates to this constructor to performs moves during its lifetime.
+      basic_stringbuf(basic_stringbuf&& __rhs, __xfer_bufptrs&&)
+      : __streambuf_type(static_cast<const __streambuf_type&>(__rhs)),
+      _M_mode(__rhs._M_mode), _M_string(std::move(__rhs._M_string))
+      { }
+#endif
     };
 
 

Reply via email to