xref: /freebsd-src/contrib/llvm-project/libcxx/include/__iterator/counted_iterator.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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