1fe6060f1SDimitry Andric // -*- C++ -*- 2fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 3fe6060f1SDimitry Andric // 4fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 6fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7fe6060f1SDimitry Andric // 8fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 9bdd1243dSDimitry Andric 10fe6060f1SDimitry Andric #ifndef _LIBCPP___ITERATOR_COUNTED_ITERATOR_H 11fe6060f1SDimitry Andric #define _LIBCPP___ITERATOR_COUNTED_ITERATOR_H 12fe6060f1SDimitry Andric 1381ad6265SDimitry Andric #include <__assert> 14bdd1243dSDimitry Andric #include <__concepts/assignable.h> 15bdd1243dSDimitry Andric #include <__concepts/common_with.h> 16bdd1243dSDimitry Andric #include <__concepts/constructible.h> 17bdd1243dSDimitry Andric #include <__concepts/convertible_to.h> 18bdd1243dSDimitry Andric #include <__concepts/same_as.h> 19fe6060f1SDimitry Andric #include <__config> 20fe6060f1SDimitry Andric #include <__iterator/concepts.h> 21fe6060f1SDimitry Andric #include <__iterator/default_sentinel.h> 2204eeddc0SDimitry Andric #include <__iterator/incrementable_traits.h> 23fe6060f1SDimitry Andric #include <__iterator/iter_move.h> 24fe6060f1SDimitry Andric #include <__iterator/iter_swap.h> 25fe6060f1SDimitry Andric #include <__iterator/iterator_traits.h> 26fe6060f1SDimitry Andric #include <__iterator/readable_traits.h> 27fe6060f1SDimitry Andric #include <__memory/pointer_traits.h> 28bdd1243dSDimitry Andric #include <__type_traits/add_pointer.h> 29bdd1243dSDimitry Andric #include <__type_traits/conditional.h> 30349cc55cSDimitry Andric #include <__utility/move.h> 31349cc55cSDimitry Andric #include <compare> 32fe6060f1SDimitry Andric 33fe6060f1SDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 34fe6060f1SDimitry Andric # pragma GCC system_header 35fe6060f1SDimitry Andric #endif 36fe6060f1SDimitry Andric 3706c3fb27SDimitry Andric _LIBCPP_PUSH_MACROS 3806c3fb27SDimitry Andric #include <__undef_macros> 3906c3fb27SDimitry Andric 40fe6060f1SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 41fe6060f1SDimitry Andric 4206c3fb27SDimitry Andric #if _LIBCPP_STD_VER >= 20 43fe6060f1SDimitry Andric 44fe6060f1SDimitry Andric template <class> 45fe6060f1SDimitry Andric struct __counted_iterator_concept {}; 46fe6060f1SDimitry Andric 47fe6060f1SDimitry Andric template <class _Iter> 48fe6060f1SDimitry Andric requires requires { typename _Iter::iterator_concept; } 49fe6060f1SDimitry Andric struct __counted_iterator_concept<_Iter> { 50fe6060f1SDimitry Andric using iterator_concept = typename _Iter::iterator_concept; 51fe6060f1SDimitry Andric }; 52fe6060f1SDimitry Andric 53fe6060f1SDimitry Andric template <class> 54fe6060f1SDimitry Andric struct __counted_iterator_category {}; 55fe6060f1SDimitry Andric 56fe6060f1SDimitry Andric template <class _Iter> 57fe6060f1SDimitry Andric requires requires { typename _Iter::iterator_category; } 58fe6060f1SDimitry Andric struct __counted_iterator_category<_Iter> { 59fe6060f1SDimitry Andric using iterator_category = typename _Iter::iterator_category; 60fe6060f1SDimitry Andric }; 61fe6060f1SDimitry Andric 62fe6060f1SDimitry Andric template <class> 63fe6060f1SDimitry Andric struct __counted_iterator_value_type {}; 64fe6060f1SDimitry Andric 65fe6060f1SDimitry Andric template <indirectly_readable _Iter> 66fe6060f1SDimitry Andric struct __counted_iterator_value_type<_Iter> { 67fe6060f1SDimitry Andric using value_type = iter_value_t<_Iter>; 68fe6060f1SDimitry Andric }; 69fe6060f1SDimitry Andric 70fe6060f1SDimitry Andric template <input_or_output_iterator _Iter> 71fe6060f1SDimitry Andric class counted_iterator 72cb14a3feSDimitry Andric : public __counted_iterator_concept<_Iter>, 73cb14a3feSDimitry Andric public __counted_iterator_category<_Iter>, 74cb14a3feSDimitry Andric public __counted_iterator_value_type<_Iter> { 75fe6060f1SDimitry Andric public: 76fe6060f1SDimitry Andric using iterator_type = _Iter; 77fe6060f1SDimitry Andric using difference_type = iter_difference_t<_Iter>; 78fe6060f1SDimitry Andric 79cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr counted_iterator() 80cb14a3feSDimitry Andric requires default_initializable<_Iter> 81cb14a3feSDimitry Andric = default; 82fe6060f1SDimitry Andric 83cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr counted_iterator(_Iter __iter, iter_difference_t<_Iter> __n) 845f757f3fSDimitry Andric : __current_(std::move(__iter)), __count_(__n) { 8506c3fb27SDimitry Andric _LIBCPP_ASSERT_UNCATEGORIZED(__n >= 0, "__n must not be negative."); 86fe6060f1SDimitry Andric } 87fe6060f1SDimitry Andric 88fe6060f1SDimitry Andric template <class _I2> 89fe6060f1SDimitry Andric requires convertible_to<const _I2&, _Iter> 90cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr counted_iterator(const counted_iterator<_I2>& __other) 91fe6060f1SDimitry Andric : __current_(__other.__current_), __count_(__other.__count_) {} 92fe6060f1SDimitry Andric 93fe6060f1SDimitry Andric template <class _I2> 94fe6060f1SDimitry Andric requires assignable_from<_Iter&, const _I2&> 95cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr counted_iterator& operator=(const counted_iterator<_I2>& __other) { 96fe6060f1SDimitry Andric __current_ = __other.__current_; 97fe6060f1SDimitry Andric __count_ = __other.__count_; 98fe6060f1SDimitry Andric return *this; 99fe6060f1SDimitry Andric } 100fe6060f1SDimitry Andric 101cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr const _Iter& base() const& noexcept { return __current_; } 102fe6060f1SDimitry Andric 103cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr _Iter base() && { return std::move(__current_); } 104fe6060f1SDimitry Andric 105cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr iter_difference_t<_Iter> count() const noexcept { return __count_; } 106fe6060f1SDimitry Andric 107cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator*() { 108cb14a3feSDimitry Andric _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__count_ > 0, "Iterator is equal to or past end."); 109fe6060f1SDimitry Andric return *__current_; 110fe6060f1SDimitry Andric } 111fe6060f1SDimitry Andric 112cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator*() const 113fe6060f1SDimitry Andric requires __dereferenceable<const _Iter> 114fe6060f1SDimitry Andric { 115cb14a3feSDimitry Andric _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__count_ > 0, "Iterator is equal to or past end."); 116fe6060f1SDimitry Andric return *__current_; 117fe6060f1SDimitry Andric } 118fe6060f1SDimitry Andric 119cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr auto operator->() const noexcept 120fe6060f1SDimitry Andric requires contiguous_iterator<_Iter> 121fe6060f1SDimitry Andric { 1225f757f3fSDimitry Andric return std::to_address(__current_); 123fe6060f1SDimitry Andric } 124fe6060f1SDimitry Andric 125cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr counted_iterator& operator++() { 12606c3fb27SDimitry Andric _LIBCPP_ASSERT_UNCATEGORIZED(__count_ > 0, "Iterator already at or past end."); 127fe6060f1SDimitry Andric ++__current_; 128fe6060f1SDimitry Andric --__count_; 129fe6060f1SDimitry Andric return *this; 130fe6060f1SDimitry Andric } 131fe6060f1SDimitry Andric 132*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator++(int) { 13306c3fb27SDimitry Andric _LIBCPP_ASSERT_UNCATEGORIZED(__count_ > 0, "Iterator already at or past end."); 134fe6060f1SDimitry Andric --__count_; 13506c3fb27SDimitry Andric # ifndef _LIBCPP_HAS_NO_EXCEPTIONS 136cb14a3feSDimitry Andric try { 137cb14a3feSDimitry Andric return __current_++; 138cb14a3feSDimitry Andric } catch (...) { 139cb14a3feSDimitry Andric ++__count_; 140cb14a3feSDimitry Andric throw; 141cb14a3feSDimitry Andric } 142fe6060f1SDimitry Andric # else 143fe6060f1SDimitry Andric return __current_++; 14406c3fb27SDimitry Andric # endif // _LIBCPP_HAS_NO_EXCEPTIONS 145fe6060f1SDimitry Andric } 146fe6060f1SDimitry Andric 147cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr counted_iterator operator++(int) 148fe6060f1SDimitry Andric requires forward_iterator<_Iter> 149fe6060f1SDimitry Andric { 15006c3fb27SDimitry Andric _LIBCPP_ASSERT_UNCATEGORIZED(__count_ > 0, "Iterator already at or past end."); 151fe6060f1SDimitry Andric counted_iterator __tmp = *this; 152fe6060f1SDimitry Andric ++*this; 153fe6060f1SDimitry Andric return __tmp; 154fe6060f1SDimitry Andric } 155fe6060f1SDimitry Andric 156cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr counted_iterator& operator--() 157fe6060f1SDimitry Andric requires bidirectional_iterator<_Iter> 158fe6060f1SDimitry Andric { 159fe6060f1SDimitry Andric --__current_; 160fe6060f1SDimitry Andric ++__count_; 161fe6060f1SDimitry Andric return *this; 162fe6060f1SDimitry Andric } 163fe6060f1SDimitry Andric 164cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr counted_iterator operator--(int) 165fe6060f1SDimitry Andric requires bidirectional_iterator<_Iter> 166fe6060f1SDimitry Andric { 167fe6060f1SDimitry Andric counted_iterator __tmp = *this; 168fe6060f1SDimitry Andric --*this; 169fe6060f1SDimitry Andric return __tmp; 170fe6060f1SDimitry Andric } 171fe6060f1SDimitry Andric 172cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr counted_iterator operator+(iter_difference_t<_Iter> __n) const 173fe6060f1SDimitry Andric requires random_access_iterator<_Iter> 174fe6060f1SDimitry Andric { 175fe6060f1SDimitry Andric return counted_iterator(__current_ + __n, __count_ - __n); 176fe6060f1SDimitry Andric } 177fe6060f1SDimitry Andric 178cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI friend constexpr counted_iterator 179cb14a3feSDimitry Andric operator+(iter_difference_t<_Iter> __n, const counted_iterator& __x) 180fe6060f1SDimitry Andric requires random_access_iterator<_Iter> 181fe6060f1SDimitry Andric { 182fe6060f1SDimitry Andric return __x + __n; 183fe6060f1SDimitry Andric } 184fe6060f1SDimitry Andric 185cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr counted_iterator& operator+=(iter_difference_t<_Iter> __n) 186fe6060f1SDimitry Andric requires random_access_iterator<_Iter> 187fe6060f1SDimitry Andric { 18806c3fb27SDimitry Andric _LIBCPP_ASSERT_UNCATEGORIZED(__n <= __count_, "Cannot advance iterator past end."); 189fe6060f1SDimitry Andric __current_ += __n; 190fe6060f1SDimitry Andric __count_ -= __n; 191fe6060f1SDimitry Andric return *this; 192fe6060f1SDimitry Andric } 193fe6060f1SDimitry Andric 194cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr counted_iterator operator-(iter_difference_t<_Iter> __n) const 195fe6060f1SDimitry Andric requires random_access_iterator<_Iter> 196fe6060f1SDimitry Andric { 197fe6060f1SDimitry Andric return counted_iterator(__current_ - __n, __count_ + __n); 198fe6060f1SDimitry Andric } 199fe6060f1SDimitry Andric 200fe6060f1SDimitry Andric template <common_with<_Iter> _I2> 201cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI friend constexpr iter_difference_t<_I2> 202cb14a3feSDimitry Andric operator-(const counted_iterator& __lhs, const counted_iterator<_I2>& __rhs) { 203fe6060f1SDimitry Andric return __rhs.__count_ - __lhs.__count_; 204fe6060f1SDimitry Andric } 205fe6060f1SDimitry Andric 206cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI friend constexpr iter_difference_t<_Iter> 207cb14a3feSDimitry Andric operator-(const counted_iterator& __lhs, default_sentinel_t) { 208fe6060f1SDimitry Andric return -__lhs.__count_; 209fe6060f1SDimitry Andric } 210fe6060f1SDimitry Andric 211cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI friend constexpr iter_difference_t<_Iter> 212cb14a3feSDimitry Andric operator-(default_sentinel_t, const counted_iterator& __rhs) { 213fe6060f1SDimitry Andric return __rhs.__count_; 214fe6060f1SDimitry Andric } 215fe6060f1SDimitry Andric 216cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr counted_iterator& operator-=(iter_difference_t<_Iter> __n) 217fe6060f1SDimitry Andric requires random_access_iterator<_Iter> 218fe6060f1SDimitry Andric { 219cb14a3feSDimitry Andric _LIBCPP_ASSERT_UNCATEGORIZED( 220cb14a3feSDimitry Andric -__n <= __count_, 22106c3fb27SDimitry Andric "Attempt to subtract too large of a size: " 222fe6060f1SDimitry Andric "counted_iterator would be decremented before the " 223fe6060f1SDimitry Andric "first element of its range."); 224fe6060f1SDimitry Andric __current_ -= __n; 225fe6060f1SDimitry Andric __count_ += __n; 226fe6060f1SDimitry Andric return *this; 227fe6060f1SDimitry Andric } 228fe6060f1SDimitry Andric 229cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](iter_difference_t<_Iter> __n) const 230fe6060f1SDimitry Andric requires random_access_iterator<_Iter> 231fe6060f1SDimitry Andric { 232cb14a3feSDimitry Andric _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n < __count_, "Subscript argument must be less than size."); 233fe6060f1SDimitry Andric return __current_[__n]; 234fe6060f1SDimitry Andric } 235fe6060f1SDimitry Andric 236fe6060f1SDimitry Andric template <common_with<_Iter> _I2> 237cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI friend constexpr bool 238cb14a3feSDimitry Andric operator==(const counted_iterator& __lhs, const counted_iterator<_I2>& __rhs) { 239fe6060f1SDimitry Andric return __lhs.__count_ == __rhs.__count_; 240fe6060f1SDimitry Andric } 241fe6060f1SDimitry Andric 242cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const counted_iterator& __lhs, default_sentinel_t) { 243fe6060f1SDimitry Andric return __lhs.__count_ == 0; 244fe6060f1SDimitry Andric } 245fe6060f1SDimitry Andric 246fe6060f1SDimitry Andric template <common_with<_Iter> _I2> 247cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI friend constexpr strong_ordering 248cb14a3feSDimitry Andric operator<=>(const counted_iterator& __lhs, const counted_iterator<_I2>& __rhs) { 249fe6060f1SDimitry Andric return __rhs.__count_ <=> __lhs.__count_; 250fe6060f1SDimitry Andric } 251fe6060f1SDimitry Andric 252cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI friend constexpr iter_rvalue_reference_t<_Iter> 253cb14a3feSDimitry Andric iter_move(const counted_iterator& __i) noexcept(noexcept(ranges::iter_move(__i.__current_))) 254fe6060f1SDimitry Andric requires input_iterator<_Iter> 255fe6060f1SDimitry Andric { 256cb14a3feSDimitry Andric _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i.__count_ > 0, "Iterator must not be past end of range."); 257fe6060f1SDimitry Andric return ranges::iter_move(__i.__current_); 258fe6060f1SDimitry Andric } 259fe6060f1SDimitry Andric 260fe6060f1SDimitry Andric template <indirectly_swappable<_Iter> _I2> 261cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI friend constexpr void 262cb14a3feSDimitry Andric iter_swap(const counted_iterator& __x, 263cb14a3feSDimitry Andric const counted_iterator<_I2>& __y) noexcept(noexcept(ranges::iter_swap(__x.__current_, __y.__current_))) { 264cb14a3feSDimitry Andric _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( 265cb14a3feSDimitry Andric __x.__count_ > 0 && __y.__count_ > 0, "Iterators must not be past end of range."); 266fe6060f1SDimitry Andric return ranges::iter_swap(__x.__current_, __y.__current_); 267fe6060f1SDimitry Andric } 2685f757f3fSDimitry Andric 2695f757f3fSDimitry Andric private: 2705f757f3fSDimitry Andric _LIBCPP_NO_UNIQUE_ADDRESS _Iter __current_ = _Iter(); 2715f757f3fSDimitry Andric iter_difference_t<_Iter> __count_ = 0; 2725f757f3fSDimitry Andric template <input_or_output_iterator _OtherIter> 2735f757f3fSDimitry Andric friend class counted_iterator; 274fe6060f1SDimitry Andric }; 275bdd1243dSDimitry Andric _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(counted_iterator); 276fe6060f1SDimitry Andric 277fe6060f1SDimitry Andric template <input_iterator _Iter> 278fe6060f1SDimitry Andric requires same_as<_ITER_TRAITS<_Iter>, iterator_traits<_Iter>> 279fe6060f1SDimitry Andric struct iterator_traits<counted_iterator<_Iter>> : iterator_traits<_Iter> { 280cb14a3feSDimitry Andric using pointer = conditional_t<contiguous_iterator<_Iter>, add_pointer_t<iter_reference_t<_Iter>>, void>; 281fe6060f1SDimitry Andric }; 282fe6060f1SDimitry Andric 28306c3fb27SDimitry Andric #endif // _LIBCPP_STD_VER >= 20 284fe6060f1SDimitry Andric 285fe6060f1SDimitry Andric _LIBCPP_END_NAMESPACE_STD 286fe6060f1SDimitry Andric 28706c3fb27SDimitry Andric _LIBCPP_POP_MACROS 28806c3fb27SDimitry Andric 289fe6060f1SDimitry Andric #endif // _LIBCPP___ITERATOR_COUNTED_ITERATOR_H 290