2 //===----------------------------------------------------------------------===//
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
8 //===----------------------------------------------------------------------===//
10 #ifndef _LIBCPP___ITERATOR_COUNTED_ITERATOR_H
11 #define _LIBCPP___ITERATOR_COUNTED_ITERATOR_H
14 #include <__concepts/assignable.h>
15 #include <__concepts/common_with.h>
16 #include <__concepts/constructible.h>
17 #include <__concepts/convertible_to.h>
18 #include <__concepts/same_as.h>
20 #include <__iterator/concepts.h>
21 #include <__iterator/default_sentinel.h>
22 #include <__iterator/incrementable_traits.h>
23 #include <__iterator/iter_move.h>
24 #include <__iterator/iter_swap.h>
25 #include <__iterator/iterator_traits.h>
26 #include <__iterator/readable_traits.h>
27 #include <__memory/pointer_traits.h>
28 #include <__type_traits/add_pointer.h>
29 #include <__type_traits/conditional.h>
30 #include <__utility/move.h>
33 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
34 # pragma GCC system_header
38 #include <__undef_macros>
40 _LIBCPP_BEGIN_NAMESPACE_STD
42 #if _LIBCPP_STD_VER >= 20
45 struct __counted_iterator_concept
{};
48 requires requires
{ typename
_Iter::iterator_concept
; }
49 struct __counted_iterator_concept
<_Iter
> {
50 using iterator_concept
= typename
_Iter::iterator_concept
;
54 struct __counted_iterator_category
{};
57 requires requires
{ typename
_Iter::iterator_category
; }
58 struct __counted_iterator_category
<_Iter
> {
59 using iterator_category
= typename
_Iter::iterator_category
;
63 struct __counted_iterator_value_type
{};
65 template<indirectly_readable _Iter
>
66 struct __counted_iterator_value_type
<_Iter
> {
67 using value_type
= iter_value_t
<_Iter
>;
70 template<input_or_output_iterator _Iter
>
71 class counted_iterator
72 : public __counted_iterator_concept
<_Iter
>
73 , public __counted_iterator_category
<_Iter
>
74 , public __counted_iterator_value_type
<_Iter
>
77 _LIBCPP_NO_UNIQUE_ADDRESS _Iter __current_
= _Iter();
78 iter_difference_t
<_Iter
> __count_
= 0;
80 using iterator_type
= _Iter
;
81 using difference_type
= iter_difference_t
<_Iter
>;
84 constexpr counted_iterator() requires default_initializable
<_Iter
> = default;
87 constexpr counted_iterator(_Iter __iter
, iter_difference_t
<_Iter
> __n
)
88 : __current_(_VSTD::move(__iter
)), __count_(__n
) {
89 _LIBCPP_ASSERT_UNCATEGORIZED(__n
>= 0, "__n must not be negative.");
93 requires convertible_to
<const _I2
&, _Iter
>
95 constexpr counted_iterator(const counted_iterator
<_I2
>& __other
)
96 : __current_(__other
.__current_
), __count_(__other
.__count_
) {}
99 requires assignable_from
<_Iter
&, const _I2
&>
100 _LIBCPP_HIDE_FROM_ABI
101 constexpr counted_iterator
& operator=(const counted_iterator
<_I2
>& __other
) {
102 __current_
= __other
.__current_
;
103 __count_
= __other
.__count_
;
107 _LIBCPP_HIDE_FROM_ABI
108 constexpr const _Iter
& base() const& noexcept
{ return __current_
; }
110 _LIBCPP_HIDE_FROM_ABI
111 constexpr _Iter
base() && { return _VSTD::move(__current_
); }
113 _LIBCPP_HIDE_FROM_ABI
114 constexpr iter_difference_t
<_Iter
> count() const noexcept
{ return __count_
; }
116 _LIBCPP_HIDE_FROM_ABI
117 constexpr decltype(auto) operator*() {
118 _LIBCPP_ASSERT_UNCATEGORIZED(__count_
> 0, "Iterator is equal to or past end.");
122 _LIBCPP_HIDE_FROM_ABI
123 constexpr decltype(auto) operator*() const
124 requires __dereferenceable
<const _Iter
>
126 _LIBCPP_ASSERT_UNCATEGORIZED(__count_
> 0, "Iterator is equal to or past end.");
130 _LIBCPP_HIDE_FROM_ABI
131 constexpr auto operator->() const noexcept
132 requires contiguous_iterator
<_Iter
>
134 return _VSTD::to_address(__current_
);
137 _LIBCPP_HIDE_FROM_ABI
138 constexpr counted_iterator
& operator++() {
139 _LIBCPP_ASSERT_UNCATEGORIZED(__count_
> 0, "Iterator already at or past end.");
145 _LIBCPP_HIDE_FROM_ABI
146 decltype(auto) operator++(int) {
147 _LIBCPP_ASSERT_UNCATEGORIZED(__count_
> 0, "Iterator already at or past end.");
149 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
150 try { return __current_
++; }
151 catch(...) { ++__count_
; throw; }
154 #endif // _LIBCPP_HAS_NO_EXCEPTIONS
157 _LIBCPP_HIDE_FROM_ABI
158 constexpr counted_iterator
operator++(int)
159 requires forward_iterator
<_Iter
>
161 _LIBCPP_ASSERT_UNCATEGORIZED(__count_
> 0, "Iterator already at or past end.");
162 counted_iterator __tmp
= *this;
167 _LIBCPP_HIDE_FROM_ABI
168 constexpr counted_iterator
& operator--()
169 requires bidirectional_iterator
<_Iter
>
176 _LIBCPP_HIDE_FROM_ABI
177 constexpr counted_iterator
operator--(int)
178 requires bidirectional_iterator
<_Iter
>
180 counted_iterator __tmp
= *this;
185 _LIBCPP_HIDE_FROM_ABI
186 constexpr counted_iterator
operator+(iter_difference_t
<_Iter
> __n
) const
187 requires random_access_iterator
<_Iter
>
189 return counted_iterator(__current_
+ __n
, __count_
- __n
);
192 _LIBCPP_HIDE_FROM_ABI
193 friend constexpr counted_iterator
operator+(
194 iter_difference_t
<_Iter
> __n
, const counted_iterator
& __x
)
195 requires random_access_iterator
<_Iter
>
200 _LIBCPP_HIDE_FROM_ABI
201 constexpr counted_iterator
& operator+=(iter_difference_t
<_Iter
> __n
)
202 requires random_access_iterator
<_Iter
>
204 _LIBCPP_ASSERT_UNCATEGORIZED(__n
<= __count_
, "Cannot advance iterator past end.");
210 _LIBCPP_HIDE_FROM_ABI
211 constexpr counted_iterator
operator-(iter_difference_t
<_Iter
> __n
) const
212 requires random_access_iterator
<_Iter
>
214 return counted_iterator(__current_
- __n
, __count_
+ __n
);
217 template<common_with
<_Iter
> _I2
>
218 _LIBCPP_HIDE_FROM_ABI
219 friend constexpr iter_difference_t
<_I2
> operator-(
220 const counted_iterator
& __lhs
, const counted_iterator
<_I2
>& __rhs
)
222 return __rhs
.__count_
- __lhs
.__count_
;
225 _LIBCPP_HIDE_FROM_ABI
226 friend constexpr iter_difference_t
<_Iter
> operator-(
227 const counted_iterator
& __lhs
, default_sentinel_t
)
229 return -__lhs
.__count_
;
232 _LIBCPP_HIDE_FROM_ABI
233 friend constexpr iter_difference_t
<_Iter
> operator-(
234 default_sentinel_t
, const counted_iterator
& __rhs
)
236 return __rhs
.__count_
;
239 _LIBCPP_HIDE_FROM_ABI
240 constexpr counted_iterator
& operator-=(iter_difference_t
<_Iter
> __n
)
241 requires random_access_iterator
<_Iter
>
243 _LIBCPP_ASSERT_UNCATEGORIZED(-__n
<= __count_
,
244 "Attempt to subtract too large of a size: "
245 "counted_iterator would be decremented before the "
246 "first element of its range.");
252 _LIBCPP_HIDE_FROM_ABI
253 constexpr decltype(auto) operator[](iter_difference_t
<_Iter
> __n
) const
254 requires random_access_iterator
<_Iter
>
256 _LIBCPP_ASSERT_UNCATEGORIZED(__n
< __count_
, "Subscript argument must be less than size.");
257 return __current_
[__n
];
260 template<common_with
<_Iter
> _I2
>
261 _LIBCPP_HIDE_FROM_ABI
262 friend constexpr bool operator==(
263 const counted_iterator
& __lhs
, const counted_iterator
<_I2
>& __rhs
)
265 return __lhs
.__count_
== __rhs
.__count_
;
268 _LIBCPP_HIDE_FROM_ABI
269 friend constexpr bool operator==(
270 const counted_iterator
& __lhs
, default_sentinel_t
)
272 return __lhs
.__count_
== 0;
275 template<common_with
<_Iter
> _I2
>
276 _LIBCPP_HIDE_FROM_ABI
friend constexpr strong_ordering
operator<=>(
277 const counted_iterator
& __lhs
, const counted_iterator
<_I2
>& __rhs
)
279 return __rhs
.__count_
<=> __lhs
.__count_
;
282 _LIBCPP_HIDE_FROM_ABI
283 friend constexpr iter_rvalue_reference_t
<_Iter
> iter_move(const counted_iterator
& __i
)
284 noexcept(noexcept(ranges::iter_move(__i
.__current_
)))
285 requires input_iterator
<_Iter
>
287 _LIBCPP_ASSERT_UNCATEGORIZED(__i
.__count_
> 0, "Iterator must not be past end of range.");
288 return ranges::iter_move(__i
.__current_
);
291 template<indirectly_swappable
<_Iter
> _I2
>
292 _LIBCPP_HIDE_FROM_ABI
293 friend constexpr void iter_swap(const counted_iterator
& __x
, const counted_iterator
<_I2
>& __y
)
294 noexcept(noexcept(ranges::iter_swap(__x
.__current_
, __y
.__current_
)))
296 _LIBCPP_ASSERT_UNCATEGORIZED(__x
.__count_
> 0 && __y
.__count_
> 0,
297 "Iterators must not be past end of range.");
298 return ranges::iter_swap(__x
.__current_
, __y
.__current_
);
301 _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(counted_iterator
);
303 template<input_iterator _Iter
>
304 requires same_as
<_ITER_TRAITS
<_Iter
>, iterator_traits
<_Iter
>>
305 struct iterator_traits
<counted_iterator
<_Iter
>> : iterator_traits
<_Iter
> {
306 using pointer
= conditional_t
<contiguous_iterator
<_Iter
>,
307 add_pointer_t
<iter_reference_t
<_Iter
>>, void>;
310 #endif // _LIBCPP_STD_VER >= 20
312 _LIBCPP_END_NAMESPACE_STD
316 #endif // _LIBCPP___ITERATOR_COUNTED_ITERATOR_H