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