Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/2196957/?format=api
{ "id": 2196957, "url": "http://patchwork.ozlabs.org/api/patches/2196957/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/20260216172745.1513917-1-tkaminsk@redhat.com/", "project": { "id": 17, "url": "http://patchwork.ozlabs.org/api/projects/17/?format=api", "name": "GNU Compiler Collection", "link_name": "gcc", "list_id": "gcc-patches.gcc.gnu.org", "list_email": "gcc-patches@gcc.gnu.org", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20260216172745.1513917-1-tkaminsk@redhat.com>", "list_archive_url": null, "date": "2026-02-16T17:26:58", "name": "[committed,v3] libstdc++: Implement rvalue overload for basic_string::substr() [PR119745]", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "c2cdecbdc6e2337c5bef24cf2803c08ba4c55018", "submitter": { "id": 90409, "url": "http://patchwork.ozlabs.org/api/people/90409/?format=api", "name": "Tomasz Kamiński", "email": "tkaminsk@redhat.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/gcc/patch/20260216172745.1513917-1-tkaminsk@redhat.com/mbox/", "series": [ { "id": 492337, "url": "http://patchwork.ozlabs.org/api/series/492337/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/list/?series=492337", "date": "2026-02-16T17:26:58", "name": "[committed,v3] libstdc++: Implement rvalue overload for basic_string::substr() [PR119745]", "version": 3, "mbox": "http://patchwork.ozlabs.org/series/492337/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2196957/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2196957/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "gcc-patches@gcc.gnu.org" ], "Delivered-To": [ "patchwork-incoming@legolas.ozlabs.org", "gcc-patches@gcc.gnu.org" ], "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=MIxZcVFe;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=38.145.34.32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)", "sourceware.org;\n\tdkim=pass (1024-bit key,\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=MIxZcVFe", "sourceware.org; dmarc=pass (p=quarantine dis=none)\n header.from=redhat.com", "sourceware.org; spf=pass smtp.mailfrom=redhat.com", "server2.sourceware.org;\n arc=none smtp.remote-ip=170.10.133.124" ], "Received": [ "from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fF8tC0Jhdz1xtN\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 17 Feb 2026 04:30:10 +1100 (AEDT)", "from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 9EB144BAE7C3\n\tfor <incoming@patchwork.ozlabs.org>; Mon, 16 Feb 2026 17:30:08 +0000 (GMT)", "from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.133.124])\n by sourceware.org (Postfix) with ESMTP id F26464BAE7C4\n for <gcc-patches@gcc.gnu.org>; Mon, 16 Feb 2026 17:27:56 +0000 (GMT)", "from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com\n (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by\n relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3,\n cipher=TLS_AES_256_GCM_SHA384) id us-mta-650-odpvnOk5NY6Ou3sfWwE-1Q-1; Mon,\n 16 Feb 2026 12:27:53 -0500", "from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com\n (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest\n SHA256)\n (No client certificate requested)\n by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS\n id C1702180254B; Mon, 16 Feb 2026 17:27:48 +0000 (UTC)", "from localhost (unknown [10.44.33.164])\n by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP\n id E677330002C7; Mon, 16 Feb 2026 17:27:47 +0000 (UTC)" ], "DKIM-Filter": [ "OpenDKIM Filter v2.11.0 sourceware.org 9EB144BAE7C3", "OpenDKIM Filter v2.11.0 sourceware.org F26464BAE7C4" ], "DMARC-Filter": "OpenDMARC Filter v1.4.2 sourceware.org F26464BAE7C4", "ARC-Filter": "OpenARC Filter v1.0.0 sourceware.org F26464BAE7C4", "ARC-Seal": "i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1771262877; cv=none;\n b=o30uVdo7EfqjfnyEiifVJ/n/7N1cWmApLoOuapb8NMoadFvdcwtArKFAe6+juA/cxOttJ4tiLYzg3LgoCLQyK5fTfbepWZe2sJVWzCAVY00/Zl+PbVq53DsfR4kESl5geRWLRP3OShvekbIHx5lBGmIAbrnDGJGogSwf20u8NjA=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1771262877; c=relaxed/simple;\n bh=bHUx4/batI0bzCmXs7W33iYdtKf1lYwdkLVajXYo93Q=;\n h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version;\n b=Q9SyCcbdVvpRoa97RHb1+YC5mcavQo9cDqF9j2D3ZfYb1a2fpMLWD0SOoalEnz0l7tfd1CSRweKUXydZGtGtmghfGZ0tevVilBnXYoytNhi7lwhhkTTT7ooJVrV6lViY+UCWSYUYGsvVngr87ggJUfQ7+o88ik7BDiBSSBCrjqc=", "ARC-Authentication-Results": "i=1; server2.sourceware.org", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1771262876;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:cc:mime-version:mime-version:content-type:content-type:\n content-transfer-encoding:content-transfer-encoding:\n in-reply-to:in-reply-to:references:references;\n bh=dqNC0HNp/vvMNzzVdWXGlJeYencu2dettal3MvRM40M=;\n b=MIxZcVFeTyEPz0oU21m5Clb7Vx/6PLQrvrpKrMjMoXf8GMWmN57XHbDAJxTkbQsUj18Vbk\n YtJCyKnNxnx2RhweksTVgmJMm7QkvsIfd5ZjuhWbN3O4LEpmlUFr+8synPT03fnmkezBiH\n yqe9Q4Si6puVRfNiC17FADB52knxE0E=", "X-MC-Unique": "odpvnOk5NY6Ou3sfWwE-1Q-1", "X-Mimecast-MFC-AGG-ID": "odpvnOk5NY6Ou3sfWwE-1Q_1771262872", "From": "=?utf-8?q?Tomasz_Kami=C5=84ski?= <tkaminsk@redhat.com>", "To": "libstdc++@gcc.gnu.org,\n\tgcc-patches@gcc.gnu.org", "Cc": "Jonathan Wakely <jwakely@redhat.com>,\n\tPatrick Palka <ppalka@redhat.com>", "Subject": "[committed v3] libstdc++: Implement rvalue overload for\n basic_string::substr() [PR119745]", "Date": "Mon, 16 Feb 2026 18:26:58 +0100", "Message-ID": "<20260216172745.1513917-1-tkaminsk@redhat.com>", "In-Reply-To": "\n <CACb0b4kbP_ioqs9vKdN4ZqU-DW1MvDLdA090VKy_1yiWfN6cdA@mail.gmail.com>", "References": "\n <CACb0b4kbP_ioqs9vKdN4ZqU-DW1MvDLdA090VKy_1yiWfN6cdA@mail.gmail.com>", "MIME-Version": "1.0", "X-Scanned-By": "MIMEDefang 3.4.1 on 10.30.177.4", "X-Mimecast-Spam-Score": "0", "X-Mimecast-MFC-PROC-ID": "BRbRIisGdIDsQqz7Ovz4g8pt5bmFmk-9_C5ILBMtzsw_1771262872", "X-Mimecast-Originator": "redhat.com", "Content-Type": "text/plain; charset=UTF-8", "Content-Transfer-Encoding": "8bit", "X-BeenThere": "gcc-patches@gcc.gnu.org", "X-Mailman-Version": "2.1.30", "Precedence": "list", "List-Id": "Gcc-patches mailing list <gcc-patches.gcc.gnu.org>", "List-Unsubscribe": "<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>", "List-Archive": "<https://gcc.gnu.org/pipermail/gcc-patches/>", "List-Post": "<mailto:gcc-patches@gcc.gnu.org>", "List-Help": "<mailto:gcc-patches-request@gcc.gnu.org?subject=help>", "List-Subscribe": "<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>", "Errors-To": "gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org" }, "content": "This paper implement the changes from P2438R2 basic_string::substr() &&\npaper into C++26. The additional substr and constructor overload are\nimplemented only for SSO string, as they require mutating the content\n(if reused), and thus would require copy of the string anyway for COW\nstrings. (In consequence allocators implicitly constructible from int\nremain ambiguous for C++11 ABI strings, see r16-7497-gfa1149534d8580).\n\nIn addition to cases when the allocators are not compatible (equal),\nthis patch does not reuse (transfer) allocator storage, if the selected\nsubstring fits inside the SSO buffer, so we do not risk keeping large\nchunk of memory for few characters. (This also covers cases when the\nsource stored the content in the local buffer).\n\nAs this additional overloads are meant to be optimization, in contrast\nto move constructor, the source is left unmodified if the allocation\nis not transferred. This avoid introducing a write (of null terminator)\nto previously untouched, heap allocated, memory.\n\nSeparate overloads for substr(size_type __pos, size_type __n) and\nsubstr(size_type __pos == 0), that delegate to corresponding constructor,\nare provided to avoid the check of __n against the length() in the later\ncase.\n\nFinally, the signatures of existing substr() overload are not modified\n(no longer required since C++20), which avoid any impact on the ABI.\n\n\tPR libstdc++/119745\n\nlibstdc++-v3/ChangeLog:\n\n\t* include/bits/basic_string.h (basic_string::_M_construct)\n\t[__cplusplus >= 202302L]: Declare.\n\t(basic_string::basic_string(basic_string&&, size_type, const _Alloc&))\n\t(basic_string(basic_string&&, size_type, size_type, const _Alloc&))\n\t(basic_string::substr(size_type, size_type) &&)\n\t(basic_string::substr(size_type) &&) [__cplusplus >= 202302L]: Define.\n\t* include/bits/basic_string.tcc (basic_string::_M_construct)\n\t[__cplusplus >= 202302L]: Define.\n\t* testsuite/21_strings/basic_string/operations/substr/rvalue.cc: New test.\n\nReviewed-by: Jonathan Wakely <jwakely@redhat.com>\nReviewed-by: Patrick Palka <ppalka@redhat.com>\nSigned-off-by: Tomasz Kamiński <tkaminsk@redhat.com>\n---\nv3:\n- moves // C++23 comments to #endif\n- remove duplicated line in commit description\n\nTested on x86_64-linux. Pushed to trunk.\n\n libstdc++-v3/include/bits/basic_string.h | 37 ++\n libstdc++-v3/include/bits/basic_string.tcc | 32 ++\n .../basic_string/operations/substr/rvalue.cc | 359 ++++++++++++++++++\n 3 files changed, 428 insertions(+)\n create mode 100644 libstdc++-v3/testsuite/21_strings/basic_string/operations/substr/rvalue.cc", "diff": "diff --git a/libstdc++-v3/include/bits/basic_string.h b/libstdc++-v3/include/bits/basic_string.h\nindex cd6f312f1bd..9bbe16507d0 100644\n--- a/libstdc++-v3/include/bits/basic_string.h\n+++ b/libstdc++-v3/include/bits/basic_string.h\n@@ -354,6 +354,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11\n \tvoid\n \t_M_construct(const _CharT *__c, size_type __n);\n \n+#if __cplusplus >= 202302L\n+ constexpr void\n+ _M_construct(basic_string&& __str, size_type __pos, size_type __n);\n+#endif\n+\n _GLIBCXX20_CONSTEXPR\n allocator_type&\n _M_get_allocator()\n@@ -671,6 +676,26 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11\n \t\t std::forward_iterator_tag());\n }\n \n+#if __cplusplus >= 202302L\n+ _GLIBCXX20_CONSTEXPR\n+ basic_string(basic_string&& __str, size_type __pos,\n+\t\t const _Alloc& __a = _Alloc())\n+ : _M_dataplus(_M_local_data(), __a)\n+ {\n+\t__pos = __str._M_check(__pos, \"string::string\");\n+\t_M_construct(std::move(__str), __pos, __str.length() - __pos);\n+ }\n+\n+ _GLIBCXX20_CONSTEXPR\n+ basic_string(basic_string&& __str, size_type __pos, size_type __n,\n+\t\t const _Alloc& __a = _Alloc())\n+ : _M_dataplus(_M_local_data(), __a)\n+ {\n+\t__pos = __str._M_check(__pos, \"string::string\");\n+\t_M_construct(std::move(__str), __pos, __str._M_limit(__pos, __n));\n+ }\n+#endif // C++23\n+\n /**\n * @brief Construct string initialized by a character %array.\n * @param __s Source character %array.\n@@ -3442,6 +3467,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11\n { return basic_string(*this,\n \t\t\t _M_check(__pos, \"basic_string::substr\"), __n); }\n \n+#if __cplusplus >= 202302L\n+ _GLIBCXX_NODISCARD\n+ constexpr basic_string\n+ substr(size_type __pos = 0) &&\n+ { return basic_string(std::move(*this), __pos); }\n+\n+ _GLIBCXX_NODISCARD\n+ constexpr basic_string\n+ substr(size_type __pos, size_type __n) &&\n+ { return basic_string(std::move(*this), __pos, __n); }\n+#endif // C++23\n+\n #ifdef __glibcxx_string_subview // >= C++26\n /**\n * @brief Get a subview.\ndiff --git a/libstdc++-v3/include/bits/basic_string.tcc b/libstdc++-v3/include/bits/basic_string.tcc\nindex 75ffea42ced..a223edf67ac 100644\n--- a/libstdc++-v3/include/bits/basic_string.tcc\n+++ b/libstdc++-v3/include/bits/basic_string.tcc\n@@ -302,6 +302,38 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n \ttraits_type::assign(_M_data()[__n], _CharT());\n }\n \n+#if __cplusplus >= 202302L\n+ template<typename _CharT, typename _Traits, typename _Alloc>\n+ constexpr void\n+ basic_string<_CharT, _Traits, _Alloc>::\n+ _M_construct(basic_string&& __str, size_type __pos, size_type __n)\n+ {\n+ const _CharT* __start = __str._M_data() + __pos;\n+ if (__n <= _S_local_capacity)\n+\t{\n+\t _M_init_local_buf();\n+\t traits_type::copy(_M_local_buf, __start, __n);\n+\t _M_set_length(__n);\n+\t return;\n+\t}\n+\n+ if constexpr (!allocator_traits<_Alloc>::is_always_equal::value)\n+\tif (get_allocator() != __str.get_allocator())\n+\t {\n+\t _M_construct<false>(__start, __n);\n+\t return;\n+\t }\n+\n+ _M_data(__str._M_data());\n+ _M_capacity(__str._M_allocated_capacity);\n+ __str._M_data(__str._M_use_local_data());\n+ __str._M_set_length(0);\n+\n+ _S_move(_M_data(), _M_data() + __pos, __n);\n+ _M_set_length(__n);\n+ }\n+#endif // C++23\n+\n template<typename _CharT, typename _Traits, typename _Alloc>\n _GLIBCXX20_CONSTEXPR\n void\ndiff --git a/libstdc++-v3/testsuite/21_strings/basic_string/operations/substr/rvalue.cc b/libstdc++-v3/testsuite/21_strings/basic_string/operations/substr/rvalue.cc\nnew file mode 100644\nindex 00000000000..70ccea6f06f\n--- /dev/null\n+++ b/libstdc++-v3/testsuite/21_strings/basic_string/operations/substr/rvalue.cc\n@@ -0,0 +1,359 @@\n+// { dg-do run { target c++26 } }\n+\n+#include <string_view>\n+#include <testsuite_hooks.h>\n+#include <testsuite_allocator.h>\n+\n+// When selection is short enough to fit into SSO, the rhs\n+// is left unchanged.\n+template<typename CharT, typename Allocator>\n+constexpr void\n+do_test_short_in(const CharT* cstr, Allocator alloc)\n+{\n+ using StringView = std::basic_string_view<CharT>;\n+ using String = std::basic_string<CharT, std::char_traits<CharT>, Allocator>;\n+\n+ const Allocator defAlloc;\n+ String src, res;\n+\n+ // substr(0)\n+ src = String(cstr, alloc);\n+ res = std::move(src).substr(0);\n+ VERIFY( res == StringView(cstr).substr(0) );\n+ VERIFY( res.get_allocator() == defAlloc );\n+ VERIFY( src == cstr );\n+\n+ src = String(cstr, alloc);\n+ String res1(std::move(src), 0);\n+ VERIFY( res1 == StringView(cstr).substr(0) );\n+ VERIFY( res1.get_allocator() == defAlloc );\n+ VERIFY( src == cstr );\n+\n+ src = String(cstr, alloc);\n+ String res2(std::move(src), 0, alloc);\n+ VERIFY( res2 == StringView(cstr).substr(0) );\n+ VERIFY( res2.get_allocator() == alloc );\n+ VERIFY( src == cstr );\n+\n+ // substr(1)\n+ src = String(cstr, alloc);\n+ res = std::move(src).substr(1);\n+ VERIFY( res == StringView(cstr).substr(1) );\n+ VERIFY( res.get_allocator() == defAlloc );\n+ VERIFY( src == cstr );\n+\n+ src = String(cstr, alloc);\n+ String res3(std::move(src), 1);\n+ VERIFY( res3 == StringView(cstr).substr(1) );\n+ VERIFY( res3.get_allocator() == defAlloc );\n+ VERIFY( src == cstr );\n+\n+ src = String(cstr, alloc);\n+ String res4(std::move(src), 1, alloc);\n+ VERIFY( res4 == StringView(cstr).substr(1) );\n+ VERIFY( res4.get_allocator() == alloc );\n+ VERIFY( src == cstr );\n+\n+ // substr(1, 1000)\n+ src = String(cstr, alloc);\n+ res = std::move(src).substr(1, 1000);\n+ VERIFY( res == StringView(cstr).substr(1, 1000) );\n+ VERIFY( res.get_allocator() == defAlloc );\n+ VERIFY( src == cstr );\n+\n+ src = String(cstr, alloc);\n+ String res5(std::move(src), 1, 1000);\n+ VERIFY( res5 == StringView(cstr).substr(1, 1000) );\n+ VERIFY( res5.get_allocator() == defAlloc );\n+ VERIFY( src == cstr );\n+\n+ src = String(cstr, alloc);\n+ String res6(std::move(src), 1, 1000, alloc);\n+ VERIFY( res6 == StringView(cstr).substr(1, 1000) );\n+ VERIFY( res6.get_allocator() == alloc );\n+ VERIFY( src == cstr );\n+}\n+\n+template<typename CharT, typename Allocator>\n+constexpr void\n+do_test_short_sel(const CharT* cstr, Allocator alloc)\n+{\n+ using StringView = std::basic_string_view<CharT>;\n+ using String = std::basic_string<CharT, std::char_traits<CharT>, Allocator>;\n+\n+ const Allocator defAlloc;\n+ String src, res;\n+\n+ // substr(0, 2)\n+ src = String(cstr, alloc);\n+ res = std::move(src).substr(0, 2);\n+ VERIFY( res == StringView(cstr).substr(0, 2) );\n+ VERIFY( res.get_allocator() == defAlloc );\n+ VERIFY( src == cstr );\n+\n+ src = String(cstr, alloc);\n+ String res1(std::move(src), 0, 2);\n+ VERIFY( res1 == StringView(cstr).substr(0, 2) );\n+ VERIFY( res1.get_allocator() == defAlloc );\n+ VERIFY( src == cstr );\n+\n+ src = String(cstr, alloc);\n+ String res2(std::move(src), 0, 2, alloc);\n+ VERIFY( res2 == StringView(cstr).substr(0, 2) );\n+ VERIFY( res2.get_allocator() == alloc );\n+ VERIFY( src == cstr );\n+\n+ // substr(1, 2)\n+ src = String(cstr, alloc);\n+ res = std::move(src).substr(1, 2);\n+ VERIFY( res == StringView(cstr).substr(1, 2) );\n+ VERIFY( res.get_allocator() == defAlloc );\n+ VERIFY( src == cstr );\n+\n+ src = String(cstr, alloc);\n+ String res3(std::move(src), 1, 2);\n+ VERIFY( res3 == StringView(cstr).substr(1, 2) );\n+ VERIFY( res3.get_allocator() == defAlloc );\n+ VERIFY( src == cstr );\n+\n+ src = String(cstr, alloc);\n+ String res4(std::move(src), 1, 2, alloc);\n+ VERIFY( res4 == StringView(cstr).substr(1, 2) );\n+ VERIFY( res4.get_allocator() == alloc );\n+ VERIFY( src == cstr );\n+\n+ // libstdc++ specific\n+ constexpr int max_short = (sizeof(CharT) == 1) ? 15 : 3;\n+ // substr(0, max_short)\n+ src = String(cstr, alloc);\n+ res = std::move(src).substr(0, max_short);\n+ VERIFY( res == StringView(cstr).substr(0, max_short) );\n+ VERIFY( res.get_allocator() == defAlloc );\n+ VERIFY( src == cstr );\n+\n+ src = String(cstr, alloc);\n+ String res5(std::move(src), 0, max_short);\n+ VERIFY( res5 == StringView(cstr).substr(0, max_short) );\n+ VERIFY( res5.get_allocator() == defAlloc );\n+ VERIFY( src == cstr );\n+\n+ src = String(cstr, alloc);\n+ String res6(std::move(src), 0, max_short, alloc);\n+ VERIFY( res6 == StringView(cstr).substr(0, max_short) );\n+ VERIFY( res6.get_allocator() == alloc );\n+ VERIFY( src == cstr );\n+}\n+\n+// If the selection is long enough to do not fit into SSO,\n+// the memory is moved if allocators are compatible.\n+template<typename CharT, typename Allocator>\n+constexpr void\n+do_test_long(const CharT* cstr, Allocator alloc)\n+{\n+ using StringView = std::basic_string_view<CharT>;\n+ using String = std::basic_string<CharT, std::char_traits<CharT>, Allocator>;\n+\n+ const Allocator defAlloc;\n+ String src, res;\n+ const CharT* data;\n+\n+ auto verifyMove = [&](const String& str)\n+ {\n+ // Only SSO string provide rvalue overloads of\n+ // substr and corresponding constructor.\n+#if _GLIBCXX_USE_CXX11_ABI || !_GLIBCXX_USE_DUAL_ABI\n+ if (str.get_allocator() == alloc) {\n+ VERIFY( str.data() == data );\n+ VERIFY( src.empty() );\n+ } else\n+#endif\n+ VERIFY( src == cstr );\n+ };\n+\n+ // substr(0)\n+ src = String(cstr, alloc);\n+ data = src.data();\n+ res = std::move(src).substr(0);\n+ VERIFY( res == StringView(cstr).substr(0) );\n+ VERIFY( res.get_allocator() == defAlloc );\n+ verifyMove(res);\n+\n+ src = String(cstr, alloc);\n+ data = src.data();\n+ String res1(std::move(src), 0);\n+ VERIFY( res1 == StringView(cstr).substr(0) );\n+ VERIFY( res1.get_allocator() == defAlloc );\n+ verifyMove(res1);\n+\n+ src = String(cstr, alloc);\n+ data = src.data();\n+ String res2(std::move(src), 0, alloc);\n+ VERIFY( res2 == StringView(cstr).substr(0) );\n+ VERIFY( res2.get_allocator() == alloc );\n+ verifyMove(res2);\n+\n+ // substr(5)\n+ src = String(cstr, alloc);\n+ data = src.data();\n+ res = std::move(src).substr(5);\n+ VERIFY( res == StringView(cstr).substr(5) );\n+ VERIFY( res.get_allocator() == defAlloc );\n+ verifyMove(res);\n+\n+ src = String(cstr, alloc);\n+ data = src.data();\n+ String res3(std::move(src), 5);\n+ VERIFY( res3 == StringView(cstr).substr(5) );\n+ VERIFY( res3.get_allocator() == defAlloc );\n+ verifyMove(res3);\n+\n+ src = String(cstr, alloc);\n+ data = src.data();\n+ String res4(std::move(src), 5, alloc);\n+ VERIFY( res4 == StringView(cstr).substr(5) );\n+ verifyMove(res4);\n+\n+ // substr(0, 50)\n+ src = String(cstr, alloc);\n+ data = src.data();\n+ res = std::move(src).substr(0, 50);\n+ VERIFY( res == StringView(cstr).substr(0, 50) );\n+ VERIFY( res.get_allocator() == defAlloc );\n+ verifyMove(res);\n+\n+ src = String(cstr, alloc);\n+ data = src.data();\n+ String res5(std::move(src), 0, 50);\n+ VERIFY( res5 == StringView(cstr).substr(0, 50) );\n+ VERIFY( res5.get_allocator() == defAlloc );\n+ verifyMove(res5);\n+\n+ src = String(cstr, alloc);\n+ data = src.data();\n+ String res6(std::move(src), 0, 50, alloc);\n+ VERIFY( res6 == StringView(cstr).substr(0, 50) );\n+ VERIFY( res6.get_allocator() == alloc );\n+ verifyMove(res6);\n+\n+ // substr(5, 50)\n+ src = String(cstr, alloc);\n+ data = src.data();\n+ res = std::move(src).substr(5, 50);\n+ VERIFY( res == StringView(cstr).substr(5, 50) );\n+ VERIFY( res.get_allocator() == defAlloc );\n+ verifyMove(res);\n+\n+ src = String(cstr, alloc);\n+ data = src.data();\n+ String res7(std::move(src), 5, 50);\n+ VERIFY( res7 == StringView(cstr).substr(5, 50) );\n+ VERIFY( res7.get_allocator() == defAlloc );\n+ verifyMove(res7);\n+\n+ src = String(cstr, alloc);\n+ data = src.data();\n+ String res8(std::move(src), 5, 50, alloc);\n+ VERIFY( res8 == StringView(cstr).substr(5, 50) );\n+ VERIFY( res8.get_allocator() == alloc );\n+ verifyMove(res8);\n+\n+ // substr(5, 100)\n+ src = String(cstr, alloc);\n+ data = src.data();\n+ res = std::move(src).substr(5, 1000);\n+ VERIFY( res == StringView(cstr).substr(5, 1000) );\n+ VERIFY( res.get_allocator() == defAlloc );\n+ verifyMove(res);\n+\n+ src = String(cstr, alloc);\n+ data = src.data();\n+ String res9(std::move(src), 5, 1000);\n+ VERIFY( res9 == StringView(cstr).substr(5, 1000) );\n+ VERIFY( res9.get_allocator() == defAlloc );\n+ verifyMove(res9);\n+\n+ src = String(cstr, alloc);\n+ data = src.data();\n+ String res10(std::move(src), 5, 1000, alloc);\n+ VERIFY( res10 == StringView(cstr).substr(5, 1000) );\n+ VERIFY( res10.get_allocator() == alloc );\n+ verifyMove(res10);\n+}\n+\n+template<typename CharT, typename Allocator>\n+constexpr void\n+do_test_alloc(const CharT* sht, const CharT* lng, Allocator alloc)\n+{\n+ do_test_short_in(sht, alloc);\n+ do_test_short_sel(sht, alloc);\n+ do_test_short_sel(lng, alloc);\n+ do_test_long(lng, alloc);\n+}\n+\n+template<typename CharT>\n+constexpr void\n+do_test_bounds(const CharT* cstr)\n+{\n+ using String = std::basic_string<CharT>;\n+ try\n+ {\n+ auto res = String(cstr).substr(30);\n+ VERIFY(false);\n+ } catch (const std::out_of_range&) {\n+ VERIFY(true);\n+ }\n+\n+ try\n+ {\n+ auto res = String(cstr).substr(30, 20);\n+ VERIFY(false);\n+ } catch (const std::out_of_range&) {\n+ VERIFY(true);\n+ }\n+\n+ try\n+ {\n+ String res(String(cstr), 30);\n+ VERIFY(false);\n+ } catch (const std::out_of_range&) {\n+ VERIFY(true);\n+ }\n+\n+ try\n+ {\n+ String res(String(cstr), 30, 20);\n+ VERIFY(false);\n+ } catch (const std::out_of_range&) {\n+ VERIFY(true);\n+ }\n+}\n+\n+template<typename CharT>\n+constexpr void\n+do_test(const CharT* sht, const CharT* lng)\n+{\n+ do_test_alloc(sht, lng, std::allocator<CharT>());\n+ if ! consteval {\n+ do_test_alloc(sht, lng, __gnu_test::uneq_allocator<CharT>());\n+ do_test_alloc(sht, lng, __gnu_test::uneq_allocator<CharT>(42));\n+ do_test_bounds(sht);\n+ }\n+}\n+\n+constexpr bool\n+test_all()\n+{\n+ do_test(\n+ \"abcdefghijklmop\",\n+ \"some very very long string, that will not use SSO, and have at least fifty characters\");\n+ do_test(\n+ L\"abc\", \n+ L\"some very very long string, that will not use SSO, and have at least fifty characters\");\n+\n+ return true;\n+}\n+\n+int main()\n+{ \n+ test_all();\n+}\n", "prefixes": [ "committed", "v3" ] }