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