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