| 1 | // -*- C++ -*- |
| 2 | //===----------------------------------------------------------------------===// |
| 3 | // |
| 4 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 5 | // See https://llvm.org/LICENSE.txt for license information. |
| 6 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | |
| 10 | #ifndef _LIBCPP___RANGES_ENUMERATE_VIEW_H |
| 11 | #define _LIBCPP___RANGES_ENUMERATE_VIEW_H |
| 12 | |
| 13 | #include <__concepts/constructible.h> |
| 14 | #include <__concepts/convertible_to.h> |
| 15 | #include <__config> |
| 16 | #include <__iterator/concepts.h> |
| 17 | #include <__iterator/distance.h> |
| 18 | #include <__iterator/iter_move.h> |
| 19 | #include <__iterator/iterator_traits.h> |
| 20 | #include <__ranges/access.h> |
| 21 | #include <__ranges/all.h> |
| 22 | #include <__ranges/concepts.h> |
| 23 | #include <__ranges/enable_borrowed_range.h> |
| 24 | #include <__ranges/range_adaptor.h> |
| 25 | #include <__ranges/size.h> |
| 26 | #include <__ranges/view_interface.h> |
| 27 | #include <__type_traits/maybe_const.h> |
| 28 | #include <__utility/forward.h> |
| 29 | #include <__utility/move.h> |
| 30 | #include <tuple> |
| 31 | |
| 32 | #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
| 33 | # pragma GCC system_header |
| 34 | #endif |
| 35 | |
| 36 | _LIBCPP_PUSH_MACROS |
| 37 | #include <__undef_macros> |
| 38 | |
| 39 | _LIBCPP_BEGIN_NAMESPACE_STD |
| 40 | |
| 41 | #if _LIBCPP_STD_VER >= 23 |
| 42 | |
| 43 | namespace ranges { |
| 44 | |
| 45 | // [concept.object] |
| 46 | |
| 47 | template <class _Rp> |
| 48 | concept __range_with_movable_references = |
| 49 | input_range<_Rp> && std::move_constructible<range_reference_t<_Rp>> && |
| 50 | std::move_constructible<range_rvalue_reference_t<_Rp>>; |
| 51 | |
| 52 | // [range.enumerate.view] |
| 53 | |
| 54 | template <view _View> |
| 55 | requires __range_with_movable_references<_View> |
| 56 | class enumerate_view : public view_interface<enumerate_view<_View>> { |
| 57 | _View __base_ = _View(); |
| 58 | |
| 59 | // [range.enumerate.iterator] |
| 60 | template <bool _Const> |
| 61 | class __iterator; |
| 62 | |
| 63 | // [range.enumerate.sentinel] |
| 64 | template <bool _Const> |
| 65 | class __sentinel; |
| 66 | |
| 67 | public: |
| 68 | _LIBCPP_HIDE_FROM_ABI constexpr enumerate_view() |
| 69 | requires default_initializable<_View> |
| 70 | = default; |
| 71 | _LIBCPP_HIDE_FROM_ABI constexpr explicit enumerate_view(_View __base) : __base_(std::move(__base)) {} |
| 72 | |
| 73 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() |
| 74 | requires(!__simple_view<_View>) |
| 75 | { |
| 76 | return __iterator<false>(ranges::begin(__base_), 0); |
| 77 | } |
| 78 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const |
| 79 | requires __range_with_movable_references<const _View> |
| 80 | { |
| 81 | return __iterator<true>(ranges::begin(__base_), 0); |
| 82 | } |
| 83 | |
| 84 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() |
| 85 | requires(!__simple_view<_View>) |
| 86 | { |
| 87 | if constexpr (forward_range<_View> && common_range<_View> && sized_range<_View>) |
| 88 | return __iterator<false>(ranges::end(__base_), ranges::distance(__base_)); |
| 89 | else |
| 90 | return __sentinel<false>(ranges::end(__base_)); |
| 91 | } |
| 92 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() const |
| 93 | requires __range_with_movable_references<const _View> |
| 94 | { |
| 95 | if constexpr (forward_range<_View> && common_range<const _View> && sized_range<const _View>) |
| 96 | return __iterator<true>(ranges::end(__base_), ranges::distance(__base_)); |
| 97 | else |
| 98 | return __sentinel<true>(ranges::end(__base_)); |
| 99 | } |
| 100 | |
| 101 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() |
| 102 | requires sized_range<_View> |
| 103 | { |
| 104 | return ranges::size(__base_); |
| 105 | } |
| 106 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const |
| 107 | requires sized_range<const _View> |
| 108 | { |
| 109 | return ranges::size(__base_); |
| 110 | } |
| 111 | |
| 112 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() const& |
| 113 | requires copy_constructible<_View> |
| 114 | { |
| 115 | return __base_; |
| 116 | } |
| 117 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); } |
| 118 | }; |
| 119 | |
| 120 | template <class _Range> |
| 121 | enumerate_view(_Range&&) -> enumerate_view<views::all_t<_Range>>; |
| 122 | |
| 123 | // [range.enumerate.iterator] |
| 124 | |
| 125 | template <view _View> |
| 126 | requires __range_with_movable_references<_View> |
| 127 | template <bool _Const> |
| 128 | class enumerate_view<_View>::__iterator { |
| 129 | using _Base _LIBCPP_NODEBUG = __maybe_const<_Const, _View>; |
| 130 | |
| 131 | static consteval auto __get_iterator_concept() { |
| 132 | if constexpr (random_access_range<_Base>) { |
| 133 | return random_access_iterator_tag{}; |
| 134 | } else if constexpr (bidirectional_range<_Base>) { |
| 135 | return bidirectional_iterator_tag{}; |
| 136 | } else if constexpr (forward_range<_Base>) { |
| 137 | return forward_iterator_tag{}; |
| 138 | } else { |
| 139 | return input_iterator_tag{}; |
| 140 | } |
| 141 | } |
| 142 | |
| 143 | friend class enumerate_view<_View>; |
| 144 | |
| 145 | public: |
| 146 | using iterator_category = input_iterator_tag; |
| 147 | using iterator_concept = decltype(__get_iterator_concept()); |
| 148 | using difference_type = range_difference_t<_Base>; |
| 149 | using value_type = tuple<difference_type, range_value_t<_Base>>; |
| 150 | |
| 151 | private: |
| 152 | using __reference_type _LIBCPP_NODEBUG = tuple<difference_type, range_reference_t<_Base>>; |
| 153 | |
| 154 | iterator_t<_Base> __current_ = iterator_t<_Base>(); |
| 155 | difference_type __pos_ = 0; |
| 156 | |
| 157 | _LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(iterator_t<_Base> __current, difference_type __pos) |
| 158 | : __current_(std::move(__current)), __pos_(__pos) {} |
| 159 | |
| 160 | public: |
| 161 | _LIBCPP_HIDE_FROM_ABI __iterator() |
| 162 | requires default_initializable<iterator_t<_Base>> |
| 163 | = default; |
| 164 | |
| 165 | _LIBCPP_HIDE_FROM_ABI constexpr __iterator(__iterator<!_Const> __i) |
| 166 | requires _Const && convertible_to<iterator_t<_View>, iterator_t<_Base>> |
| 167 | : __current_(std::move(__i.__current_)), __pos_(__i.__pos_) {} |
| 168 | |
| 169 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const iterator_t<_Base>& base() const& noexcept { return __current_; } |
| 170 | |
| 171 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_Base> base() && { return std::move(__current_); } |
| 172 | |
| 173 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr difference_type index() const noexcept { return __pos_; } |
| 174 | |
| 175 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator*() const { return __reference_type(__pos_, *__current_); } |
| 176 | |
| 177 | _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() { |
| 178 | ++__current_; |
| 179 | ++__pos_; |
| 180 | return *this; |
| 181 | } |
| 182 | |
| 183 | _LIBCPP_HIDE_FROM_ABI constexpr void operator++(int) { return ++*this; } |
| 184 | |
| 185 | _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int) |
| 186 | requires forward_range<_Base> |
| 187 | { |
| 188 | auto __temp = *this; |
| 189 | ++*this; |
| 190 | return __temp; |
| 191 | } |
| 192 | |
| 193 | _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator--() |
| 194 | requires bidirectional_range<_Base> |
| 195 | { |
| 196 | --__current_; |
| 197 | --__pos_; |
| 198 | return *this; |
| 199 | } |
| 200 | |
| 201 | _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator--(int) |
| 202 | requires bidirectional_range<_Base> |
| 203 | { |
| 204 | auto __temp = *this; |
| 205 | --*this; |
| 206 | return *__temp; |
| 207 | } |
| 208 | |
| 209 | _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator+=(difference_type __n) |
| 210 | requires random_access_range<_Base> |
| 211 | { |
| 212 | __current_ += __n; |
| 213 | __pos_ += __n; |
| 214 | return *this; |
| 215 | } |
| 216 | |
| 217 | _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator-=(difference_type __n) |
| 218 | requires random_access_range<_Base> |
| 219 | { |
| 220 | __current_ -= __n; |
| 221 | __pos_ -= __n; |
| 222 | return *this; |
| 223 | } |
| 224 | |
| 225 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator[](difference_type __n) const |
| 226 | requires random_access_range<_Base> |
| 227 | { |
| 228 | return __reference_type(__pos_ + __n, __current_[__n]); |
| 229 | } |
| 230 | |
| 231 | _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, const __iterator& __y) noexcept { |
| 232 | return __x.__pos_ == __y.__pos_; |
| 233 | } |
| 234 | |
| 235 | _LIBCPP_HIDE_FROM_ABI friend constexpr strong_ordering |
| 236 | operator<=>(const __iterator& __x, const __iterator& __y) noexcept { |
| 237 | return __x.__pos_ <=> __y.__pos_; |
| 238 | } |
| 239 | |
| 240 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(const __iterator& __i, difference_type __n) |
| 241 | requires random_access_range<_Base> |
| 242 | { |
| 243 | auto __temp = __i; |
| 244 | __temp += __n; |
| 245 | return __temp; |
| 246 | } |
| 247 | |
| 248 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(difference_type __n, const __iterator& __i) |
| 249 | requires random_access_range<_Base> |
| 250 | { |
| 251 | return __i + __n; |
| 252 | } |
| 253 | |
| 254 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator-(const __iterator& __i, difference_type __n) |
| 255 | requires random_access_range<_Base> |
| 256 | { |
| 257 | auto __temp = __i; |
| 258 | __temp -= __n; |
| 259 | return __temp; |
| 260 | } |
| 261 | |
| 262 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type |
| 263 | operator-(const __iterator& __x, const __iterator& __y) noexcept { |
| 264 | return __x.__pos_ - __y.__pos_; |
| 265 | } |
| 266 | |
| 267 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto iter_move(const __iterator& __i) noexcept( |
| 268 | noexcept(ranges::iter_move(__i.__current_)) && is_nothrow_move_constructible_v<range_rvalue_reference_t<_Base>>) { |
| 269 | return tuple<difference_type, range_rvalue_reference_t<_Base>>(__i.__pos_, ranges::iter_move(__i.__current_)); |
| 270 | } |
| 271 | }; |
| 272 | |
| 273 | // [range.enumerate.sentinel] |
| 274 | |
| 275 | template <view _View> |
| 276 | requires __range_with_movable_references<_View> |
| 277 | template <bool _Const> |
| 278 | class enumerate_view<_View>::__sentinel { |
| 279 | using _Base _LIBCPP_NODEBUG = __maybe_const<_Const, _View>; |
| 280 | |
| 281 | sentinel_t<_Base> __end_ = sentinel_t<_Base>(); |
| 282 | |
| 283 | _LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(sentinel_t<_Base> __end) : __end_(std::move(__end)) {} |
| 284 | |
| 285 | friend class enumerate_view<_View>; |
| 286 | |
| 287 | public: |
| 288 | _LIBCPP_HIDE_FROM_ABI __sentinel() = default; |
| 289 | |
| 290 | _LIBCPP_HIDE_FROM_ABI constexpr __sentinel(__sentinel<!_Const> __other) |
| 291 | requires _Const && convertible_to<sentinel_t<_View>, sentinel_t<_Base>> |
| 292 | : __end_(std::move(__other.__end_)) {} |
| 293 | |
| 294 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr sentinel_t<_Base> base() const { return __end_; } |
| 295 | |
| 296 | template <bool _OtherConst> |
| 297 | requires sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>> |
| 298 | _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator<_OtherConst>& __x, const __sentinel& __y) { |
| 299 | return __x.__current_ == __y.__end_; |
| 300 | } |
| 301 | |
| 302 | template <bool _OtherConst> |
| 303 | requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>> |
| 304 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr range_difference_t<__maybe_const<_OtherConst, _View>> |
| 305 | operator-(const __iterator<_OtherConst>& __x, const __sentinel& __y) { |
| 306 | return __x.__current_ - __y.__end_; |
| 307 | } |
| 308 | |
| 309 | template <bool _OtherConst> |
| 310 | requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>> |
| 311 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr range_difference_t<__maybe_const<_OtherConst, _View>> |
| 312 | operator-(const __sentinel& __x, const __iterator<_OtherConst>& __y) { |
| 313 | return __x.__end_ - __y.__current_; |
| 314 | } |
| 315 | }; |
| 316 | |
| 317 | template <class _View> |
| 318 | constexpr bool enable_borrowed_range<enumerate_view<_View>> = enable_borrowed_range<_View>; |
| 319 | |
| 320 | namespace views { |
| 321 | namespace __enumerate { |
| 322 | |
| 323 | // [range.enumerate.overview] |
| 324 | |
| 325 | struct __fn : __range_adaptor_closure<__fn> { |
| 326 | template <class _Range> |
| 327 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto |
| 328 | operator()(_Range&& __range) noexcept(noexcept(enumerate_view<views::all_t<_Range>>(std::forward<_Range>(__range)))) |
| 329 | -> decltype(/*--------------------------*/ enumerate_view<views::all_t<_Range>>(std::forward<_Range>(__range))) { |
| 330 | return /*---------------------------------*/ enumerate_view<views::all_t<_Range>>(std::forward<_Range>(__range)); |
| 331 | } |
| 332 | }; |
| 333 | |
| 334 | } // namespace __enumerate |
| 335 | |
| 336 | inline namespace __cpo { |
| 337 | |
| 338 | inline constexpr auto enumerate = __enumerate::__fn{}; |
| 339 | |
| 340 | } // namespace __cpo |
| 341 | } // namespace views |
| 342 | } // namespace ranges |
| 343 | |
| 344 | #endif // _LIBCPP_STD_VER >= 23 |
| 345 | |
| 346 | _LIBCPP_END_NAMESPACE_STD |
| 347 | |
| 348 | _LIBCPP_POP_MACROS |
| 349 | |
| 350 | #endif // _LIBCPP___RANGES_ENUMERATE_VIEW_H |
| 351 | |