| //===----------------------------------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 |
| |
| // <string_view> |
| |
| // template <class Range> |
| // constexpr basic_string_view(Range&& range); |
| |
| #include <string_view> |
| #include <array> |
| #include <cassert> |
| #include <iterator> |
| #include <ranges> |
| #include <type_traits> |
| #include <vector> |
| |
| #include "constexpr_char_traits.h" |
| #include "make_string.h" |
| #include "test_iterators.h" |
| #include "test_range.h" |
| |
| template<class CharT> |
| constexpr void test() { |
| auto data = MAKE_STRING_VIEW(CharT, "test"); |
| std::array<CharT, 4> arr; |
| for(int i = 0; i < 4; ++i) { |
| arr[i] = data[i]; |
| } |
| auto sv = std::basic_string_view<CharT>(arr); |
| |
| ASSERT_SAME_TYPE(decltype(sv), std::basic_string_view<CharT>); |
| assert(sv.size() == arr.size()); |
| assert(sv.data() == arr.data()); |
| } |
| |
| constexpr bool test() { |
| test<char>(); |
| #ifndef TEST_HAS_NO_WIDE_CHARACTERS |
| test<wchar_t>(); |
| #endif |
| test<char8_t>(); |
| test<char16_t>(); |
| test<char32_t>(); |
| |
| { |
| struct NonConstConversionOperator { |
| const char* data_ = "test"; |
| constexpr const char* begin() const { return data_; } |
| constexpr const char* end() const { return data_ + 4; } |
| constexpr operator std::basic_string_view<char>() { return "NonConstConversionOp"; } |
| }; |
| |
| NonConstConversionOperator nc; |
| std::string_view sv = nc; |
| assert(sv == "NonConstConversionOp"); |
| static_assert(!std::is_constructible_v<std::string_view, |
| const NonConstConversionOperator&>); // conversion operator is non-const |
| } |
| |
| { |
| struct ConstConversionOperator { |
| const char* data_ = "test"; |
| constexpr const char* begin() const { return data_; } |
| constexpr const char* end() const { return data_ + 4; } |
| constexpr operator std::basic_string_view<char>() const { return "ConstConversionOp"; } |
| }; |
| ConstConversionOperator cv; |
| std::basic_string_view<char> sv = cv; |
| assert(sv == "ConstConversionOp"); |
| } |
| |
| struct DeletedConversionOperator { |
| const char* data_ = "test"; |
| constexpr const char* begin() const { return data_; } |
| constexpr const char* end() const { return data_ + 4; } |
| operator std::basic_string_view<char>() = delete; |
| }; |
| |
| struct DeletedConstConversionOperator { |
| const char* data_ = "test"; |
| constexpr const char* begin() const { return data_; } |
| constexpr const char* end() const { return data_ + 4; } |
| operator std::basic_string_view<char>() const = delete; |
| }; |
| |
| static_assert(std::is_constructible_v<std::string_view, DeletedConversionOperator>); |
| static_assert(std::is_constructible_v<std::string_view, const DeletedConversionOperator>); |
| static_assert(std::is_constructible_v<std::string_view, DeletedConstConversionOperator>); |
| static_assert(std::is_constructible_v<std::string_view, const DeletedConstConversionOperator>); |
| |
| // Test that we're not trying to use the type's conversion operator to string_view in the constructor. |
| { |
| const DeletedConversionOperator d; |
| std::basic_string_view<char> csv = std::basic_string_view<char>(d); |
| assert(csv == "test"); |
| } |
| |
| { |
| DeletedConstConversionOperator dc; |
| std::basic_string_view<char> sv = std::basic_string_view<char>(dc); |
| assert(sv == "test"); |
| } |
| |
| return true; |
| } |
| |
| static_assert(std::is_constructible_v<std::string_view, std::vector<char>&>); |
| static_assert(std::is_constructible_v<std::string_view, const std::vector<char>&>); |
| static_assert(std::is_constructible_v<std::string_view, std::vector<char>&&>); |
| static_assert(std::is_constructible_v<std::string_view, const std::vector<char>&&>); |
| |
| using SizedButNotContiguousRange = std::ranges::subrange<random_access_iterator<char*>>; |
| static_assert(!std::ranges::contiguous_range<SizedButNotContiguousRange>); |
| static_assert(std::ranges::sized_range<SizedButNotContiguousRange>); |
| static_assert(!std::is_constructible_v<std::string_view, SizedButNotContiguousRange>); |
| |
| using ContiguousButNotSizedRange = std::ranges::subrange<contiguous_iterator<char*>, sentinel_wrapper<contiguous_iterator<char*>>, std::ranges::subrange_kind::unsized>; |
| static_assert(std::ranges::contiguous_range<ContiguousButNotSizedRange>); |
| static_assert(!std::ranges::sized_range<ContiguousButNotSizedRange>); |
| static_assert(!std::is_constructible_v<std::string_view, ContiguousButNotSizedRange>); |
| |
| static_assert(!std::is_constructible_v<std::string_view, std::vector<char16_t>>); // different CharT |
| |
| struct WithStringViewConversionOperator { |
| char* begin() const; |
| char* end() const; |
| operator std::string_view() const { return {}; } |
| }; |
| |
| static_assert(std::is_constructible_v<std::string_view, WithStringViewConversionOperator>); // lvalue |
| static_assert(std::is_constructible_v<std::string_view, const WithStringViewConversionOperator&>); // const lvalue |
| static_assert(std::is_constructible_v<std::string_view, WithStringViewConversionOperator&&>); // rvalue |
| |
| template <class CharTraits> |
| struct WithTraitsType { |
| typename CharTraits::char_type* begin() const; |
| typename CharTraits::char_type* end() const; |
| using traits_type = CharTraits; |
| }; |
| |
| using CCT = constexpr_char_traits<char>; |
| static_assert(std::is_constructible_v<std::string_view, WithTraitsType<std::char_traits<char>>>); |
| #ifndef TEST_HAS_NO_WIDE_CHARACTERS |
| static_assert(std::is_constructible_v<std::wstring_view, WithTraitsType<std::char_traits<wchar_t>>>); |
| #endif |
| static_assert(std::is_constructible_v<std::basic_string_view<char, CCT>, WithTraitsType<CCT>>); |
| static_assert(!std::is_constructible_v<std::string_view, WithTraitsType<CCT>>); // wrong traits type |
| #ifndef TEST_HAS_NO_WIDE_CHARACTERS |
| static_assert(!std::is_constructible_v<std::wstring_view, WithTraitsType<std::char_traits<char>>>); // wrong traits type |
| #endif |
| |
| #ifndef TEST_HAS_NO_EXCEPTIONS |
| void test_throwing() { |
| struct ThrowingData { |
| char* begin() const { return nullptr; } |
| char* end() const { return nullptr; } |
| char* data() const { throw 42; return nullptr; } |
| }; |
| try { |
| ThrowingData x; |
| (void) std::string_view(x); |
| assert(false); |
| } catch (int i) { |
| assert(i == 42); |
| } |
| |
| struct ThrowingSize { |
| char* begin() const { return nullptr; } |
| char* end() const { return nullptr; } |
| size_t size() const { throw 42; return 0; } |
| }; |
| try { |
| ThrowingSize x; |
| (void) std::string_view(x); |
| assert(false); |
| } catch (int i) { |
| assert(i == 42); |
| } |
| } |
| #endif |
| |
| static_assert(!std::is_convertible_v<std::vector<char>, std::string_view>); |
| |
| int main(int, char**) { |
| test(); |
| static_assert(test()); |
| #ifndef TEST_HAS_NO_EXCEPTIONS |
| test_throwing(); |
| #endif |
| |
| return 0; |
| } |
| |