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