xref: /llvm-project/libcxx/test/std/ranges/range.adaptors/range.take/range.take.sentinel/eq.pass.cpp (revision 808d794a45e169601ff16f72beae2f7bd79342a2)
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 // friend constexpr bool operator==(const CI<Const>& y, const sentinel& x);
12 // template<bool OtherConst = !Const>
13 //   requires sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>
14 // friend constexpr bool operator==(const CI<OtherConst>& y, const sentinel& x);
15 
16 #include <cassert>
17 #include <cstddef>
18 #include <ranges>
19 #include <type_traits>
20 #include <utility>
21 
22 #include "test_comparisons.h"
23 #include "test_iterators.h"
24 #include "test_range.h"
25 
26 template <bool Const>
27 using MaybeConstIterator = cpp20_input_iterator<std::conditional_t<Const, const int*, int*>>;
28 
29 template <bool Const>
30 class CrossConstComparableSentinel {
31   using Base = std::conditional_t<Const, const int*, int*>;
32   Base base_;
33 
34 public:
35   CrossConstComparableSentinel() = default;
CrossConstComparableSentinel(Base base)36   constexpr explicit CrossConstComparableSentinel(Base base) : base_(base) {}
37 
operator ==(const MaybeConstIterator<Const> & it,const CrossConstComparableSentinel & se)38   friend constexpr bool operator==(const MaybeConstIterator<Const>& it, const CrossConstComparableSentinel& se) {
39     return base(it) == se.base_;
40   }
41 
operator ==(const MaybeConstIterator<!Const> & it,const CrossConstComparableSentinel & se)42   friend constexpr bool operator==(const MaybeConstIterator<!Const>& it, const CrossConstComparableSentinel& se) {
43     return base(it) == se.base_;
44   }
45 };
46 
47 static_assert(std::sentinel_for<CrossConstComparableSentinel<true>, MaybeConstIterator<false>>);
48 static_assert(std::sentinel_for<CrossConstComparableSentinel<true>, MaybeConstIterator<true>>);
49 static_assert(std::sentinel_for<CrossConstComparableSentinel<false>, MaybeConstIterator<false>>);
50 static_assert(std::sentinel_for<CrossConstComparableSentinel<false>, MaybeConstIterator<true>>);
51 
52 struct CrossConstComparableView : std::ranges::view_base {
53   template <std::size_t N>
CrossConstComparableViewCrossConstComparableView54   constexpr explicit CrossConstComparableView(int (&arr)[N]) : b_(arr), e_(arr + N) {}
55 
beginCrossConstComparableView56   constexpr MaybeConstIterator<false> begin() { return MaybeConstIterator<false>{b_}; }
endCrossConstComparableView57   constexpr CrossConstComparableSentinel<false> end() { return CrossConstComparableSentinel<false>{e_}; }
58 
beginCrossConstComparableView59   constexpr MaybeConstIterator<true> begin() const { return MaybeConstIterator<true>{b_}; }
endCrossConstComparableView60   constexpr CrossConstComparableSentinel<true> end() const { return CrossConstComparableSentinel<true>{e_}; }
61 
62 private:
63   int* b_;
64   int* e_;
65 };
66 
67 static_assert(std::ranges::range<CrossConstComparableView>);
68 static_assert(std::ranges::range<const CrossConstComparableView>);
69 
70 struct NonCrossConstComparableView : std::ranges::view_base {
71   int* begin();
72   sentinel_wrapper<int*> end();
73 
74   long* begin() const;
75   sentinel_wrapper<long*> end() const;
76 };
77 
78 static_assert(std::ranges::range<NonCrossConstComparableView>);
79 static_assert(std::ranges::range<const NonCrossConstComparableView>);
80 
test()81 constexpr bool test() {
82   int buffer[8]                      = {1, 2, 3, 4, 5, 6, 7, 8};
83   using CrossConstComparableTakeView = std::ranges::take_view<CrossConstComparableView>;
84 
85   {   // Compare CI<Const> with sentinel<Const>
86     { // Const == true
87       AssertEqualityReturnBool<std::ranges::iterator_t<const CrossConstComparableTakeView>,
88                                std::ranges::sentinel_t<const CrossConstComparableTakeView>>();
89       const CrossConstComparableTakeView tv(CrossConstComparableView{buffer}, 4);
90       assert(testEquality(std::ranges::next(tv.begin(), 4), tv.end(), true));
91       assert(testEquality(tv.begin(), tv.end(), false));
92     }
93 
94     { // Const == false
95       AssertEqualityReturnBool<std::ranges::iterator_t<CrossConstComparableTakeView>,
96                                std::ranges::sentinel_t<CrossConstComparableTakeView>>();
97       CrossConstComparableTakeView tv(CrossConstComparableView{buffer}, 4);
98       assert(testEquality(std::ranges::next(tv.begin(), 4), tv.end(), true));
99       assert(testEquality(std::ranges::next(tv.begin(), 1), tv.end(), false));
100     }
101   }
102 
103   {   // Compare CI<Const> with sentinel<!Const>
104     { // Const == true
105       AssertEqualityReturnBool<std::ranges::iterator_t<const CrossConstComparableTakeView>,
106                                std::ranges::sentinel_t<CrossConstComparableTakeView>>();
107       CrossConstComparableTakeView tv(CrossConstComparableView{buffer}, 4);
108       assert(testEquality(std::ranges::next(std::as_const(tv).begin(), 4), tv.end(), true));
109       assert(testEquality(std::ranges::next(std::as_const(tv).begin(), 2), tv.end(), false));
110     }
111 
112     { // Const == false
113       AssertEqualityReturnBool<std::ranges::iterator_t<CrossConstComparableTakeView>,
114                                std::ranges::sentinel_t<const CrossConstComparableTakeView>>();
115       CrossConstComparableTakeView tv(CrossConstComparableView{buffer}, 4);
116       assert(testEquality(std::ranges::next(tv.begin(), 4), std::as_const(tv).end(), true));
117       assert(testEquality(std::ranges::next(tv.begin(), 3), std::as_const(tv).end(), false));
118     }
119   }
120 
121   { // Check invalid comparisons between CI<Const> and sentinel<!Const>
122     using TakeView = std::ranges::take_view<NonCrossConstComparableView>;
123     static_assert(
124         !weakly_equality_comparable_with<std::ranges::iterator_t<const TakeView>, std::ranges::sentinel_t<TakeView>>);
125     static_assert(
126         !weakly_equality_comparable_with<std::ranges::iterator_t<TakeView>, std::ranges::sentinel_t<const TakeView>>);
127 
128     // Those should be valid
129     static_assert(
130         weakly_equality_comparable_with<std::ranges::iterator_t<TakeView>, std::ranges::sentinel_t<TakeView>>);
131     static_assert(weakly_equality_comparable_with<std::ranges::iterator_t<const TakeView>,
132                                                   std::ranges::sentinel_t<const TakeView>>);
133   }
134 
135   return true;
136 }
137 
main(int,char **)138 int main(int, char**) {
139   test();
140   static_assert(test());
141 
142   return 0;
143 }
144