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
26template <bool Const>
27using MaybeConstIterator = cpp20_input_iterator<std::conditional_t<Const, const int*, int*>>;
28
29template <bool Const>
30class CrossConstComparableSentinel {
31 using Base = std::conditional_t<Const, const int*, int*>;
32 Base base_;
33
34public:
35 CrossConstComparableSentinel() = default;
36 constexpr explicit CrossConstComparableSentinel(Base base) : base_(base) {}
37
38 friend constexpr bool operator==(const MaybeConstIterator<Const>& it, const CrossConstComparableSentinel& se) {
39 return base(it) == se.base_;
40 }
41
42 friend constexpr bool operator==(const MaybeConstIterator<!Const>& it, const CrossConstComparableSentinel& se) {
43 return base(it) == se.base_;
44 }
45};
46
47static_assert(std::sentinel_for<CrossConstComparableSentinel<true>, MaybeConstIterator<false>>);
48static_assert(std::sentinel_for<CrossConstComparableSentinel<true>, MaybeConstIterator<true>>);
49static_assert(std::sentinel_for<CrossConstComparableSentinel<false>, MaybeConstIterator<false>>);
50static_assert(std::sentinel_for<CrossConstComparableSentinel<false>, MaybeConstIterator<true>>);
51
52struct CrossConstComparableView : std::ranges::view_base {
53 template <std::size_t N>
54 constexpr explicit CrossConstComparableView(int (&arr)[N]) : b_(arr), e_(arr + N) {}
55
56 constexpr MaybeConstIterator<false> begin() { return MaybeConstIterator<false>{b_}; }
57 constexpr CrossConstComparableSentinel<false> end() { return CrossConstComparableSentinel<false>{e_}; }
58
59 constexpr MaybeConstIterator<true> begin() const { return MaybeConstIterator<true>{b_}; }
60 constexpr CrossConstComparableSentinel<true> end() const { return CrossConstComparableSentinel<true>{e_}; }
61
62private:
63 int* b_;
64 int* e_;
65};
66
67static_assert(std::ranges::range<CrossConstComparableView>);
68static_assert(std::ranges::range<const CrossConstComparableView>);
69
70struct 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
78static_assert(std::ranges::range<NonCrossConstComparableView>);
79static_assert(std::ranges::range<const NonCrossConstComparableView>);
80
81constexpr 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
138int main(int, char**) {
139 test();
140 static_assert(test());
141
142 return 0;
143}
144

source code of libcxx/test/std/ranges/range.adaptors/range.take/range.take.sentinel/eq.pass.cpp