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