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 9 // UNSUPPORTED: c++03, c++11, c++14, c++17 10 // UNSUPPORTED: libcpp-no-concepts 11 // UNSUPPORTED: libcpp-has-no-incomplete-ranges 12 13 14 // constexpr iterator_t<R> begin(); 15 // constexpr sentinel_t<R> end(); 16 // constexpr auto begin() const requires range<const R>; 17 // constexpr auto end() const requires range<const R>; 18 19 #include <ranges> 20 21 #include <array> 22 #include <cassert> 23 #include <concepts> 24 25 #include "test_iterators.h" 26 #include "test_macros.h" 27 28 struct Base { 29 constexpr int *begin() { return nullptr; } 30 constexpr auto end() { return sentinel_wrapper<int*>(nullptr); } 31 constexpr char *begin() const { return nullptr; } 32 constexpr auto end() const { return sentinel_wrapper<char*>(nullptr); } 33 }; 34 static_assert(std::same_as<std::ranges::iterator_t<Base>, int*>); 35 static_assert(std::same_as<std::ranges::sentinel_t<Base>, sentinel_wrapper<int*>>); 36 static_assert(std::same_as<std::ranges::iterator_t<const Base>, char*>); 37 static_assert(std::same_as<std::ranges::sentinel_t<const Base>, sentinel_wrapper<char*>>); 38 39 struct NoConst { 40 int* begin(); 41 sentinel_wrapper<int*> end(); 42 }; 43 44 struct DecayChecker { 45 int*& begin() const; 46 int*& end() const; 47 }; 48 49 template <class T> 50 concept HasBegin = requires (T t) { 51 t.begin(); 52 }; 53 54 template <class T> 55 concept HasEnd = requires (T t) { 56 t.end(); 57 }; 58 59 constexpr bool test() 60 { 61 { 62 using OwningView = std::ranges::owning_view<Base>; 63 OwningView ov; 64 std::same_as<int*> decltype(auto) b1 = static_cast<OwningView&>(ov).begin(); 65 std::same_as<int*> decltype(auto) b2 = static_cast<OwningView&&>(ov).begin(); 66 std::same_as<char*> decltype(auto) b3 = static_cast<const OwningView&>(ov).begin(); 67 std::same_as<char*> decltype(auto) b4 = static_cast<const OwningView&&>(ov).begin(); 68 69 std::same_as<sentinel_wrapper<int*>> decltype(auto) e1 = static_cast<OwningView&>(ov).end(); 70 std::same_as<sentinel_wrapper<int*>> decltype(auto) e2 = static_cast<OwningView&&>(ov).end(); 71 std::same_as<sentinel_wrapper<char*>> decltype(auto) e3 = static_cast<const OwningView&>(ov).end(); 72 std::same_as<sentinel_wrapper<char*>> decltype(auto) e4 = static_cast<const OwningView&&>(ov).end(); 73 74 assert(b1 == e1); 75 assert(b2 == e2); 76 assert(b3 == e3); 77 assert(b4 == e4); 78 } 79 { 80 // NoConst has non-const begin() and end(); so does the owning_view. 81 using OwningView = std::ranges::owning_view<NoConst>; 82 static_assert(HasBegin<OwningView&>); 83 static_assert(HasBegin<OwningView&&>); 84 static_assert(!HasBegin<const OwningView&>); 85 static_assert(!HasBegin<const OwningView&&>); 86 static_assert(HasEnd<OwningView&>); 87 static_assert(HasEnd<OwningView&&>); 88 static_assert(!HasEnd<const OwningView&>); 89 static_assert(!HasEnd<const OwningView&&>); 90 } 91 { 92 // DecayChecker's begin() and end() return references; make sure the owning_view decays them. 93 using OwningView = std::ranges::owning_view<DecayChecker>; 94 OwningView ov; 95 ASSERT_SAME_TYPE(decltype(ov.begin()), int*); 96 ASSERT_SAME_TYPE(decltype(ov.end()), int*); 97 } 98 { 99 // Test an empty view. 100 int a[] = {1}; 101 auto ov = std::ranges::owning_view(std::ranges::subrange(a, a)); 102 assert(ov.begin() == a); 103 assert(std::as_const(ov).begin() == a); 104 assert(ov.end() == a); 105 assert(std::as_const(ov).end() == a); 106 } 107 { 108 // Test a non-empty view. 109 int a[] = {1}; 110 auto ov = std::ranges::owning_view(std::ranges::subrange(a, a+1)); 111 assert(ov.begin() == a); 112 assert(std::as_const(ov).begin() == a); 113 assert(ov.end() == a+1); 114 assert(std::as_const(ov).end() == a+1); 115 } 116 { 117 // Test a non-view. 118 std::array<int, 2> a = {1, 2}; 119 auto ov = std::ranges::owning_view(std::move(a)); 120 assert(ov.begin() != a.begin()); // because it points into the copy 121 assert(std::as_const(ov).begin() != a.begin()); 122 assert(ov.end() != a.end()); 123 assert(std::as_const(ov).end() != a.end()); 124 } 125 return true; 126 } 127 128 int main(int, char**) { 129 test(); 130 static_assert(test()); 131 132 return 0; 133 } 134