[libcxx-commits] [libcxx] 4a19be5 - [libc++][strings] P2591R5: Concatenation of strings and string views (#88389)
via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Jul 18 03:26:40 PDT 2024
Author: Hristo Hristov
Date: 2024-07-18T13:26:37+03:00
New Revision: 4a19be5d45e4b1e02c2512023151be5d56ef5744
URL: https://github.com/llvm/llvm-project/commit/4a19be5d45e4b1e02c2512023151be5d56ef5744
DIFF: https://github.com/llvm/llvm-project/commit/4a19be5d45e4b1e02c2512023151be5d56ef5744.diff
LOG: [libc++][strings] P2591R5: Concatenation of strings and string views (#88389)
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 <zingam at outlook.com>
Added:
libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
Modified:
libcxx/docs/FeatureTestMacroTable.rst
libcxx/docs/ReleaseNotes/19.rst
libcxx/docs/Status/Cxx2cPapers.csv
libcxx/include/string
libcxx/include/version
libcxx/test/std/language.support/support.limits/support.limits.general/string.version.compile.pass.cpp
libcxx/test/std/language.support/support.limits/support.limits.general/string_view.version.compile.pass.cpp
libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
libcxx/utils/generate_feature_test_macro_components.py
Removed:
################################################################################
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 1e347d043ef69..53cfc3739d2be 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 80b9e18cec901..80f43256f1270 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 2c498f336b125..968d82a973a79 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -55,7 +55,7 @@
"`P2845R8 <https://wg21.link/P2845R8>`__","LWG","Formatting of ``std::filesystem::path``","Tokyo March 2024","","","|format|"
"`P0493R5 <https://wg21.link/P0493R5>`__","LWG","Atomic minimum/maximum","Tokyo March 2024","","",""
"`P2542R8 <https://wg21.link/P2542R8>`__","LWG","``views::concat``","Tokyo March 2024","","","|ranges|"
-"`P2591R5 <https://wg21.link/P2591R5>`__","LWG","Concatenation of strings and string views","Tokyo March 2024","","",""
+"`P2591R5 <https://wg21.link/P2591R5>`__","LWG","Concatenation of strings and string views","Tokyo March 2024","|Complete|","19.0",""
"`P2248R8 <https://wg21.link/P2248R8>`__","LWG","Enabling list-initialization for algorithms","Tokyo March 2024","","",""
"`P2810R4 <https://wg21.link/P2810R4>`__","LWG","``is_debugger_present`` ``is_replaceable``","Tokyo March 2024","","",""
"`P1068R11 <https://wg21.link/P1068R11>`__","LWG","Vector API for random number generation","Tokyo March 2024","","",""
diff --git a/libcxx/include/string b/libcxx/include/string
index 9a52ab6aef41e..90394e9edbe83 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -407,6 +407,24 @@ template<class charT, class traits, class Allocator>
basic_string<charT, traits, Allocator>
operator+(const basic_string<charT, traits, Allocator>& lhs, charT rhs); // constexpr since C++20
+template<class charT, class traits, class Allocator>
+ constexpr basic_string<charT, traits, Allocator>
+ operator+(const basic_string<charT, traits, Allocator>& lhs,
+ type_identity_t<basic_string_view<charT, traits>> rhs); // Since C++26
+template<class charT, class traits, class Allocator>
+ constexpr basic_string<charT, traits, Allocator>
+ operator+(basic_string<charT, traits, Allocator>&& lhs,
+ type_identity_t<basic_string_view<charT, traits>> rhs); // Since C++26
+template<class charT, class traits, class Allocator>
+ constexpr basic_string<charT, traits, Allocator>
+ operator+(type_identity_t<basic_string_view<charT, traits>> lhs,
+ const basic_string<charT, traits, Allocator>& rhs); // Since C++26
+template<class charT, class traits, class Allocator>
+ constexpr basic_string<charT, traits, Allocator>
+ operator+(type_identity_t<basic_string_view<charT, traits>> lhs,
+ basic_string<charT, traits, Allocator>&& rhs); // Since C++26
+
+
template<class charT, class traits, class Allocator>
bool operator==(const basic_string<charT, traits, Allocator>& lhs,
const basic_string<charT, traits, Allocator>& rhs) noexcept; // constexpr since C++20
@@ -687,6 +705,28 @@ template <class _CharT, class _Traits, class _Allocator>
_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 <class _CharT, class _Traits, class _Allocator>
+_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
+operator+(const basic_string<_CharT, _Traits, _Allocator>& __lhs,
+ type_identity_t<basic_string_view<_CharT, _Traits>> __rhs);
+
+template <class _CharT, class _Traits, class _Allocator>
+_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
+operator+(basic_string<_CharT, _Traits, _Allocator>&& __lhs, type_identity_t<basic_string_view<_CharT, _Traits>> __rhs);
+
+template <class _CharT, class _Traits, class _Allocator>
+_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
+operator+(type_identity_t<basic_string_view<_CharT, _Traits>> __lhs,
+ const basic_string<_CharT, _Traits, _Allocator>& __rhs);
+
+template <class _CharT, class _Traits, class _Allocator>
+_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
+operator+(type_identity_t<basic_string_view<_CharT, _Traits>> __lhs, basic_string<_CharT, _Traits, _Allocator>&& __rhs);
+
+#endif
+
extern template _LIBCPP_EXPORTED_FROM_ABI string operator+
<char, char_traits<char>, allocator<char> >(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 <class _CharT, class _Traits, class _Allocator>
+_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
+operator+(const basic_string<_CharT, _Traits, _Allocator>& __lhs,
+ type_identity_t<basic_string_view<_CharT, _Traits>> __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 <class _CharT, class _Traits, class _Allocator>
+_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
+operator+(basic_string<_CharT, _Traits, _Allocator>&& __lhs,
+ type_identity_t<basic_string_view<_CharT, _Traits>> __rhs) {
+ __lhs.append(__rhs);
+ return std::move(__lhs);
+}
+
+template <class _CharT, class _Traits, class _Allocator>
+_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
+operator+(type_identity_t<basic_string_view<_CharT, _Traits>> __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 <class _CharT, class _Traits, class _Allocator>
+_LIBCPP_HIDE_FROM_ABI constexpr basic_string<_CharT, _Traits, _Allocator>
+operator+(type_identity_t<basic_string_view<_CharT, _Traits>> __lhs,
+ basic_string<_CharT, _Traits, _Allocator>&& __rhs) {
+ __rhs.insert(0, __lhs);
+ return std::move(__rhs);
+}
+
+#endif // _LIBCPP_STD_VER >= 26
+
// swap
template <class _CharT, class _Traits, class _Allocator>
diff --git a/libcxx/include/version b/libcxx/include/version
index c971336bcb85c..7d9fad1cb1eb2 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -231,7 +231,8 @@ __cpp_lib_stdatomic_h 202011L <stdatomic.h>
__cpp_lib_string_contains 202011L <string> <string_view>
__cpp_lib_string_resize_and_overwrite 202110L <string>
__cpp_lib_string_udls 201304L <string>
-__cpp_lib_string_view 201803L <string> <string_view>
+__cpp_lib_string_view 202403L <string> <string_view>
+ 201803L // C++20
201606L // C++17
__cpp_lib_submdspan 202306L <mdspan>
__cpp_lib_syncbuf 201803L <syncstream>
@@ -547,6 +548,8 @@ __cpp_lib_void_t 201411L <type_traits>
# 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 af6386a40a458..69a938edd1cb9 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 a86ab2adff6a9..f3c70cf977973 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 <string_view>
@@ -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 a01ee702a5172..e1af3061725df 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 0000000000000..3d981e8b3a3cd
--- /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>
+
+// [string.op.plus]
+//
+// template<class charT, class traits, class Allocator>
+// constexpr basic_string<charT, traits, Allocator>
+// operator+(const basic_string<charT, traits, Allocator>& lhs,
+// type_identity_t<basic_string_view<charT, traits>> rhs); // Since C++26
+// template<class charT, class traits, class Allocator>
+// constexpr basic_string<charT, traits, Allocator>
+// operator+(basic_string<charT, traits, Allocator>&& lhs,
+// type_identity_t<basic_string_view<charT, traits>> rhs); // Since C++26
+// template<class charT, class traits, class Allocator>
+// constexpr basic_string<charT, traits, Allocator>
+// operator+(type_identity_t<basic_string_view<charT, traits>> lhs,
+// const basic_string<charT, traits, Allocator>& rhs); // Since C++26
+// template<class charT, class traits, class Allocator>
+// constexpr basic_string<charT, traits, Allocator>
+// operator+(type_identity_t<basic_string_view<charT, traits>> lhs,
+// basic_string<charT, traits, Allocator>&& rhs); // Since C++26
+
+#include <cassert>
+#include <concepts>
+#include <string>
+#include <utility>
+
+#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 <typename CharT, class TraitsT = std::char_traits<CharT>>
+class ConvertibleToStringView {
+public:
+ constexpr explicit ConvertibleToStringView(const CharT* cs) : cs_{cs} {}
+
+ constexpr operator std::basic_string_view<CharT, TraitsT>() { return std::basic_string_view<CharT, TraitsT>(cs_); }
+ constexpr operator std::basic_string_view<CharT, TraitsT>() const {
+ return std::basic_string_view<CharT, TraitsT>(cs_);
+ }
+
+private:
+ const CharT* cs_;
+};
+
+static_assert(std::constructible_from<std::basic_string_view<char>, const ConvertibleToStringView<char>>);
+static_assert(std::convertible_to<const ConvertibleToStringView<char>, std::basic_string_view<char>>);
+
+static_assert(std::constructible_from<std::basic_string_view<char>, ConvertibleToStringView<char>>);
+static_assert(std::convertible_to<ConvertibleToStringView<char>, std::basic_string_view<char>>);
+
+#define CS(S) MAKE_CSTRING(CharT, S)
+
+template <template <typename, typename> typename StringViewT, typename CharT, typename TraitsT, typename AllocT>
+constexpr void test(const CharT* x, const CharT* y, const CharT* expected) {
+ AllocT allocator;
+
+ // string& + string_view
+ {
+ std::basic_string<CharT, TraitsT, AllocT> st{x, allocator};
+ StringViewT<CharT, TraitsT> sv{y};
+
+ std::same_as<std::basic_string<CharT, TraitsT, AllocT>> decltype(auto) result = st + sv;
+ assert(result == expected);
+ assert(result.get_allocator() == allocator);
+ LIBCPP_ASSERT(is_string_asan_correct(st + sv));
+ }
+ // const string& + string_view
+ {
+ const std::basic_string<CharT, TraitsT, AllocT> st{x, allocator};
+ StringViewT<CharT, TraitsT> sv{y};
+
+ std::same_as<std::basic_string<CharT, TraitsT, AllocT>> decltype(auto) result = st + sv;
+ assert(result == expected);
+ assert(result.get_allocator() == allocator);
+ LIBCPP_ASSERT(is_string_asan_correct(st + sv));
+ }
+ // string&& + string_view
+ {
+ std::basic_string<CharT, TraitsT, AllocT> st{x, allocator};
+ StringViewT<CharT, TraitsT> sv{y};
+
+ std::same_as<std::basic_string<CharT, TraitsT, AllocT>> decltype(auto) result = std::move(st) + sv;
+ assert(result == expected);
+ assert(result.get_allocator() == allocator);
+ LIBCPP_ASSERT(is_string_asan_correct(std::move(st) + sv));
+ }
+ // string_view + string&
+ {
+ StringViewT<CharT, TraitsT> sv{x};
+ std::basic_string<CharT, TraitsT, AllocT> st{y, allocator};
+
+ std::same_as<std::basic_string<CharT, TraitsT, AllocT>> decltype(auto) result = sv + st;
+ assert(result == expected);
+ assert(result.get_allocator() == allocator);
+ LIBCPP_ASSERT(is_string_asan_correct(sv + st));
+ }
+ // string_view + const string&
+ {
+ StringViewT<CharT, TraitsT> sv{x};
+ const std::basic_string<CharT, TraitsT, AllocT> st{y, allocator};
+
+ std::same_as<std::basic_string<CharT, TraitsT, AllocT>> decltype(auto) result = sv + st;
+ assert(result == expected);
+ assert(result.get_allocator() == allocator);
+ LIBCPP_ASSERT(is_string_asan_correct(sv + st));
+ }
+ // string_view + string&&
+ {
+ // TODO: Remove workaround once https://github.com/llvm/llvm-project/issues/92382 is fixed.
+ // Create a `basic_string` to workaround clang bug:
+ // https://github.com/llvm/llvm-project/issues/92382
+ // Comparison between pointers to a string literal and some other object results in constant evaluation failure.
+ if constexpr (std::same_as<StringViewT<CharT, TraitsT>, std::basic_string_view<CharT, TraitsT>>) {
+ std::basic_string<CharT, TraitsT, AllocT> st_{x, allocator};
+ StringViewT<CharT, TraitsT> sv{st_};
+ std::basic_string<CharT, TraitsT, AllocT> st{y, allocator};
+
+ std::same_as<std::basic_string<CharT, TraitsT, AllocT>> decltype(auto) result = sv + std::move(st);
+ assert(result == expected);
+ assert(result.get_allocator() == allocator);
+ LIBCPP_ASSERT(is_string_asan_correct(sv + std::move(st)));
+ }
+ }
+}
+
+template <template <typename, typename> typename StringViewT,
+ typename CharT,
+ typename TraitsT,
+ typename AllocT = std::allocator<CharT>>
+constexpr void test() {
+ // Concatenate with an empty `string`/`string_view`
+ test<StringViewT, CharT, TraitsT, AllocT>(CS(""), CS(""), CS(""));
+ test<StringViewT, CharT, TraitsT, AllocT>(CS(""), CS("short"), CS("short"));
+ test<StringViewT, CharT, TraitsT, AllocT>(CS(""), CS("not so short"), CS("not so short"));
+ test<StringViewT, CharT, TraitsT, AllocT>(
+ CS(""), CS("this is a much longer string"), CS("this is a much longer string"));
+
+ test<StringViewT, CharT, TraitsT, AllocT>(CS(""), CS(""), CS(""));
+ test<StringViewT, CharT, TraitsT, AllocT>(CS("short"), CS(""), CS("short"));
+ test<StringViewT, CharT, TraitsT, AllocT>(CS("not so short"), CS(""), CS("not so short"));
+ test<StringViewT, CharT, TraitsT, AllocT>(
+ CS("this is a much longer string"), CS(""), CS("this is a much longer string"));
+
+ // Non empty
+ test<StringViewT, CharT, TraitsT, AllocT>(CS("B"), CS("D"), CS("BD"));
+ test<StringViewT, CharT, TraitsT, AllocT>(CS("zmt94"), CS("+hkt82"), CS("zmt94+hkt82"));
+ test<StringViewT, CharT, TraitsT, AllocT>(CS("not so short"), CS("+is not bad"), CS("not so short+is not bad"));
+ test<StringViewT, CharT, TraitsT, AllocT>(
+ CS("this is a much longer string"),
+ CS("+which is so much better"),
+ CS("this is a much longer string+which is so much better"));
+}
+
+template <template <typename, typename> typename StringViewT, typename CharT>
+constexpr bool test() {
+ test<StringViewT, CharT, std::char_traits<CharT>>();
+ test<StringViewT, CharT, std::char_traits<CharT>, min_allocator<CharT>>();
+ test<StringViewT, CharT, std::char_traits<CharT>, safe_allocator<CharT>>();
+ test<StringViewT, CharT, std::char_traits<CharT>, test_allocator<CharT>>();
+
+ test<StringViewT, CharT, constexpr_char_traits<CharT>>();
+ test<StringViewT, CharT, constexpr_char_traits<CharT>, min_allocator<CharT>>();
+ test<StringViewT, CharT, constexpr_char_traits<CharT>, safe_allocator<CharT>>();
+ test<StringViewT, CharT, constexpr_char_traits<CharT>, test_allocator<CharT>>();
+
+ return true;
+}
+
+int main(int, char**) {
+ // std::basic_string_view
+ test<std::basic_string_view, char>();
+ static_assert(test<std::basic_string_view, char>());
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+ test<std::basic_string_view, wchar_t>();
+ static_assert(test<std::basic_string_view, wchar_t>());
+#endif
+#ifndef TEST_HAS_NO_CHAR8_T
+ test<std::basic_string_view, char8_t>();
+ static_assert(test<std::basic_string_view, char8_t>());
+#endif
+ test<std::basic_string_view, char16_t>();
+ static_assert(test<std::basic_string_view, char16_t>());
+ test<std::basic_string_view, char32_t>();
+ static_assert(test<std::basic_string_view, char32_t>());
+
+ // ConvertibleToStringView
+ test<ConvertibleToStringView, char>();
+ static_assert(test<ConvertibleToStringView, char>());
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+ test<ConvertibleToStringView, wchar_t>();
+ static_assert(test<ConvertibleToStringView, wchar_t>());
+#endif
+#ifndef TEST_HAS_NO_CHAR8_T
+ test<ConvertibleToStringView, char8_t>();
+ static_assert(test<ConvertibleToStringView, char8_t>());
+#endif
+ test<ConvertibleToStringView, char16_t>();
+ static_assert(test<ConvertibleToStringView, char16_t>());
+ test<ConvertibleToStringView, char32_t>();
+ static_assert(test<ConvertibleToStringView, char32_t>());
+
+ return 0;
+}
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 773b1523cde4e..a267e5774e2ad 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -1267,7 +1267,7 @@ def add_version_header(tc):
"values": {
"c++17": 201606,
"c++20": 201803,
- # "c++26": 202403, # P2591R5: Concatenation of strings and string views
+ "c++26": 202403, # P2591R5: Concatenation of strings and string views
},
"headers": ["string", "string_view"],
},
More information about the libcxx-commits
mailing list