From patchwork Wed May 2 16:25:35 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 907621 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-477122-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="J2zOMHD/"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 40bkD65qfDz9ry1 for ; Thu, 3 May 2018 02:25:56 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=ws4WDpQcyH4xqsN534KDxjnhQVefVv5H83ZVCTc/57KjxaLdQDrtG Yl1trYjiew41Zjigry3uwOuTKBPqh5rXNi0hQ+erxMdPN+LSGsdfjiWlS7QocpTd NJRvOT/ukTMGUgw2GvQXaxi360IFYzyIMPrVdbP3wnUmRPt2/fNMmA= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=Gt1YdDLFEI3VAqCNnNmjjCrQMp8=; b=J2zOMHD/AKaiC9e0Q3T/ D9INkRw2/G+hpDsviuhvyObzzgEOFxU3qLXG/99EG2v3rDn+pTxiCP2DVqbBS69m nDVIzvRfZ43Xaw0wz7Su+0d7J0Zggn1WyILqKVoXOxhLkJH1sf+iyajjmk7qLbLd ZyJ5XKlG2vderJGl+5+3fU0= Received: (qmail 104349 invoked by alias); 2 May 2018 16:25:41 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 104330 invoked by uid 89); 2 May 2018 16:25:40 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=ss, 1107, fits, streams X-Spam-User: qpsmtpd, 2 recipients X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 02 May 2018 16:25:38 +0000 Received: from smtp.corp.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.26]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 14FEE300441B; Wed, 2 May 2018 16:25:37 +0000 (UTC) Received: from localhost (unknown [10.33.36.9]) by smtp.corp.redhat.com (Postfix) with ESMTP id B6D8330012A2; Wed, 2 May 2018 16:25:36 +0000 (UTC) Date: Wed, 2 May 2018 17:25:35 +0100 From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [PATCH] PR libstdc++/69608 Move semantics for strstreambuf Message-ID: <20180502162535.GA22893@redhat.com> MIME-Version: 1.0 Content-Disposition: inline X-Clacks-Overhead: GNU Terry Pratchett User-Agent: Mutt/1.9.1 (2017-09-22) 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. commit 323f52cd6604c661dd07b8fbc79e10f1ae778255 Author: Jonathan Wakely 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(__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 +// . + +// { dg-options "-Wno-deprecated" } +// { dg-do run { target c++11 } } + +#include +#include + +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(); +}