diff mbox

New std::string implementation

Message ID 20141117104140.GP5191@redhat.com
State New
Headers show

Commit Message

Jonathan Wakely Nov. 17, 2014, 10:41 a.m. UTC
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 mbox

Patch

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
     };