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