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