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

source code of libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp