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 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
9 // UNSUPPORTED: libcpp-has-no-incomplete-ranges
10
11 // <string_view>
12
13 // template <class Range>
14 // constexpr basic_string_view(Range&& range);
15
16 #include <string_view>
17 #include <array>
18 #include <cassert>
19 #include <iterator>
20 #include <ranges>
21 #include <type_traits>
22 #include <vector>
23
24 #include "constexpr_char_traits.h"
25 #include "make_string.h"
26 #include "test_iterators.h"
27 #include "test_range.h"
28
29 template<class CharT>
test()30 constexpr void test() {
31 auto data = MAKE_STRING_VIEW(CharT, "test");
32 std::array<CharT, 4> arr;
33 for(int i = 0; i < 4; ++i) {
34 arr[i] = data[i];
35 }
36 auto sv = std::basic_string_view<CharT>(arr);
37
38 ASSERT_SAME_TYPE(decltype(sv), std::basic_string_view<CharT>);
39 assert(sv.size() == arr.size());
40 assert(sv.data() == arr.data());
41 }
42
test()43 constexpr bool test() {
44 test<char>();
45 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
46 test<wchar_t>();
47 #endif
48 test<char8_t>();
49 test<char16_t>();
50 test<char32_t>();
51
52 {
53 struct NonConstConversionOperator {
54 const char* data_ = "test";
55 constexpr const char* begin() const { return data_; }
56 constexpr const char* end() const { return data_ + 4; }
57 constexpr operator std::basic_string_view<char>() { return "NonConstConversionOp"; }
58 };
59
60 NonConstConversionOperator nc;
61 std::string_view sv = nc;
62 assert(sv == "NonConstConversionOp");
63 static_assert(!std::is_constructible_v<std::string_view,
64 const NonConstConversionOperator&>); // conversion operator is non-const
65 }
66
67 {
68 struct ConstConversionOperator {
69 const char* data_ = "test";
70 constexpr const char* begin() const { return data_; }
71 constexpr const char* end() const { return data_ + 4; }
72 constexpr operator std::basic_string_view<char>() const { return "ConstConversionOp"; }
73 };
74 ConstConversionOperator cv;
75 std::basic_string_view<char> sv = cv;
76 assert(sv == "ConstConversionOp");
77 }
78
79 struct DeletedConversionOperator {
80 const char* data_ = "test";
81 constexpr const char* begin() const { return data_; }
82 constexpr const char* end() const { return data_ + 4; }
83 operator std::basic_string_view<char>() = delete;
84 };
85
86 struct DeletedConstConversionOperator {
87 const char* data_ = "test";
88 constexpr const char* begin() const { return data_; }
89 constexpr const char* end() const { return data_ + 4; }
90 operator std::basic_string_view<char>() const = delete;
91 };
92
93 static_assert(std::is_constructible_v<std::string_view, DeletedConversionOperator>);
94 static_assert(std::is_constructible_v<std::string_view, const DeletedConversionOperator>);
95 static_assert(std::is_constructible_v<std::string_view, DeletedConstConversionOperator>);
96 static_assert(std::is_constructible_v<std::string_view, const DeletedConstConversionOperator>);
97
98 // Test that we're not trying to use the type's conversion operator to string_view in the constructor.
99 {
100 const DeletedConversionOperator d;
101 std::basic_string_view<char> csv = d;
102 assert(csv == "test");
103 }
104
105 {
106 DeletedConstConversionOperator dc;
107 std::basic_string_view<char> sv = dc;
108 assert(sv == "test");
109 }
110
111 return true;
112 }
113
114 static_assert(std::is_constructible_v<std::string_view, std::vector<char>&>);
115 static_assert(std::is_constructible_v<std::string_view, const std::vector<char>&>);
116 static_assert(std::is_constructible_v<std::string_view, std::vector<char>&&>);
117 static_assert(std::is_constructible_v<std::string_view, const std::vector<char>&&>);
118
119 using SizedButNotContiguousRange = std::ranges::subrange<random_access_iterator<char*>>;
120 static_assert(!std::ranges::contiguous_range<SizedButNotContiguousRange>);
121 static_assert(std::ranges::sized_range<SizedButNotContiguousRange>);
122 static_assert(!std::is_constructible_v<std::string_view, SizedButNotContiguousRange>);
123
124 using ContiguousButNotSizedRange = std::ranges::subrange<contiguous_iterator<char*>, sentinel_wrapper<contiguous_iterator<char*>>, std::ranges::subrange_kind::unsized>;
125 static_assert(std::ranges::contiguous_range<ContiguousButNotSizedRange>);
126 static_assert(!std::ranges::sized_range<ContiguousButNotSizedRange>);
127 static_assert(!std::is_constructible_v<std::string_view, ContiguousButNotSizedRange>);
128
129 static_assert(!std::is_constructible_v<std::string_view, std::vector<char16_t>>); // different CharT
130
131 struct WithStringViewConversionOperator {
132 char* begin() const;
133 char* end() const;
operator std::string_viewWithStringViewConversionOperator134 operator std::string_view() const { return {}; }
135 };
136
137 static_assert(std::is_constructible_v<std::string_view, WithStringViewConversionOperator>); // lvalue
138 static_assert(std::is_constructible_v<std::string_view, const WithStringViewConversionOperator&>); // const lvalue
139 static_assert(std::is_constructible_v<std::string_view, WithStringViewConversionOperator&&>); // rvalue
140
141 template <class CharTraits>
142 struct WithTraitsType {
143 typename CharTraits::char_type* begin() const;
144 typename CharTraits::char_type* end() const;
145 using traits_type = CharTraits;
146 };
147
148 using CCT = constexpr_char_traits<char>;
149 static_assert(std::is_constructible_v<std::string_view, WithTraitsType<std::char_traits<char>>>);
150 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
151 static_assert(std::is_constructible_v<std::wstring_view, WithTraitsType<std::char_traits<wchar_t>>>);
152 #endif
153 static_assert(std::is_constructible_v<std::basic_string_view<char, CCT>, WithTraitsType<CCT>>);
154 static_assert(!std::is_constructible_v<std::string_view, WithTraitsType<CCT>>); // wrong traits type
155 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
156 static_assert(!std::is_constructible_v<std::wstring_view, WithTraitsType<std::char_traits<char>>>); // wrong traits type
157 #endif
158
159 #ifndef TEST_HAS_NO_EXCEPTIONS
test_throwing()160 void test_throwing() {
161 struct ThrowingData {
162 char* begin() const { return nullptr; }
163 char* end() const { return nullptr; }
164 char* data() const { throw 42; return nullptr; }
165 };
166 try {
167 ThrowingData x;
168 (void) std::string_view(x);
169 assert(false);
170 } catch (int i) {
171 assert(i == 42);
172 }
173
174 struct ThrowingSize {
175 char* begin() const { return nullptr; }
176 char* end() const { return nullptr; }
177 size_t size() const { throw 42; return 0; }
178 };
179 try {
180 ThrowingSize x;
181 (void) std::string_view(x);
182 assert(false);
183 } catch (int i) {
184 assert(i == 42);
185 }
186 }
187 #endif
188
main(int,char **)189 int main(int, char**) {
190 test();
191 static_assert(test());
192 #ifndef TEST_HAS_NO_EXCEPTIONS
193 test_throwing();
194 #endif
195
196 return 0;
197 }
198
199