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