* [PATCH] PR libstdc++/69608 Move semantics for strstreambuf
@ 2018-05-02 16:25 Jonathan Wakely
2018-05-02 16:27 ` Jonathan Wakely
0 siblings, 1 reply; 2+ messages in thread
From: Jonathan Wakely @ 2018-05-02 16:25 UTC (permalink / raw)
To: libstdc++, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 594 bytes --]
In libstdc++ the deprecated char* streams are non-copyable, as was
required pre-C++11.
Since C++11 the standard implies that those streams should be copyable,
but doesn't specify the effects of copying them. This is surely a
defect, so for consistency with other implementations this change makes
them movable, but not copyable.
PR libstdc++/69608
* include/backward/strstream (strstreambuf): Define move constructor
and move assignment operator.
(istrstream, ostrstream, strstream): Likewise.
* testsuite/backward/strstream_move.cc: New.
Tested powerpc64le-linux, committed to trunk.
[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 9730 bytes --]
commit 323f52cd6604c661dd07b8fbc79e10f1ae778255
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Wed May 2 17:06:18 2018 +0100
PR libstdc++/69608 Move semantics for strstreambuf
In libstdc++ the deprecated char* streams are non-copyable, as was
required pre-C++11.
Since C++11 the standard implies that those streams should be copyable,
but doesn't specify the effects of copying them. This is surely a
defect, so for consistency with other implementations this change makes
them movable, but not copyable.
PR libstdc++/69608
* include/backward/strstream (strstreambuf): Define move constructor
and move assignment operator.
(istrstream, ostrstream, strstream): Likewise.
* testsuite/backward/strstream_move.cc: New.
diff --git a/libstdc++-v3/include/backward/strstream b/libstdc++-v3/include/backward/strstream
index 0f0ede46f7a..0429c28ce35 100644
--- a/libstdc++-v3/include/backward/strstream
+++ b/libstdc++-v3/include/backward/strstream
@@ -81,6 +81,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
virtual ~strstreambuf();
+#if __cplusplus >= 201103L
+ strstreambuf(strstreambuf&& __rhs) noexcept
+ : _Base(__rhs), _M_alloc_fun(__rhs._M_alloc_fun),
+ _M_free_fun(__rhs._M_free_fun), _M_dynamic(__rhs._M_dynamic),
+ _M_frozen(__rhs._M_frozen), _M_constant(__rhs._M_constant)
+ {
+ __rhs.setg(nullptr, nullptr, nullptr);
+ __rhs.setp(nullptr, nullptr);
+ }
+
+ strstreambuf&
+ operator=(strstreambuf&& __rhs) noexcept
+ {
+ if (_M_dynamic && !_M_frozen)
+ _M_free(eback());
+ _Base::operator=(static_cast<const _Base&>(__rhs));
+ _M_alloc_fun = __rhs._M_alloc_fun;
+ _M_free_fun = __rhs._M_free_fun;
+ _M_dynamic = __rhs._M_dynamic;
+ _M_frozen = __rhs._M_frozen;
+ _M_constant = __rhs._M_constant;
+ __rhs.setg(nullptr, nullptr, nullptr);
+ __rhs.setp(nullptr, nullptr);
+ return *this;
+ }
+#endif
+
public:
void freeze(bool = true) throw ();
char* str() throw ();
@@ -98,10 +125,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
= ios_base::in | ios_base::out);
private:
+#if __cplusplus < 201103L
strstreambuf&
operator=(const strstreambuf&);
strstreambuf(const strstreambuf&);
+#endif
// Dynamic allocation, possibly using _M_alloc_fun and _M_free_fun.
char* _M_alloc(size_t);
@@ -110,7 +139,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Helper function used in constructors.
void _M_setup(char* __get, char* __put, streamsize __n) throw ();
- private:
// Data members.
void* (*_M_alloc_fun)(size_t);
void (*_M_free_fun)(void*);
@@ -130,6 +158,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
istrstream(const char*, streamsize);
virtual ~istrstream();
+#if __cplusplus >= 201103L
+ istrstream(istrstream&& __rhs)
+ : istream(std::move(__rhs)), _M_buf(std::move(__rhs._M_buf))
+ { set_rdbuf(&_M_buf); }
+
+ istrstream& operator=(istrstream&&) = default;
+#endif
+
_GLIBCXX_CONST strstreambuf* rdbuf() const throw ();
char* str() throw ();
@@ -145,6 +181,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
ostrstream(char*, int, ios_base::openmode = ios_base::out);
virtual ~ostrstream();
+#if __cplusplus >= 201103L
+ ostrstream(ostrstream&& __rhs)
+ : ostream(std::move(__rhs)), _M_buf(std::move(__rhs._M_buf))
+ { set_rdbuf(&_M_buf); }
+
+ ostrstream& operator=(ostrstream&&) = default;
+#endif
+
_GLIBCXX_CONST strstreambuf* rdbuf() const throw ();
void freeze(bool = true) throw();
char* str() throw ();
@@ -167,6 +211,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
strstream(char*, int, ios_base::openmode = ios_base::in | ios_base::out);
virtual ~strstream();
+#if __cplusplus >= 201103L
+ strstream(strstream&& __rhs)
+ : iostream(std::move(__rhs)), _M_buf(std::move(__rhs._M_buf))
+ { set_rdbuf(&_M_buf); }
+
+ strstream& operator=(strstream&&) = default;
+#endif
+
_GLIBCXX_CONST strstreambuf* rdbuf() const throw ();
void freeze(bool = true) throw ();
_GLIBCXX_PURE int pcount() const throw ();
diff --git a/libstdc++-v3/testsuite/backward/strstream_move.cc b/libstdc++-v3/testsuite/backward/strstream_move.cc
new file mode 100644
index 00000000000..7dfbd337901
--- /dev/null
+++ b/libstdc++-v3/testsuite/backward/strstream_move.cc
@@ -0,0 +1,244 @@
+// Copyright (C) 2018 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
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-Wno-deprecated" }
+// { dg-do run { target c++11 } }
+
+#include <strstream>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+ std::istrstream is("15 16");
+ std::istrstream is2 = std::move(is);
+ int a;
+ is >> a;
+ VERIFY( !is );
+ is2 >> a;
+ VERIFY( is2 );
+ VERIFY( a == 15 );
+ std::istrstream is3 = std::move(is2);
+ int b;
+ is2 >> b;
+ VERIFY( !is2 );
+ is3 >> b;
+ VERIFY( is3 );
+ VERIFY( b == 16 );
+}
+
+void
+test02()
+{
+ std::istrstream is("");
+ int a;
+ is >> a;
+ VERIFY( !is );
+ is = std::istrstream("17 18");
+ is >> a;
+ VERIFY( is );
+ VERIFY( a == 17 );
+ is = std::istrstream("");
+ int b;
+ is >> b;
+ VERIFY( !is );
+}
+
+void
+test03()
+{
+ std::ostrstream os;
+ os << "a few chars"; // fits in initial allocation
+ char* s = os.str(); // os now frozen
+ std::ostrstream os2 = std::move(os);
+ VERIFY( os2.str() == s );
+ VERIFY( os.str() == nullptr );
+ os2.freeze(false);
+
+ os2 << "enough additional chars to force a reallocation";
+ VERIFY( os2 );
+ s = os2.str(); // os2 now frozen
+ std::ostrstream os3 = std::move(os2);
+ VERIFY( os3.str() == s );
+ VERIFY( os2.str() == nullptr );
+ delete[] s;
+}
+
+void
+test04()
+{
+ char buf[16];
+ std::ostrstream os(buf, sizeof(buf));
+ os << "a few chars";
+ char* s = os.str(); // os now frozen
+ VERIFY( s == buf );
+ std::ostrstream os2 = std::move(os);
+ VERIFY( os2.str() == s );
+ VERIFY( os.str() == nullptr );
+ os2.freeze(false);
+
+ os2 << "enough additional chars to force a reallocation";
+ VERIFY( !os2 );
+ s = os2.str(); // os2 now frozen
+ VERIFY( s == buf );
+ std::ostrstream os3 = std::move(os2);
+ VERIFY( os3.str() == s );
+ VERIFY( os2.str() == nullptr );
+}
+
+void
+test05()
+{
+ char buf[] = "0123456789";
+ std::ostrstream os(buf, 1);
+ os << "aa";
+ VERIFY( !os );
+ os = std::ostrstream(buf, 10);
+ os << "some chars";
+ VERIFY( os );
+ VERIFY( os.pcount() == 10 );
+ os << "a";
+ VERIFY( !os );
+ os = std::ostrstream();
+ os << "a";
+ VERIFY( os );
+ VERIFY( os.pcount() == 1 );
+ char* s = os.str(); // os now frozen
+ os = std::ostrstream();
+ os.freeze(false); // no effect
+ delete[] s;
+}
+
+void
+test06()
+{
+ char buf[] = "15 16";
+ std::strstream ss(buf, 5, std::ios::in|std::ios::app);
+ std::strstream ss2 = std::move(ss);
+ int a;
+ ss >> a;
+ VERIFY( !ss );
+ ss2 >> a;
+ VERIFY( ss2 );
+ VERIFY( a == 15 );
+ std::strstream ss3 = std::move(ss2);
+ int b;
+ ss2 >> b;
+ VERIFY( !ss2 );
+ ss3 >> b;
+ VERIFY( ss3 );
+ VERIFY( b == 16 );
+}
+
+void
+test07()
+{
+ std::strstream ss;
+ int a;
+ ss >> a;
+ VERIFY( !ss );
+ char buf[] = "17 18";
+ ss = std::strstream(buf, 5, std::ios::in|std::ios::app);
+ ss >> a;
+ VERIFY( ss );
+ VERIFY( a == 17 );
+ ss = std::strstream();
+ int b;
+ ss >> b;
+ VERIFY( !ss );
+}
+
+void
+test08()
+{
+ std::strstream ss;
+ ss << "a few chars"; // fits in initial allocation
+ char* s = ss.str(); // ss now frozen
+ std::strstream ss2 = std::move(ss);
+ VERIFY( ss2.str() == s );
+ VERIFY( ss.str() == nullptr );
+ ss2.freeze(false);
+
+ ss2 << "enough additional chars to force a reallocation";
+ VERIFY( ss2 );
+ s = ss2.str(); // ss2 now frozen
+ std::strstream ss3 = std::move(ss2);
+ VERIFY( ss3.str() == s );
+ VERIFY( ss2.str() == nullptr );
+ delete[] s;
+}
+
+void
+test09()
+{
+ char buf[16];
+ std::strstream ss(buf, sizeof(buf));
+ ss << "a few chars";
+ char* s = ss.str(); // ss now frozen
+ VERIFY( s == buf );
+ std::strstream ss2 = std::move(ss);
+ VERIFY( ss2.str() == s );
+ VERIFY( ss.str() == nullptr );
+ ss2.freeze(false);
+
+ ss2 << "enough additional chars to force a reallocation";
+ VERIFY( !ss2 );
+ s = ss2.str(); // ss2 now frozen
+ VERIFY( s == buf );
+ std::strstream ss3 = std::move(ss2);
+ VERIFY( ss3.str() == s );
+ VERIFY( ss2.str() == nullptr );
+}
+
+void
+test10()
+{
+ char buf[] = "0123456789";
+ std::strstream ss(buf, 1);
+ ss << "aa";
+ VERIFY( !ss );
+ ss = std::strstream(buf, 10);
+ ss << "some chars";
+ VERIFY( ss );
+ VERIFY( ss.pcount() == 10 );
+ ss << "a";
+ VERIFY( !ss );
+ ss = std::strstream();
+ ss << "a";
+ VERIFY( ss );
+ VERIFY( ss.pcount() == 1 );
+ char* s = ss.str(); // ss now frozen
+ ss = std::strstream();
+ ss.freeze(false); // no effect
+ delete[] s;
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+ test05();
+ test05();
+ test06();
+ test07();
+ test08();
+ test09();
+ test10();
+}
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [PATCH] PR libstdc++/69608 Move semantics for strstreambuf
2018-05-02 16:25 [PATCH] PR libstdc++/69608 Move semantics for strstreambuf Jonathan Wakely
@ 2018-05-02 16:27 ` Jonathan Wakely
0 siblings, 0 replies; 2+ messages in thread
From: Jonathan Wakely @ 2018-05-02 16:27 UTC (permalink / raw)
To: libstdc++, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 229 bytes --]
On 02/05/18 17:25 +0100, Jonathan Wakely wrote:
>+int
>+main()
>+{
>+ test01();
>+ test02();
>+ test03();
>+ test04();
>+ test05();
>+ test05();
After committing this I noticed test05() is run twice. Fixed by this
patch.
[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 660 bytes --]
commit 81d3cafc6bd00d44413adca3420f75c52870b1eb
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Wed May 2 17:26:19 2018 +0100
Remove duplicate function call in test
* testsuite/backward/strstream_move.cc: Remove duplicate function
call.
diff --git a/libstdc++-v3/testsuite/backward/strstream_move.cc b/libstdc++-v3/testsuite/backward/strstream_move.cc
index 7dfbd337901..dbe789cbc6f 100644
--- a/libstdc++-v3/testsuite/backward/strstream_move.cc
+++ b/libstdc++-v3/testsuite/backward/strstream_move.cc
@@ -235,7 +235,6 @@ main()
test03();
test04();
test05();
- test05();
test06();
test07();
test08();
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2018-05-02 16:27 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-05-02 16:25 [PATCH] PR libstdc++/69608 Move semantics for strstreambuf Jonathan Wakely
2018-05-02 16:27 ` Jonathan Wakely
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).