From patchwork Tue Jun 3 21:32:35 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 355660 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org 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 2F98514009C for ; Wed, 4 Jun 2014 07:33:14 +1000 (EST) 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=VmWEy9u/a5n1gVDoNX9GzAviaf6HhulSeZ6rSas028jApRT/7l+Ko XJghFnpcUo5Cp8N54ERSSCfbvGKFnjt+rJgGGSoSuCUDANYcn1sHmKWLnqqWPzIX 2cY/c2Rhm0wWlTjlD1SCc2/JQWnBq2Fo6o1IhmqyrermHX7fM/I3GU= 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=e4Lx2q0DPDrBr/gvmdW3ivXDiW4=; b=vJMrJEl1kdU5K3VmUje1 +aLc4cyg64RQ8YT9gPwurpN4w5GWdCwYTCfUOg6zsrNxFGSHrfLu7fBnvBpy/uba LzYVUTXOY4ArZ3tp5t84O/pVPdDw0GpkgMVqTRX9V5NehISH5UMlGL90w9r88IXd rhw+bH8BphIARX3zUijwIO8= Received: (qmail 3669 invoked by alias); 3 Jun 2014 21:33:07 -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 3648 invoked by uid 89); 3 Jun 2014 21:33:06 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.4 required=5.0 tests=AWL, BAYES_00, RP_MATCHES_RCVD, SPF_HELO_PASS, SPF_PASS autolearn=ham version=3.3.2 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; Tue, 03 Jun 2014 21:32:37 +0000 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id s53LWaTs003303 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 3 Jun 2014 17:32:36 -0400 Received: from localhost (vpn1-6-129.ams2.redhat.com [10.36.6.129]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id s53LWZm9031427; Tue, 3 Jun 2014 17:32:36 -0400 Date: Tue, 3 Jun 2014 22:32:35 +0100 From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [patch] libstdc++/56166 avoid allocation in basic_string::clear() Message-ID: <20140603213235.GX6953@redhat.com> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.23 (2014-03-12) Instead of cloning the string and then setting its length to zero, just point to the empty rep instead. I'm not sure if this is conforming in C++03, because it modifies the capacity(), whereas clear() is specified as if it called erase(begin(), end()), which typically wouldn't alter the capacity (but I'm not sure whether it's allowed to alter it). It passes all tests, but I'm not planning to commit it. commit 83de17363e8978c4ee6af499aaab9e3734863449 Author: Jonathan Wakely Date: Tue Jun 3 20:23:10 2014 +0100 PR libstdc++/56166 * include/bits/basic_string.h (basic_string::clear()): Drop reference and use empty rep. * include/ext/rc_string_base.h (__rc_string_base::_M_clear()): Likewise. * testsuite/21_strings/basic_string/56166.cc: New. * testsuite/ext/vstring/modifiers/clear/56166.cc: New. diff --git a/libstdc++-v3/include/bits/basic_string.h b/libstdc++-v3/include/bits/basic_string.h index cd60376..420ead5 100644 --- a/libstdc++-v3/include/bits/basic_string.h +++ b/libstdc++-v3/include/bits/basic_string.h @@ -808,10 +808,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /** * Erases the string, making it empty. */ +#if _GLIBCXX_FULLY_DYNAMIC_STRING == 0 + void + clear() _GLIBCXX_NOEXCEPT + { + _M_rep()->_M_dispose(this->get_allocator()); + _M_data(_S_empty_rep()._M_refdata()); + } +#else // PR 56166: this should not throw. void clear() { _M_mutate(0, this->size(), 0); } +#endif /** * Returns true if the %string is empty. Equivalent to diff --git a/libstdc++-v3/include/ext/rc_string_base.h b/libstdc++-v3/include/ext/rc_string_base.h index 4c72407..e9df075 100644 --- a/libstdc++-v3/include/ext/rc_string_base.h +++ b/libstdc++-v3/include/ext/rc_string_base.h @@ -354,7 +354,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION void _M_clear() - { _M_erase(size_type(0), _M_length()); } + { + _M_dispose(); + _M_data(_S_empty_rep._M_refcopy()); + } bool _M_compare(const __rc_string_base&) const diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/56166.cc b/libstdc++-v3/testsuite/21_strings/basic_string/56166.cc new file mode 100644 index 0000000..b680afa --- /dev/null +++ b/libstdc++-v3/testsuite/21_strings/basic_string/56166.cc @@ -0,0 +1,90 @@ +// Copyright (C) 2014 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 " -std=gnu++11 " } + +// libstdc++/56166 + +#include +#include + +static int fail_after = -1; + +template + struct Allocator + { + using value_type = T; + + // shouldn't need these typedefs, but doesn't use allocator_traits + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using difference_type = long; + using size_type = unsigned long; + template + struct rebind { + using other = Allocator; + }; + + Allocator() { } + + template + Allocator(const Allocator&) { } + + T* allocate(size_type n) + { + if (fail_after >= 0) { + if (fail_after-- == 0) { + throw std::bad_alloc(); + } + } + return (T*)new char[n * sizeof(T)]; + } + + void deallocate(T* p, size_type) + { + delete[] (char*)p; + } + }; + +template + bool operator==(const Allocator&, const Allocator&) { return true; } +template + bool operator!=(const Allocator&, const Allocator&) { return false; } + +using string = std::basic_string, Allocator>; + +string f() +{ + string s1("xxxxxx"); + string s2 = s1; + s1.clear(); + return s2; +} + +int main() +{ + for (int i = 0; i < 10; i++) { + try { + fail_after = i; + f(); + break; + } catch (std::bad_alloc) { + } + } +} diff --git a/libstdc++-v3/testsuite/ext/vstring/modifiers/clear/56166.cc b/libstdc++-v3/testsuite/ext/vstring/modifiers/clear/56166.cc new file mode 100644 index 0000000..0217023 --- /dev/null +++ b/libstdc++-v3/testsuite/ext/vstring/modifiers/clear/56166.cc @@ -0,0 +1,93 @@ +// Copyright (C) 2014 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 " -std=gnu++11 " } + +// libstdc++/56166 + +#include +#include + +static int fail_after = -1; + +template + struct Allocator + { + using value_type = T; + + // shouldn't need these typedefs, but doesn't use allocator_traits + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using difference_type = long; + using size_type = unsigned long; + template + struct rebind { + using other = Allocator; + }; + + Allocator() { } + + template + Allocator(const Allocator&) { } + + T* allocate(size_type n) + { + if (fail_after >= 0) { + if (fail_after-- == 0) { + throw std::bad_alloc(); + } + } + return (T*)new char[n * sizeof(T)]; + } + + void deallocate(T* p, size_type) + { + delete[] (char*)p; + } + }; + +template + bool operator==(const Allocator&, const Allocator&) { return true; } +template + bool operator!=(const Allocator&, const Allocator&) { return false; } + + +using string = __gnu_cxx::__versa_string, + Allocator, + __gnu_cxx::__rc_string_base>; + +string f() +{ + string s1("xxxxxx"); + string s2 = s1; + s1.clear(); + return s2; +} + +int main() +{ + for (int i = 0; i < 10; i++) { + try { + fail_after = i; + f(); + break; + } catch (std::bad_alloc) { + } + } +}