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 // 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 <concepts>
18 #include <ranges>
19 
20 #include "../types.h"
21 
22 template <class Iter, class Sent>
23 concept EqualityComparable = std::invocable<std::equal_to<>, const Iter&, const Sent&> ;
24 
25 using Iterator = random_access_iterator<BufferView<int*>*>;
26 using ConstIterator = random_access_iterator<const BufferView<int*>*>;
27 
28 template <bool Const>
29 struct ConstComparableSentinel {
30 
31   using Iter = std::conditional_t<Const, ConstIterator, Iterator>;
32   Iter iter_;
33 
34   explicit ConstComparableSentinel() = default;
35   constexpr explicit ConstComparableSentinel(const Iter& it) : iter_(it) {}
36 
37   constexpr friend bool operator==(const Iterator& i, const ConstComparableSentinel& s) {
38     return base(i) == base(s.iter_);
39   }
40 
41   constexpr friend bool operator==(const ConstIterator& i, const ConstComparableSentinel& s) {
42     return base(i) == base(s.iter_);
43   }
44 };
45 
46 struct ConstComparableView : BufferView<BufferView<int*>*> {
47   using BufferView<BufferView<int*>*>::BufferView;
48 
49   constexpr auto begin() { return Iterator(data_); }
50   constexpr auto begin() const { return ConstIterator(data_); }
51   constexpr auto end() { return ConstComparableSentinel<false>(Iterator(data_ + size_)); }
52   constexpr auto end() const { return ConstComparableSentinel<true>(ConstIterator(data_ + size_)); }
53 };
54 
55 static_assert(EqualityComparable<std::ranges::iterator_t<ConstComparableView>,
56                                  std::ranges::sentinel_t<const ConstComparableView>>);
57 static_assert(EqualityComparable<std::ranges::iterator_t<const ConstComparableView>,
58                                  std::ranges::sentinel_t<ConstComparableView>>);
59 
60 constexpr bool test() {
61   int buffer[4][4] = {{1111, 2222, 3333, 4444}, {555, 666, 777, 888}, {99, 1010, 1111, 1212}, {13, 14, 15, 16}};
62 
63   {
64     ChildView children[4] = {ChildView(buffer[0]), ChildView(buffer[1]), ChildView(buffer[2]), ChildView(buffer[3])};
65     auto jv = std::ranges::join_view(ParentView(children));
66     assert(jv.end() == std::ranges::next(jv.begin(), 16));
67     static_assert(!EqualityComparable<decltype(std::as_const(jv).begin()), decltype(jv.end())>);
68     static_assert(!EqualityComparable<decltype(jv.begin()), decltype(std::as_const(jv).end())>);
69   }
70 
71   {
72     CopyableChild children[4] = {CopyableChild(buffer[0]), CopyableChild(buffer[1]), CopyableChild(buffer[2]),
73                                  CopyableChild(buffer[3])};
74     const auto jv = std::ranges::join_view(ParentView(children));
75     assert(jv.end() == std::ranges::next(jv.begin(), 16));
76   }
77 
78   // test iterator<Const> == sentinel<!Const>
79   {
80     BufferView<int*> inners[] = {buffer[0], buffer[1]};
81     ConstComparableView outer(inners);
82     auto jv = std::ranges::join_view(outer);
83     assert(jv.end() == std::ranges::next(jv.begin(), 8));
84     assert(std::as_const(jv).end() == std::ranges::next(jv.begin(), 8));
85     assert(jv.end() == std::ranges::next(std::as_const(jv).begin(), 8));
86   }
87 
88   return true;
89 }
90 
91 int main(int, char**) {
92   test();
93   static_assert(test());
94 
95   return 0;
96 }
97