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 // UNSUPPORTED: libcpp-has-no-incomplete-ranges
11
12 // template<bool OtherConst>
13 // requires sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>
14 // friend constexpr bool operator==(const iterator<OtherConst>& x, const sentinel& y);
15
16 #include <cassert>
17 #include <compare>
18 #include <ranges>
19 #include <tuple>
20
21 #include "../types.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;
ComparableSentinelComparableSentinel33 constexpr explicit ComparableSentinel(const Iter& it) : iter_(it) {}
34
operator ==(const Iterator & i,const ComparableSentinel & s)35 constexpr friend bool operator==(const Iterator& i, const ComparableSentinel& s) { return base(i) == base(s.iter_); }
36
operator ==(const ConstIterator & i,const ComparableSentinel & s)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
beginComparableView45 constexpr auto begin() { return Iterator(buffer_); }
beginComparableView46 constexpr auto begin() const { return ConstIterator(buffer_); }
endComparableView47 constexpr auto end() { return ComparableSentinel<false>(Iterator(buffer_ + size_)); }
endComparableView48 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 // clang-format off
59 template <class Iter, class Sent>
60 concept EqualComparable = std::invocable<std::equal_to<>, const Iter&, const Sent&>;
61 // clang-format on
62
test()63 constexpr bool test() {
64 int buffer1[4] = {1, 2, 3, 4};
65 int buffer2[5] = {1, 2, 3, 4, 5};
66 int buffer3[8] = {1, 2, 3, 4, 5, 6, 7, 8};
67 {
68 // simple-view: const and non-const have the same iterator/sentinel type
69 std::ranges::zip_view v{SimpleNonCommon(buffer1), SimpleNonCommon(buffer2), SimpleNonCommon(buffer3)};
70 static_assert(!std::ranges::common_range<decltype(v)>);
71 LIBCPP_STATIC_ASSERT(std::ranges::__simple_view<decltype(v)>);
72
73 assert(v.begin() != v.end());
74 assert(v.begin() + 1 != v.end());
75 assert(v.begin() + 2 != v.end());
76 assert(v.begin() + 3 != v.end());
77 assert(v.begin() + 4 == v.end());
78 }
79
80 {
81 // !simple-view: const and non-const have different iterator/sentinel types
82 std::ranges::zip_view v{NonSimpleNonCommon(buffer1), SimpleNonCommon(buffer2), SimpleNonCommon(buffer3)};
83 static_assert(!std::ranges::common_range<decltype(v)>);
84 LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view<decltype(v)>);
85
86 assert(v.begin() != v.end());
87 assert(v.begin() + 4 == v.end());
88
89 // const_iterator (const int*) converted to iterator (int*)
90 assert(v.begin() + 4 == std::as_const(v).end());
91
92 using Iter = std::ranges::iterator_t<decltype(v)>;
93 using ConstIter = std::ranges::iterator_t<const decltype(v)>;
94 static_assert(!std::is_same_v<Iter, ConstIter>);
95 using Sentinel = std::ranges::sentinel_t<decltype(v)>;
96 using ConstSentinel = std::ranges::sentinel_t<const decltype(v)>;
97 static_assert(!std::is_same_v<Sentinel, ConstSentinel>);
98
99 static_assert(EqualComparable<Iter, Sentinel>);
100 static_assert(!EqualComparable<ConstIter, Sentinel>);
101 static_assert(EqualComparable<Iter, ConstSentinel>);
102 static_assert(EqualComparable<ConstIter, ConstSentinel>);
103 }
104
105 {
106 // underlying const/non-const sentinel can be compared with both const/non-const iterator
107 std::ranges::zip_view v{ComparableView(buffer1), ComparableView(buffer2)};
108 static_assert(!std::ranges::common_range<decltype(v)>);
109 LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view<decltype(v)>);
110
111 assert(v.begin() != v.end());
112 assert(v.begin() + 4 == v.end());
113 assert(std::as_const(v).begin() + 4 == v.end());
114 assert(std::as_const(v).begin() + 4 == std::as_const(v).end());
115 assert(v.begin() + 4 == std::as_const(v).end());
116
117 using Iter = std::ranges::iterator_t<decltype(v)>;
118 using ConstIter = std::ranges::iterator_t<const decltype(v)>;
119 static_assert(!std::is_same_v<Iter, ConstIter>);
120 using Sentinel = std::ranges::sentinel_t<decltype(v)>;
121 using ConstSentinel = std::ranges::sentinel_t<const decltype(v)>;
122 static_assert(!std::is_same_v<Sentinel, ConstSentinel>);
123
124 static_assert(EqualComparable<Iter, Sentinel>);
125 static_assert(EqualComparable<ConstIter, Sentinel>);
126 static_assert(EqualComparable<Iter, ConstSentinel>);
127 static_assert(EqualComparable<ConstIter, ConstSentinel>);
128 }
129
130 {
131 // underlying const/non-const sentinel cannot be compared with non-const/const iterator
132 std::ranges::zip_view v{ComparableView(buffer1), ConstIncompatibleView{}};
133 static_assert(!std::ranges::common_range<decltype(v)>);
134 LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view<decltype(v)>);
135
136 using Iter = std::ranges::iterator_t<decltype(v)>;
137 using ConstIter = std::ranges::iterator_t<const decltype(v)>;
138 static_assert(!std::is_same_v<Iter, ConstIter>);
139 using Sentinel = std::ranges::sentinel_t<decltype(v)>;
140 using ConstSentinel = std::ranges::sentinel_t<const decltype(v)>;
141 static_assert(!std::is_same_v<Sentinel, ConstSentinel>);
142
143 static_assert(EqualComparable<Iter, Sentinel>);
144 static_assert(!EqualComparable<ConstIter, Sentinel>);
145 static_assert(!EqualComparable<Iter, ConstSentinel>);
146 static_assert(EqualComparable<ConstIter, ConstSentinel>);
147 }
148 return true;
149 }
150
main(int,char **)151 int main(int, char**) {
152 test();
153 static_assert(test());
154
155 return 0;
156 }
157