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, c++20 |
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 <cassert> |
16 | #include <compare> |
17 | #include <ranges> |
18 | #include <tuple> |
19 | |
20 | #include "../types.h" |
21 | #include "test_range.h" |
22 | |
23 | using Iterator = random_access_iterator<int*>; |
24 | using ConstIterator = random_access_iterator<const int*>; |
25 | |
26 | template <bool Const> |
27 | struct ComparableSentinel { |
28 | |
29 | using Iter = std::conditional_t<Const, ConstIterator, Iterator>; |
30 | Iter iter_; |
31 | |
32 | explicit ComparableSentinel() = default; |
33 | constexpr explicit ComparableSentinel(const Iter& it) : iter_(it) {} |
34 | |
35 | constexpr friend bool operator==(const Iterator& i, const ComparableSentinel& s) { return base(i) == base(s.iter_); } |
36 | |
37 | constexpr friend bool operator==(const ConstIterator& i, const ComparableSentinel& s) { |
38 | return base(i) == base(s.iter_); |
39 | } |
40 | }; |
41 | |
42 | struct ComparableView : IntBufferView { |
43 | using IntBufferView::IntBufferView; |
44 | |
45 | constexpr auto begin() { return Iterator(buffer_); } |
46 | constexpr auto begin() const { return ConstIterator(buffer_); } |
47 | constexpr auto end() { return ComparableSentinel<false>(Iterator(buffer_ + size_)); } |
48 | constexpr auto end() const { return ComparableSentinel<true>(ConstIterator(buffer_ + size_)); } |
49 | }; |
50 | |
51 | struct ConstIncompatibleView : std::ranges::view_base { |
52 | cpp17_input_iterator<int*> begin(); |
53 | forward_iterator<const int*> begin() const; |
54 | sentinel_wrapper<cpp17_input_iterator<int*>> end(); |
55 | sentinel_wrapper<forward_iterator<const int*>> end() const; |
56 | }; |
57 | |
58 | constexpr bool test() { |
59 | int buffer1[4] = {1, 2, 3, 4}; |
60 | int buffer2[5] = {1, 2, 3, 4, 5}; |
61 | int buffer3[8] = {1, 2, 3, 4, 5, 6, 7, 8}; |
62 | { |
63 | // simple-view: const and non-const have the same iterator/sentinel type |
64 | std::ranges::zip_view v{SimpleNonCommon(buffer1), SimpleNonCommon(buffer2), SimpleNonCommon(buffer3)}; |
65 | static_assert(!std::ranges::common_range<decltype(v)>); |
66 | static_assert(simple_view<decltype(v)>); |
67 | |
68 | assert(v.begin() != v.end()); |
69 | assert(v.begin() + 1 != v.end()); |
70 | assert(v.begin() + 2 != v.end()); |
71 | assert(v.begin() + 3 != v.end()); |
72 | assert(v.begin() + 4 == v.end()); |
73 | } |
74 | |
75 | { |
76 | // !simple-view: const and non-const have different iterator/sentinel types |
77 | std::ranges::zip_view v{NonSimpleNonCommon(buffer1), SimpleNonCommon(buffer2), SimpleNonCommon(buffer3)}; |
78 | static_assert(!std::ranges::common_range<decltype(v)>); |
79 | static_assert(!simple_view<decltype(v)>); |
80 | |
81 | assert(v.begin() != v.end()); |
82 | assert(v.begin() + 4 == v.end()); |
83 | |
84 | // const_iterator (const int*) converted to iterator (int*) |
85 | assert(v.begin() + 4 == std::as_const(v).end()); |
86 | |
87 | using Iter = std::ranges::iterator_t<decltype(v)>; |
88 | using ConstIter = std::ranges::iterator_t<const decltype(v)>; |
89 | static_assert(!std::is_same_v<Iter, ConstIter>); |
90 | using Sentinel = std::ranges::sentinel_t<decltype(v)>; |
91 | using ConstSentinel = std::ranges::sentinel_t<const decltype(v)>; |
92 | static_assert(!std::is_same_v<Sentinel, ConstSentinel>); |
93 | |
94 | static_assert(weakly_equality_comparable_with<Iter, Sentinel>); |
95 | static_assert(!weakly_equality_comparable_with<ConstIter, Sentinel>); |
96 | static_assert(weakly_equality_comparable_with<Iter, ConstSentinel>); |
97 | static_assert(weakly_equality_comparable_with<ConstIter, ConstSentinel>); |
98 | } |
99 | |
100 | { |
101 | // underlying const/non-const sentinel can be compared with both const/non-const iterator |
102 | std::ranges::zip_view v{ComparableView(buffer1), ComparableView(buffer2)}; |
103 | static_assert(!std::ranges::common_range<decltype(v)>); |
104 | static_assert(!simple_view<decltype(v)>); |
105 | |
106 | assert(v.begin() != v.end()); |
107 | assert(v.begin() + 4 == v.end()); |
108 | assert(std::as_const(v).begin() + 4 == v.end()); |
109 | assert(std::as_const(v).begin() + 4 == std::as_const(v).end()); |
110 | assert(v.begin() + 4 == std::as_const(v).end()); |
111 | |
112 | using Iter = std::ranges::iterator_t<decltype(v)>; |
113 | using ConstIter = std::ranges::iterator_t<const decltype(v)>; |
114 | static_assert(!std::is_same_v<Iter, ConstIter>); |
115 | using Sentinel = std::ranges::sentinel_t<decltype(v)>; |
116 | using ConstSentinel = std::ranges::sentinel_t<const decltype(v)>; |
117 | static_assert(!std::is_same_v<Sentinel, ConstSentinel>); |
118 | |
119 | static_assert(weakly_equality_comparable_with<Iter, Sentinel>); |
120 | static_assert(weakly_equality_comparable_with<ConstIter, Sentinel>); |
121 | static_assert(weakly_equality_comparable_with<Iter, ConstSentinel>); |
122 | static_assert(weakly_equality_comparable_with<ConstIter, ConstSentinel>); |
123 | } |
124 | |
125 | { |
126 | // underlying const/non-const sentinel cannot be compared with non-const/const iterator |
127 | std::ranges::zip_view v{ComparableView(buffer1), ConstIncompatibleView{}}; |
128 | static_assert(!std::ranges::common_range<decltype(v)>); |
129 | static_assert(!simple_view<decltype(v)>); |
130 | |
131 | using Iter = std::ranges::iterator_t<decltype(v)>; |
132 | using ConstIter = std::ranges::iterator_t<const decltype(v)>; |
133 | static_assert(!std::is_same_v<Iter, ConstIter>); |
134 | using Sentinel = std::ranges::sentinel_t<decltype(v)>; |
135 | using ConstSentinel = std::ranges::sentinel_t<const decltype(v)>; |
136 | static_assert(!std::is_same_v<Sentinel, ConstSentinel>); |
137 | |
138 | static_assert(weakly_equality_comparable_with<Iter, Sentinel>); |
139 | static_assert(!weakly_equality_comparable_with<ConstIter, Sentinel>); |
140 | static_assert(!weakly_equality_comparable_with<Iter, ConstSentinel>); |
141 | static_assert(weakly_equality_comparable_with<ConstIter, ConstSentinel>); |
142 | } |
143 | return true; |
144 | } |
145 | |
146 | int main(int, char**) { |
147 | test(); |
148 | static_assert(test()); |
149 | |
150 | return 0; |
151 | } |
152 | |