Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / libcxx / include / __iterator / counted_iterator.h
blob41b7e57d28c1451ab9c42cf6688630ad31cf4302
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 //===----------------------------------------------------------------------===//
10 #ifndef _LIBCPP___ITERATOR_COUNTED_ITERATOR_H
11 #define _LIBCPP___ITERATOR_COUNTED_ITERATOR_H
13 #include <__assert>
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>
19 #include <__config>
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>
31 #include <compare>
33 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
34 # pragma GCC system_header
35 #endif
37 _LIBCPP_PUSH_MACROS
38 #include <__undef_macros>
40 _LIBCPP_BEGIN_NAMESPACE_STD
42 #if _LIBCPP_STD_VER >= 20
44 template<class>
45 struct __counted_iterator_concept {};
47 template<class _Iter>
48 requires requires { typename _Iter::iterator_concept; }
49 struct __counted_iterator_concept<_Iter> {
50 using iterator_concept = typename _Iter::iterator_concept;
53 template<class>
54 struct __counted_iterator_category {};
56 template<class _Iter>
57 requires requires { typename _Iter::iterator_category; }
58 struct __counted_iterator_category<_Iter> {
59 using iterator_category = typename _Iter::iterator_category;
62 template<class>
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>
76 public:
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>;
83 _LIBCPP_HIDE_FROM_ABI
84 constexpr counted_iterator() requires default_initializable<_Iter> = default;
86 _LIBCPP_HIDE_FROM_ABI
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.");
92 template<class _I2>
93 requires convertible_to<const _I2&, _Iter>
94 _LIBCPP_HIDE_FROM_ABI
95 constexpr counted_iterator(const counted_iterator<_I2>& __other)
96 : __current_(__other.__current_), __count_(__other.__count_) {}
98 template<class _I2>
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_;
104 return *this;
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.");
119 return *__current_;
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.");
127 return *__current_;
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.");
140 ++__current_;
141 --__count_;
142 return *this;
145 _LIBCPP_HIDE_FROM_ABI
146 decltype(auto) operator++(int) {
147 _LIBCPP_ASSERT_UNCATEGORIZED(__count_ > 0, "Iterator already at or past end.");
148 --__count_;
149 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
150 try { return __current_++; }
151 catch(...) { ++__count_; throw; }
152 #else
153 return __current_++;
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;
163 ++*this;
164 return __tmp;
167 _LIBCPP_HIDE_FROM_ABI
168 constexpr counted_iterator& operator--()
169 requires bidirectional_iterator<_Iter>
171 --__current_;
172 ++__count_;
173 return *this;
176 _LIBCPP_HIDE_FROM_ABI
177 constexpr counted_iterator operator--(int)
178 requires bidirectional_iterator<_Iter>
180 counted_iterator __tmp = *this;
181 --*this;
182 return __tmp;
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>
197 return __x + __n;
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.");
205 __current_ += __n;
206 __count_ -= __n;
207 return *this;
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.");
247 __current_ -= __n;
248 __count_ += __n;
249 return *this;
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
314 _LIBCPP_POP_MACROS
316 #endif // _LIBCPP___ITERATOR_COUNTED_ITERATOR_H