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

source code of libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/begin_end.pass.cpp