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