From 620b41e4a042b1ae24af12aceeae197a04d45183 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Thu, 18 Jul 2024 13:26:37 +0300 Subject: [PATCH] [libc++][strings] P2591R5: Concatenation of strings and string views (#88389) Summary: Implemented: https://wg21.link/P2591R5 - https://eel.is/c++draft/string.syn - https://eel.is/c++draft/string.op.plus --------- Co-authored-by: Hristo Hristov Test Plan: Reviewers: Subscribers: Tasks: Tags: Differential Revision: https://phabricator.intern.facebook.com/D60250903 --- libcxx/docs/FeatureTestMacroTable.rst | 2 + libcxx/docs/ReleaseNotes/19.rst | 1 + libcxx/docs/Status/Cxx2cPapers.csv | 2 +- libcxx/include/string | 98 ++++++++ libcxx/include/version | 5 +- .../string.version.compile.pass.cpp | 5 +- .../string_view.version.compile.pass.cpp | 5 +- .../version.version.compile.pass.cpp | 5 +- .../string_op+/string.string_view.pass.cpp | 216 ++++++++++++++++++ .../generate_feature_test_macro_components.py | 2 +- 10 files changed, 332 insertions(+), 9 deletions(-) create mode 100644 libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst index 1e347d043ef692..53cfc3739d2be6 100644 --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -474,6 +474,8 @@ Status ---------------------------------------------------------- ----------------- ``__cpp_lib_sstream_from_string_view`` ``202306L`` ---------------------------------------------------------- ----------------- + ``__cpp_lib_string_view`` ``202403L`` + ---------------------------------------------------------- ----------------- ``__cpp_lib_submdspan`` *unimplemented* ---------------------------------------------------------- ----------------- ``__cpp_lib_text_encoding`` *unimplemented* diff --git a/libcxx/docs/ReleaseNotes/19.rst b/libcxx/docs/ReleaseNotes/19.rst index 80b9e18cec901c..80f43256f1270c 100644 --- a/libcxx/docs/ReleaseNotes/19.rst +++ b/libcxx/docs/ReleaseNotes/19.rst @@ -46,6 +46,7 @@ Implemented Papers - P2872R3 - Remove ``wstring_convert`` From C++26 - P3142R0 - Printing Blank Lines with ``println`` (as DR against C++23) - P2944R3 - Comparisons for ``reference_wrapper`` (comparison operators for ``reference_wrapper`` only) +- P2591R5 - Concatenation of strings and string views - P2968R2 - Make ``std::ignore`` a first-class object - P2302R4 - ``std::ranges::contains`` - P1659R3 - ``std::ranges::starts_with`` and ``std::ranges::ends_with`` diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv index 2c498f336b125f..968d82a973a79a 100644 --- a/libcxx/docs/Status/Cxx2cPapers.csv +++ b/libcxx/docs/Status/Cxx2cPapers.csv @@ -55,7 +55,7 @@ "`P2845R8 `__","LWG","Formatting of ``std::filesystem::path``","Tokyo March 2024","","","|format|" "`P0493R5 `__","LWG","Atomic minimum/maximum","Tokyo March 2024","","","" "`P2542R8 `__","LWG","``views::concat``","Tokyo March 2024","","","|ranges|" -"`P2591R5 `__","LWG","Concatenation of strings and string views","Tokyo March 2024","","","" +"`P2591R5 `__","LWG","Concatenation of strings and string views","Tokyo March 2024","|Complete|","19.0","" "`P2248R8 `__","LWG","Enabling list-initialization for algorithms","Tokyo March 2024","","","" "`P2810R4 `__","LWG","``is_debugger_present`` ``is_replaceable``","Tokyo March 2024","","","" "`P1068R11 `__","LWG","Vector API for random number generation","Tokyo March 2024","","","" diff --git a/libcxx/include/string b/libcxx/include/string index 9a52ab6aef41e8..90394e9edbe83c 100644 --- a/libcxx/include/string +++ b/libcxx/include/string @@ -407,6 +407,24 @@ template basic_string operator+(const basic_string& lhs, charT rhs); // constexpr since C++20 +template + constexpr basic_string + operator+(const basic_string& lhs, + type_identity_t> rhs); // Since C++26 +template + constexpr basic_string + operator+(basic_string&& lhs, + type_identity_t> rhs); // Since C++26 +template + constexpr basic_string + operator+(type_identity_t> lhs, + const basic_string& rhs); // Since C++26 +template + constexpr basic_string + operator+(type_identity_t> lhs, + basic_string&& rhs); // Since C++26 + + template bool operator==(const basic_string& lhs, const basic_string& rhs) noexcept; // constexpr since C++20 @@ -687,6 +705,28 @@ template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string<_CharT, _Traits, _Allocator> operator+(const basic_string<_CharT, _Traits, _Allocator>& __x, _CharT __y); +#if _LIBCPP_STD_VER >= 26 + +template +_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator> +operator+(const basic_string<_CharT, _Traits, _Allocator>& __lhs, + type_identity_t> __rhs); + +template +_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator> +operator+(basic_string<_CharT, _Traits, _Allocator>&& __lhs, type_identity_t> __rhs); + +template +_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator> +operator+(type_identity_t> __lhs, + const basic_string<_CharT, _Traits, _Allocator>& __rhs); + +template +_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator> +operator+(type_identity_t> __lhs, basic_string<_CharT, _Traits, _Allocator>&& __rhs); + +#endif + extern template _LIBCPP_EXPORTED_FROM_ABI string operator+ , allocator >(char const*, string const&); @@ -2150,6 +2190,10 @@ private: friend _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string operator+ <>(value_type, const basic_string&); friend _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string operator+ <>(const basic_string&, const value_type*); friend _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string operator+ <>(const basic_string&, value_type); +#if _LIBCPP_STD_VER >= 26 + friend constexpr basic_string operator+ <>(const basic_string&, type_identity_t<__self_view>); + friend constexpr basic_string operator+ <>(type_identity_t<__self_view>, const basic_string&); +#endif }; // These declarations must appear before any functions are implicitly used @@ -4007,6 +4051,60 @@ operator+(basic_string<_CharT, _Traits, _Allocator>&& __lhs, _CharT __rhs) { #endif // _LIBCPP_CXX03_LANG +#if _LIBCPP_STD_VER >= 26 + +template +_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator> +operator+(const basic_string<_CharT, _Traits, _Allocator>& __lhs, + type_identity_t> __rhs) { + using _String = basic_string<_CharT, _Traits, _Allocator>; + typename _String::size_type __lhs_sz = __lhs.size(); + typename _String::size_type __rhs_sz = __rhs.size(); + _String __r(__uninitialized_size_tag(), + __lhs_sz + __rhs_sz, + _String::__alloc_traits::select_on_container_copy_construction(__lhs.get_allocator())); + auto __ptr = std::__to_address(__r.__get_pointer()); + _Traits::copy(__ptr, __lhs.data(), __lhs_sz); + _Traits::copy(__ptr + __lhs_sz, __rhs.data(), __rhs_sz); + _Traits::assign(__ptr + __lhs_sz + __rhs_sz, 1, _CharT()); + return __r; +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator> +operator+(basic_string<_CharT, _Traits, _Allocator>&& __lhs, + type_identity_t> __rhs) { + __lhs.append(__rhs); + return std::move(__lhs); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator> +operator+(type_identity_t> __lhs, + const basic_string<_CharT, _Traits, _Allocator>& __rhs) { + using _String = basic_string<_CharT, _Traits, _Allocator>; + typename _String::size_type __lhs_sz = __lhs.size(); + typename _String::size_type __rhs_sz = __rhs.size(); + _String __r(__uninitialized_size_tag(), + __lhs_sz + __rhs_sz, + _String::__alloc_traits::select_on_container_copy_construction(__rhs.get_allocator())); + auto __ptr = std::__to_address(__r.__get_pointer()); + _Traits::copy(__ptr, __lhs.data(), __lhs_sz); + _Traits::copy(__ptr + __lhs_sz, __rhs.data(), __rhs_sz); + _Traits::assign(__ptr + __lhs_sz + __rhs_sz, 1, _CharT()); + return __r; +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator> +operator+(type_identity_t> __lhs, + basic_string<_CharT, _Traits, _Allocator>&& __rhs) { + __rhs.insert(0, __lhs); + return std::move(__rhs); +} + +#endif // _LIBCPP_STD_VER >= 26 + // swap template diff --git a/libcxx/include/version b/libcxx/include/version index c971336bcb85ce..7d9fad1cb1eb2a 100644 --- a/libcxx/include/version +++ b/libcxx/include/version @@ -231,7 +231,8 @@ __cpp_lib_stdatomic_h 202011L __cpp_lib_string_contains 202011L __cpp_lib_string_resize_and_overwrite 202110L __cpp_lib_string_udls 201304L -__cpp_lib_string_view 201803L +__cpp_lib_string_view 202403L + 201803L // C++20 201606L // C++17 __cpp_lib_submdspan 202306L __cpp_lib_syncbuf 201803L @@ -547,6 +548,8 @@ __cpp_lib_void_t 201411L # define __cpp_lib_span_at 202311L # define __cpp_lib_span_initializer_list 202311L # define __cpp_lib_sstream_from_string_view 202306L +# undef __cpp_lib_string_view +# define __cpp_lib_string_view 202403L // # define __cpp_lib_submdspan 202306L // # define __cpp_lib_text_encoding 202306L # undef __cpp_lib_to_chars diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/string.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/string.version.compile.pass.cpp index af6386a40a458a..69a938edd1cb92 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/string.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/string.version.compile.pass.cpp @@ -29,6 +29,7 @@ __cpp_lib_string_udls 201304L [C++14] __cpp_lib_string_view 201606L [C++17] 201803L [C++20] + 202403L [C++26] __cpp_lib_to_string 202306L [C++26] */ @@ -483,8 +484,8 @@ # ifndef __cpp_lib_string_view # error "__cpp_lib_string_view should be defined in c++26" # endif -# if __cpp_lib_string_view != 201803L -# error "__cpp_lib_string_view should have the value 201803L in c++26" +# if __cpp_lib_string_view != 202403L +# error "__cpp_lib_string_view should have the value 202403L in c++26" # endif # if !defined(_LIBCPP_VERSION) diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/string_view.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/string_view.version.compile.pass.cpp index a86ab2adff6a93..f3c70cf9779737 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/string_view.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/string_view.version.compile.pass.cpp @@ -23,6 +23,7 @@ __cpp_lib_string_contains 202011L [C++23] __cpp_lib_string_view 201606L [C++17] 201803L [C++20] + 202403L [C++26] */ #include @@ -252,8 +253,8 @@ # ifndef __cpp_lib_string_view # error "__cpp_lib_string_view should be defined in c++26" # endif -# if __cpp_lib_string_view != 201803L -# error "__cpp_lib_string_view should have the value 201803L in c++26" +# if __cpp_lib_string_view != 202403L +# error "__cpp_lib_string_view should have the value 202403L in c++26" # endif #endif // TEST_STD_VER > 23 diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp index a01ee702a51723..e1af3061725df5 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp @@ -216,6 +216,7 @@ __cpp_lib_string_udls 201304L [C++14] __cpp_lib_string_view 201606L [C++17] 201803L [C++20] + 202403L [C++26] __cpp_lib_submdspan 202306L [C++26] __cpp_lib_syncbuf 201803L [C++20] __cpp_lib_text_encoding 202306L [C++26] @@ -7894,8 +7895,8 @@ # ifndef __cpp_lib_string_view # error "__cpp_lib_string_view should be defined in c++26" # endif -# if __cpp_lib_string_view != 201803L -# error "__cpp_lib_string_view should have the value 201803L in c++26" +# if __cpp_lib_string_view != 202403L +# error "__cpp_lib_string_view should have the value 202403L in c++26" # endif # if !defined(_LIBCPP_VERSION) diff --git a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp new file mode 100644 index 00000000000000..3d981e8b3a3cd7 --- /dev/null +++ b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp @@ -0,0 +1,216 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 + +// + +// [string.op.plus] +// +// template +// constexpr basic_string +// operator+(const basic_string& lhs, +// type_identity_t> rhs); // Since C++26 +// template +// constexpr basic_string +// operator+(basic_string&& lhs, +// type_identity_t> rhs); // Since C++26 +// template +// constexpr basic_string +// operator+(type_identity_t> lhs, +// const basic_string& rhs); // Since C++26 +// template +// constexpr basic_string +// operator+(type_identity_t> lhs, +// basic_string&& rhs); // Since C++26 + +#include +#include +#include +#include + +#include "asan_testing.h" +#include "constexpr_char_traits.h" +#include "make_string.h" +#include "min_allocator.h" +#include "test_allocator.h" +#include "test_macros.h" + +template > +class ConvertibleToStringView { +public: + constexpr explicit ConvertibleToStringView(const CharT* cs) : cs_{cs} {} + + constexpr operator std::basic_string_view() { return std::basic_string_view(cs_); } + constexpr operator std::basic_string_view() const { + return std::basic_string_view(cs_); + } + +private: + const CharT* cs_; +}; + +static_assert(std::constructible_from, const ConvertibleToStringView>); +static_assert(std::convertible_to, std::basic_string_view>); + +static_assert(std::constructible_from, ConvertibleToStringView>); +static_assert(std::convertible_to, std::basic_string_view>); + +#define CS(S) MAKE_CSTRING(CharT, S) + +template