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