1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 10 11 // <string> 12 13 // [string.op.plus] 14 // 15 // template<class charT, class traits, class Allocator> 16 // constexpr basic_string<charT, traits, Allocator> 17 // operator+(const basic_string<charT, traits, Allocator>& lhs, 18 // type_identity_t<basic_string_view<charT, traits>> rhs); // Since C++26 19 // template<class charT, class traits, class Allocator> 20 // constexpr basic_string<charT, traits, Allocator> 21 // operator+(basic_string<charT, traits, Allocator>&& lhs, 22 // type_identity_t<basic_string_view<charT, traits>> rhs); // Since C++26 23 // template<class charT, class traits, class Allocator> 24 // constexpr basic_string<charT, traits, Allocator> 25 // operator+(type_identity_t<basic_string_view<charT, traits>> lhs, 26 // const basic_string<charT, traits, Allocator>& rhs); // Since C++26 27 // template<class charT, class traits, class Allocator> 28 // constexpr basic_string<charT, traits, Allocator> 29 // operator+(type_identity_t<basic_string_view<charT, traits>> lhs, 30 // basic_string<charT, traits, Allocator>&& rhs); // Since C++26 31 32 #include <cassert> 33 #include <concepts> 34 #include <string> 35 #include <utility> 36 37 #include "asan_testing.h" 38 #include "constexpr_char_traits.h" 39 #include "make_string.h" 40 #include "min_allocator.h" 41 #include "test_allocator.h" 42 #include "test_macros.h" 43 44 template <typename CharT, class TraitsT = std::char_traits<CharT>> 45 class ConvertibleToStringView { 46 public: 47 constexpr explicit ConvertibleToStringView(const CharT* cs) : cs_{cs} {} 48 49 constexpr operator std::basic_string_view<CharT, TraitsT>() { return std::basic_string_view<CharT, TraitsT>(cs_); } 50 constexpr operator std::basic_string_view<CharT, TraitsT>() const { 51 return std::basic_string_view<CharT, TraitsT>(cs_); 52 } 53 54 private: 55 const CharT* cs_; 56 }; 57 58 static_assert(std::constructible_from<std::basic_string_view<char>, const ConvertibleToStringView<char>>); 59 static_assert(std::convertible_to<const ConvertibleToStringView<char>, std::basic_string_view<char>>); 60 61 static_assert(std::constructible_from<std::basic_string_view<char>, ConvertibleToStringView<char>>); 62 static_assert(std::convertible_to<ConvertibleToStringView<char>, std::basic_string_view<char>>); 63 64 #define CS(S) MAKE_CSTRING(CharT, S) 65 66 template <template <typename, typename> typename StringViewT, typename CharT, typename TraitsT, typename AllocT> 67 constexpr void test(const CharT* x, const CharT* y, const CharT* expected) { 68 AllocT allocator; 69 70 // string& + string_view 71 { 72 std::basic_string<CharT, TraitsT, AllocT> st{x, allocator}; 73 StringViewT<CharT, TraitsT> sv{y}; 74 75 std::same_as<std::basic_string<CharT, TraitsT, AllocT>> decltype(auto) result = st + sv; 76 assert(result == expected); 77 assert(result.get_allocator() == allocator); 78 LIBCPP_ASSERT(is_string_asan_correct(st + sv)); 79 } 80 // const string& + string_view 81 { 82 const std::basic_string<CharT, TraitsT, AllocT> st{x, allocator}; 83 StringViewT<CharT, TraitsT> sv{y}; 84 85 std::same_as<std::basic_string<CharT, TraitsT, AllocT>> decltype(auto) result = st + sv; 86 assert(result == expected); 87 assert(result.get_allocator() == allocator); 88 LIBCPP_ASSERT(is_string_asan_correct(st + sv)); 89 } 90 // string&& + string_view 91 { 92 std::basic_string<CharT, TraitsT, AllocT> st{x, allocator}; 93 StringViewT<CharT, TraitsT> sv{y}; 94 95 std::same_as<std::basic_string<CharT, TraitsT, AllocT>> decltype(auto) result = std::move(st) + sv; 96 assert(result == expected); 97 assert(result.get_allocator() == allocator); 98 LIBCPP_ASSERT(is_string_asan_correct(std::move(st) + sv)); 99 } 100 // string_view + string& 101 { 102 StringViewT<CharT, TraitsT> sv{x}; 103 std::basic_string<CharT, TraitsT, AllocT> st{y, allocator}; 104 105 std::same_as<std::basic_string<CharT, TraitsT, AllocT>> decltype(auto) result = sv + st; 106 assert(result == expected); 107 assert(result.get_allocator() == allocator); 108 LIBCPP_ASSERT(is_string_asan_correct(sv + st)); 109 } 110 // string_view + const string& 111 { 112 StringViewT<CharT, TraitsT> sv{x}; 113 const std::basic_string<CharT, TraitsT, AllocT> st{y, allocator}; 114 115 std::same_as<std::basic_string<CharT, TraitsT, AllocT>> decltype(auto) result = sv + st; 116 assert(result == expected); 117 assert(result.get_allocator() == allocator); 118 LIBCPP_ASSERT(is_string_asan_correct(sv + st)); 119 } 120 // string_view + string&& 121 { 122 // TODO: Remove workaround once https://github.com/llvm/llvm-project/issues/92382 is fixed. 123 // Create a `basic_string` to workaround clang bug: 124 // https://github.com/llvm/llvm-project/issues/92382 125 // Comparison between pointers to a string literal and some other object results in constant evaluation failure. 126 if constexpr (std::same_as<StringViewT<CharT, TraitsT>, std::basic_string_view<CharT, TraitsT>>) { 127 std::basic_string<CharT, TraitsT, AllocT> st_{x, allocator}; 128 StringViewT<CharT, TraitsT> sv{st_}; 129 std::basic_string<CharT, TraitsT, AllocT> st{y, allocator}; 130 131 std::same_as<std::basic_string<CharT, TraitsT, AllocT>> decltype(auto) result = sv + std::move(st); 132 assert(result == expected); 133 assert(result.get_allocator() == allocator); 134 LIBCPP_ASSERT(is_string_asan_correct(sv + std::move(st))); 135 } 136 } 137 } 138 139 template <template <typename, typename> typename StringViewT, 140 typename CharT, 141 typename TraitsT, 142 typename AllocT = std::allocator<CharT>> 143 constexpr void test() { 144 // Concatenate with an empty `string`/`string_view` 145 test<StringViewT, CharT, TraitsT, AllocT>(CS(""), CS(""), CS("")); 146 test<StringViewT, CharT, TraitsT, AllocT>(CS(""), CS("short"), CS("short")); 147 test<StringViewT, CharT, TraitsT, AllocT>(CS(""), CS("not so short"), CS("not so short")); 148 test<StringViewT, CharT, TraitsT, AllocT>( 149 CS(""), CS("this is a much longer string"), CS("this is a much longer string")); 150 151 test<StringViewT, CharT, TraitsT, AllocT>(CS(""), CS(""), CS("")); 152 test<StringViewT, CharT, TraitsT, AllocT>(CS("short"), CS(""), CS("short")); 153 test<StringViewT, CharT, TraitsT, AllocT>(CS("not so short"), CS(""), CS("not so short")); 154 test<StringViewT, CharT, TraitsT, AllocT>( 155 CS("this is a much longer string"), CS(""), CS("this is a much longer string")); 156 157 // Non empty 158 test<StringViewT, CharT, TraitsT, AllocT>(CS("B"), CS("D"), CS("BD")); 159 test<StringViewT, CharT, TraitsT, AllocT>(CS("zmt94"), CS("+hkt82"), CS("zmt94+hkt82")); 160 test<StringViewT, CharT, TraitsT, AllocT>(CS("not so short"), CS("+is not bad"), CS("not so short+is not bad")); 161 test<StringViewT, CharT, TraitsT, AllocT>( 162 CS("this is a much longer string"), 163 CS("+which is so much better"), 164 CS("this is a much longer string+which is so much better")); 165 } 166 167 template <template <typename, typename> typename StringViewT, typename CharT> 168 constexpr bool test() { 169 test<StringViewT, CharT, std::char_traits<CharT>>(); 170 test<StringViewT, CharT, std::char_traits<CharT>, min_allocator<CharT>>(); 171 test<StringViewT, CharT, std::char_traits<CharT>, safe_allocator<CharT>>(); 172 test<StringViewT, CharT, std::char_traits<CharT>, test_allocator<CharT>>(); 173 174 test<StringViewT, CharT, constexpr_char_traits<CharT>>(); 175 test<StringViewT, CharT, constexpr_char_traits<CharT>, min_allocator<CharT>>(); 176 test<StringViewT, CharT, constexpr_char_traits<CharT>, safe_allocator<CharT>>(); 177 test<StringViewT, CharT, constexpr_char_traits<CharT>, test_allocator<CharT>>(); 178 179 return true; 180 } 181 182 int main(int, char**) { 183 // std::basic_string_view 184 test<std::basic_string_view, char>(); 185 static_assert(test<std::basic_string_view, char>()); 186 #ifndef TEST_HAS_NO_WIDE_CHARACTERS 187 test<std::basic_string_view, wchar_t>(); 188 static_assert(test<std::basic_string_view, wchar_t>()); 189 #endif 190 #ifndef TEST_HAS_NO_CHAR8_T 191 test<std::basic_string_view, char8_t>(); 192 static_assert(test<std::basic_string_view, char8_t>()); 193 #endif 194 test<std::basic_string_view, char16_t>(); 195 static_assert(test<std::basic_string_view, char16_t>()); 196 test<std::basic_string_view, char32_t>(); 197 static_assert(test<std::basic_string_view, char32_t>()); 198 199 // ConvertibleToStringView 200 test<ConvertibleToStringView, char>(); 201 static_assert(test<ConvertibleToStringView, char>()); 202 #ifndef TEST_HAS_NO_WIDE_CHARACTERS 203 test<ConvertibleToStringView, wchar_t>(); 204 static_assert(test<ConvertibleToStringView, wchar_t>()); 205 #endif 206 #ifndef TEST_HAS_NO_CHAR8_T 207 test<ConvertibleToStringView, char8_t>(); 208 static_assert(test<ConvertibleToStringView, char8_t>()); 209 #endif 210 test<ConvertibleToStringView, char16_t>(); 211 static_assert(test<ConvertibleToStringView, char16_t>()); 212 test<ConvertibleToStringView, char32_t>(); 213 static_assert(test<ConvertibleToStringView, char32_t>()); 214 215 return 0; 216 } 217