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(sized_sentinel_for<sentinel_t<maybe-const<Const, Views>>, 14 // iterator_t<maybe-const<OtherConst, Views>>>&&...) 15 // friend constexpr common_type_t<range_difference_t<maybe-const<OtherConst, Views>>...> 16 // operator-(const iterator<OtherConst>&, const sentinel&) 17 // 18 // template <bool OtherConst> 19 // requires(sized_sentinel_for<sentinel_t<maybe-const<Const, Views>>, 20 // iterator_t<maybe-const<OtherConst, Views>>>&&...) 21 // friend constexpr common_type_t<range_difference_t<maybe-const<OtherConst, Views>>...> 22 // operator-(const sentinel&, const iterator<OtherConst>&) 23 24 #include <cassert> 25 #include <concepts> 26 #include <functional> 27 #include <ranges> 28 #include <tuple> 29 30 #include "../types.h" 31 32 template <class Base = int*> 33 struct convertible_forward_sized_iterator { 34 Base it_ = nullptr; 35 36 using iterator_category = std::forward_iterator_tag; 37 using value_type = int; 38 using difference_type = intptr_t; 39 40 convertible_forward_sized_iterator() = default; 41 constexpr convertible_forward_sized_iterator(Base it) : it_(it) {} 42 43 template <std::convertible_to<Base> U> 44 constexpr convertible_forward_sized_iterator(const convertible_forward_sized_iterator<U>& it) : it_(it.it_) {} 45 46 constexpr decltype(*Base{}) operator*() const { return *it_; } 47 48 constexpr convertible_forward_sized_iterator& operator++() { 49 ++it_; 50 return *this; 51 } 52 constexpr convertible_forward_sized_iterator operator++(int) { return forward_sized_iterator(it_++); } 53 54 friend constexpr bool operator==(const convertible_forward_sized_iterator&, 55 const convertible_forward_sized_iterator&) = default; 56 57 friend constexpr difference_type operator-(const convertible_forward_sized_iterator& x, 58 const convertible_forward_sized_iterator& y) { 59 return x.it_ - y.it_; 60 } 61 }; 62 static_assert(std::forward_iterator<convertible_forward_sized_iterator<>>); 63 64 template <class Base> 65 struct convertible_sized_sentinel { 66 Base base_; 67 explicit convertible_sized_sentinel() = default; 68 constexpr convertible_sized_sentinel(const Base& it) : base_(it) {} 69 70 template <std::convertible_to<Base> U> 71 constexpr convertible_sized_sentinel(const convertible_sized_sentinel<U>& other) : base_(other.base_) {} 72 73 template <class U> 74 requires(std::convertible_to<Base, U> || std::convertible_to<U, Base>) 75 friend constexpr bool operator==(const convertible_sized_sentinel& s, const U& base) { 76 return s.base_ == base; 77 } 78 template <class U> 79 requires(std::convertible_to<Base, U> || std::convertible_to<U, Base>) 80 friend constexpr auto operator-(const convertible_sized_sentinel& s, const U& i) { 81 return s.base_ - i; 82 } 83 84 template <class U> 85 requires(std::convertible_to<Base, U> || std::convertible_to<U, Base>) 86 friend constexpr auto operator-(const U& i, const convertible_sized_sentinel& s) { 87 return i - s.base_; 88 } 89 }; 90 static_assert(std::sized_sentinel_for<convertible_sized_sentinel<convertible_forward_sized_iterator<>>, 91 convertible_forward_sized_iterator<>>); 92 static_assert(std::sized_sentinel_for<convertible_sized_sentinel<convertible_forward_sized_iterator<const int*>>, 93 convertible_forward_sized_iterator<int*>>); 94 static_assert(std::sized_sentinel_for<convertible_sized_sentinel<convertible_forward_sized_iterator<int*>>, 95 convertible_forward_sized_iterator<const int*>>); 96 97 struct ConstCompatibleForwardSized : IntBufferView { 98 using IntBufferView::IntBufferView; 99 100 using iterator = convertible_forward_sized_iterator<int*>; 101 using const_iterator = convertible_forward_sized_iterator<const int*>; 102 103 constexpr iterator begin() { return {buffer_}; } 104 constexpr const_iterator begin() const { return {buffer_}; } 105 constexpr convertible_sized_sentinel<iterator> end() { return iterator{buffer_ + size_}; } 106 constexpr convertible_sized_sentinel<const_iterator> end() const { return const_iterator{buffer_ + size_}; } 107 }; 108 109 // clang-format off 110 template <class T, class U> 111 concept HasMinus = std::invocable<std::minus<>,const T&, const U&>; 112 113 template <class T> 114 concept SentinelHasMinus = HasMinus<std::ranges::sentinel_t<T>, std::ranges::iterator_t<T>>; 115 // clang-format on 116 117 constexpr bool test() { 118 int buffer1[5] = {1, 2, 3, 4, 5}; 119 120 { 121 // simple-view 122 std::ranges::zip_view v{ForwardSizedNonCommon(buffer1)}; 123 static_assert(!std::ranges::common_range<decltype(v)>); 124 LIBCPP_STATIC_ASSERT(std::ranges::__simple_view<decltype(v)>); 125 126 auto it = v.begin(); 127 auto st = v.end(); 128 assert(st - it == 5); 129 assert(st - std::ranges::next(it, 1) == 4); 130 131 assert(it - st == -5); 132 assert(std::ranges::next(it, 1) - st == -4); 133 static_assert(SentinelHasMinus<decltype(v)>); 134 } 135 136 { 137 // shortest range 138 std::ranges::zip_view v(std::views::iota(0, 3), ForwardSizedNonCommon(buffer1)); 139 static_assert(!std::ranges::common_range<decltype(v)>); 140 auto it = v.begin(); 141 auto st = v.end(); 142 assert(st - it == 3); 143 assert(st - std::ranges::next(it, 1) == 2); 144 145 assert(it - st == -3); 146 assert(std::ranges::next(it, 1) - st == -2); 147 static_assert(SentinelHasMinus<decltype(v)>); 148 } 149 150 { 151 // underlying sentinel does not model sized_sentinel_for 152 std::ranges::zip_view v(std::views::iota(0), SizedRandomAccessView(buffer1)); 153 static_assert(!std::ranges::common_range<decltype(v)>); 154 static_assert(!SentinelHasMinus<decltype(v)>); 155 } 156 157 { 158 // const imcompatible: 159 // underlying const sentinels cannot substract underlying iterators 160 // underlying sentinels cannot substract underlying const iterators 161 std::ranges::zip_view v(NonSimpleForwardSizedNonCommon{buffer1}); 162 static_assert(!std::ranges::common_range<decltype(v)>); 163 LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view<decltype(v)>); 164 165 using Iter = std::ranges::iterator_t<decltype(v)>; 166 using ConstIter = std::ranges::iterator_t<const decltype(v)>; 167 static_assert(!std::is_same_v<Iter, ConstIter>); 168 using Sentinel = std::ranges::sentinel_t<decltype(v)>; 169 using ConstSentinel = std::ranges::sentinel_t<const decltype(v)>; 170 static_assert(!std::is_same_v<Sentinel, ConstSentinel>); 171 172 static_assert(HasMinus<Iter, Sentinel>); 173 static_assert(HasMinus<Sentinel, Iter>); 174 static_assert(HasMinus<ConstIter, ConstSentinel>); 175 static_assert(HasMinus<ConstSentinel, ConstIter>); 176 auto it = v.begin(); 177 auto const_it = std::as_const(v).begin(); 178 auto st = v.end(); 179 auto const_st = std::as_const(v).end(); 180 assert(it - st == -5); 181 assert(st - it == 5); 182 assert(const_it - const_st == -5); 183 assert(const_st - const_it == 5); 184 185 static_assert(!HasMinus<Iter, ConstSentinel>); 186 static_assert(!HasMinus<ConstSentinel, Iter>); 187 static_assert(!HasMinus<ConstIter, Sentinel>); 188 static_assert(!HasMinus<Sentinel, ConstIter>); 189 } 190 191 { 192 // const compatible allow non-const to const conversion 193 std::ranges::zip_view v(ConstCompatibleForwardSized{buffer1}); 194 static_assert(!std::ranges::common_range<decltype(v)>); 195 LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view<decltype(v)>); 196 197 using Iter = std::ranges::iterator_t<decltype(v)>; 198 using ConstIter = std::ranges::iterator_t<const decltype(v)>; 199 static_assert(!std::is_same_v<Iter, ConstIter>); 200 using Sentinel = std::ranges::sentinel_t<decltype(v)>; 201 using ConstSentinel = std::ranges::sentinel_t<const decltype(v)>; 202 static_assert(!std::is_same_v<Sentinel, ConstSentinel>); 203 204 static_assert(HasMinus<Iter, Sentinel>); 205 static_assert(HasMinus<Sentinel, Iter>); 206 static_assert(HasMinus<ConstIter, ConstSentinel>); 207 static_assert(HasMinus<ConstSentinel, ConstIter>); 208 static_assert(HasMinus<Iter, ConstSentinel>); 209 static_assert(HasMinus<ConstSentinel, Iter>); 210 static_assert(HasMinus<ConstIter, Sentinel>); 211 static_assert(HasMinus<Sentinel, ConstIter>); 212 213 auto it = v.begin(); 214 auto const_it = std::as_const(v).begin(); 215 auto st = v.end(); 216 auto const_st = std::as_const(v).end(); 217 218 assert(it - st == -5); 219 assert(st - it == 5); 220 assert(const_it - const_st == -5); 221 assert(const_st - const_it == 5); 222 assert(it - const_st == -5); 223 assert(const_st - it == 5); 224 assert(const_it - st == -5); 225 assert(st - const_it == 5); 226 } 227 return true; 228 } 229 230 int main(int, char**) { 231 test(); 232 static_assert(test()); 233 234 return 0; 235 } 236