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 | // template<bool OtherConst> |
12 | // requires sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>> |
13 | // friend constexpr bool operator==(const iterator<OtherConst>& x, const sentinel& y); |
14 | |
15 | #include <array> |
16 | #include <cassert> |
17 | #include <ranges> |
18 | |
19 | #include "../types.h" |
20 | #include "test_range.h" |
21 | |
22 | template <bool Const> |
23 | struct Iter { |
24 | std::tuple<int>* it_; |
25 | |
26 | using value_type = std::tuple<int>; |
27 | using difference_type = std::intptr_t; |
28 | using iterator_concept = std::input_iterator_tag; |
29 | |
30 | constexpr decltype(auto) operator*() const { return *it_; } |
31 | constexpr Iter& operator++() { |
32 | ++it_; |
33 | return *this; |
34 | } |
35 | constexpr void operator++(int) { ++it_; } |
36 | }; |
37 | |
38 | template <bool Const> |
39 | struct Sent { |
40 | std::tuple<int>* end_; |
41 | |
42 | constexpr bool operator==(const Iter<Const>& i) const { return i.it_ == end_; } |
43 | }; |
44 | |
45 | template <bool Const> |
46 | struct CrossComparableSent { |
47 | std::tuple<int>* end_; |
48 | |
49 | template <bool C> |
50 | constexpr bool operator==(const Iter<C>& i) const { |
51 | return i.it_ == end_; |
52 | } |
53 | }; |
54 | |
55 | template <template <bool> typename St> |
56 | struct Range : TupleBufferView { |
57 | using TupleBufferView::TupleBufferView; |
58 | constexpr Iter<false> begin() { return Iter<false>{buffer_}; } |
59 | constexpr Iter<true> begin() const { return Iter<true>{buffer_}; } |
60 | constexpr St<false> end() { return St<false>{buffer_ + size_}; } |
61 | constexpr St<true> end() const { return St<true>{buffer_ + size_}; } |
62 | }; |
63 | |
64 | using R = Range<Sent>; |
65 | using CrossComparableR = Range<CrossComparableSent>; |
66 | |
67 | using std::ranges::elements_view; |
68 | using std::ranges::iterator_t; |
69 | using std::ranges::sentinel_t; |
70 | |
71 | static_assert(weakly_equality_comparable_with<iterator_t<elements_view<R, 0>>, // |
72 | sentinel_t<elements_view<R, 0>>>); |
73 | |
74 | static_assert(!weakly_equality_comparable_with<iterator_t<const elements_view<R, 0>>, // |
75 | sentinel_t<elements_view<R, 0>>>); |
76 | |
77 | static_assert(!weakly_equality_comparable_with<iterator_t<elements_view<R, 0>>, // |
78 | sentinel_t<const elements_view<R, 0>>>); |
79 | |
80 | static_assert(weakly_equality_comparable_with<iterator_t<const elements_view<R, 0>>, // |
81 | sentinel_t<const elements_view<R, 0>>>); |
82 | |
83 | static_assert(weakly_equality_comparable_with<iterator_t<elements_view<CrossComparableR, 0>>, // |
84 | sentinel_t<elements_view<CrossComparableR, 0>>>); |
85 | |
86 | static_assert(weakly_equality_comparable_with<iterator_t<const elements_view<CrossComparableR, 0>>, // |
87 | sentinel_t<elements_view<CrossComparableR, 0>>>); |
88 | |
89 | static_assert(weakly_equality_comparable_with<iterator_t<elements_view<CrossComparableR, 0>>, // |
90 | sentinel_t<const elements_view<CrossComparableR, 0>>>); |
91 | |
92 | static_assert(weakly_equality_comparable_with<iterator_t<const elements_view<CrossComparableR, 0>>, // |
93 | sentinel_t<const elements_view<CrossComparableR, 0>>>); |
94 | |
95 | template <class R, bool ConstIter, bool ConstSent> |
96 | constexpr void testOne() { |
97 | auto getBegin = [](auto&& rng) { |
98 | if constexpr (ConstIter) { |
99 | return std::as_const(rng).begin(); |
100 | } else { |
101 | return rng.begin(); |
102 | } |
103 | }; |
104 | |
105 | auto getEnd = [](auto&& rng) { |
106 | if constexpr (ConstSent) { |
107 | return std::as_const(rng).end(); |
108 | } else { |
109 | return rng.end(); |
110 | } |
111 | }; |
112 | |
113 | // iter == sentinel.base |
114 | { |
115 | std::tuple<int> buffer[] = {{1}}; |
116 | R v{buffer}; |
117 | std::ranges::elements_view<R, 0> ev(v); |
118 | auto iter = getBegin(ev); |
119 | auto st = getEnd(ev); |
120 | ++iter; |
121 | assert(iter == st); |
122 | } |
123 | |
124 | // iter != sentinel.base |
125 | { |
126 | std::tuple<int> buffer[] = {{1}}; |
127 | R v{buffer}; |
128 | std::ranges::elements_view<R, 0> ev(v); |
129 | auto iter = getBegin(ev); |
130 | auto st = getEnd(ev); |
131 | assert(iter != st); |
132 | } |
133 | |
134 | // empty range |
135 | { |
136 | std::array<std::tuple<int>, 0> arr; |
137 | R v{arr}; |
138 | std::ranges::elements_view<R, 0> ev(v); |
139 | auto iter = getBegin(ev); |
140 | auto sent = getEnd(ev); |
141 | assert(iter == sent); |
142 | } |
143 | } |
144 | |
145 | constexpr bool test() { |
146 | testOne<R, false, false>(); |
147 | testOne<R, true, true>(); |
148 | testOne<CrossComparableR, false, false>(); |
149 | testOne<CrossComparableR, true, true>(); |
150 | testOne<CrossComparableR, true, false>(); |
151 | testOne<CrossComparableR, false, true>(); |
152 | |
153 | return true; |
154 | } |
155 | |
156 | int main(int, char**) { |
157 | test(); |
158 | static_assert(test()); |
159 | |
160 | return 0; |
161 | } |
162 | |