xref: /llvm-project/libcxx/include/__algorithm/iterator_operations.h (revision f69585235ec85d54e0f3fc41b2d5700430907f99)
1988682a3SNikolas Klauser //===----------------------------------------------------------------------===//
2988682a3SNikolas Klauser //
3988682a3SNikolas Klauser // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4988682a3SNikolas Klauser // See https://llvm.org/LICENSE.txt for license information.
5988682a3SNikolas Klauser // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6988682a3SNikolas Klauser //
7988682a3SNikolas Klauser //===----------------------------------------------------------------------===//
8988682a3SNikolas Klauser 
9295b951eSKonstantin Varlamov #ifndef _LIBCPP___ALGORITHM_ITERATOR_OPERATIONS_H
10295b951eSKonstantin Varlamov #define _LIBCPP___ALGORITHM_ITERATOR_OPERATIONS_H
11988682a3SNikolas Klauser 
12295b951eSKonstantin Varlamov #include <__algorithm/iter_swap.h>
136bdb6422SKonstantin Varlamov #include <__algorithm/ranges_iterator_concept.h>
14a0662176SIuri Chaer #include <__assert>
15988682a3SNikolas Klauser #include <__config>
16988682a3SNikolas Klauser #include <__iterator/advance.h>
17988682a3SNikolas Klauser #include <__iterator/distance.h>
186bdb6422SKonstantin Varlamov #include <__iterator/incrementable_traits.h>
19295b951eSKonstantin Varlamov #include <__iterator/iter_move.h>
20295b951eSKonstantin Varlamov #include <__iterator/iter_swap.h>
21988682a3SNikolas Klauser #include <__iterator/iterator_traits.h>
2296b674f2SHui Xie #include <__iterator/next.h>
2336c746caSKonstantin Varlamov #include <__iterator/prev.h>
2472f57e3aSHui Xie #include <__iterator/readable_traits.h>
25e0a66116SNikolas Klauser #include <__type_traits/enable_if.h>
26e0a66116SNikolas Klauser #include <__type_traits/is_reference.h>
27e0a66116SNikolas Klauser #include <__type_traits/is_same.h>
28e0a66116SNikolas Klauser #include <__type_traits/remove_cvref.h>
29b3afea1cSKonstantin Varlamov #include <__utility/declval.h>
30295b951eSKonstantin Varlamov #include <__utility/forward.h>
31295b951eSKonstantin Varlamov #include <__utility/move.h>
32988682a3SNikolas Klauser 
33988682a3SNikolas Klauser #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
34988682a3SNikolas Klauser #  pragma GCC system_header
35988682a3SNikolas Klauser #endif
36988682a3SNikolas Klauser 
3792e4d679SNicole Rabjohn _LIBCPP_PUSH_MACROS
3892e4d679SNicole Rabjohn #include <__undef_macros>
3992e4d679SNicole Rabjohn 
40988682a3SNikolas Klauser _LIBCPP_BEGIN_NAMESPACE_STD
41988682a3SNikolas Klauser 
429783f28cSLouis Dionne template <class _AlgPolicy>
439783f28cSLouis Dionne struct _IterOps;
44295b951eSKonstantin Varlamov 
454f15267dSNikolas Klauser #if _LIBCPP_STD_VER >= 20
46295b951eSKonstantin Varlamov struct _RangeAlgPolicy {};
47295b951eSKonstantin Varlamov 
48295b951eSKonstantin Varlamov template <>
49295b951eSKonstantin Varlamov struct _IterOps<_RangeAlgPolicy> {
5072f57e3aSHui Xie   template <class _Iter>
51*f6958523SNikolas Klauser   using __value_type _LIBCPP_NODEBUG = iter_value_t<_Iter>;
5272f57e3aSHui Xie 
536bdb6422SKonstantin Varlamov   template <class _Iter>
54*f6958523SNikolas Klauser   using __iterator_category _LIBCPP_NODEBUG = ranges::__iterator_concept<_Iter>;
556bdb6422SKonstantin Varlamov 
566bdb6422SKonstantin Varlamov   template <class _Iter>
57*f6958523SNikolas Klauser   using __difference_type _LIBCPP_NODEBUG = iter_difference_t<_Iter>;
586bdb6422SKonstantin Varlamov 
59988682a3SNikolas Klauser   static constexpr auto advance      = ranges::advance;
60988682a3SNikolas Klauser   static constexpr auto distance     = ranges::distance;
61295b951eSKonstantin Varlamov   static constexpr auto __iter_move  = ranges::iter_move;
62295b951eSKonstantin Varlamov   static constexpr auto iter_swap    = ranges::iter_swap;
6396b674f2SHui Xie   static constexpr auto next         = ranges::next;
6436c746caSKonstantin Varlamov   static constexpr auto prev         = ranges::prev;
65101d1e9bSNikolas Klauser   static constexpr auto __advance_to = ranges::advance;
66988682a3SNikolas Klauser };
67a7c3379cSKonstantin Varlamov 
68988682a3SNikolas Klauser #endif
69988682a3SNikolas Klauser 
70295b951eSKonstantin Varlamov struct _ClassicAlgPolicy {};
71988682a3SNikolas Klauser 
72295b951eSKonstantin Varlamov template <>
73295b951eSKonstantin Varlamov struct _IterOps<_ClassicAlgPolicy> {
7472f57e3aSHui Xie   template <class _Iter>
75*f6958523SNikolas Klauser   using __value_type _LIBCPP_NODEBUG = typename iterator_traits<_Iter>::value_type;
7672f57e3aSHui Xie 
776bdb6422SKonstantin Varlamov   template <class _Iter>
78*f6958523SNikolas Klauser   using __iterator_category _LIBCPP_NODEBUG = typename iterator_traits<_Iter>::iterator_category;
796bdb6422SKonstantin Varlamov 
806bdb6422SKonstantin Varlamov   template <class _Iter>
81*f6958523SNikolas Klauser   using __difference_type _LIBCPP_NODEBUG = typename iterator_traits<_Iter>::difference_type;
826bdb6422SKonstantin Varlamov 
83295b951eSKonstantin Varlamov   // advance
84295b951eSKonstantin Varlamov   template <class _Iter, class _Distance>
859783f28cSLouis Dionne   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static void advance(_Iter& __iter, _Distance __count) {
86295b951eSKonstantin Varlamov     std::advance(__iter, __count);
87988682a3SNikolas Klauser   }
88988682a3SNikolas Klauser 
89295b951eSKonstantin Varlamov   // distance
90295b951eSKonstantin Varlamov   template <class _Iter>
919783f28cSLouis Dionne   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static typename iterator_traits<_Iter>::difference_type
929783f28cSLouis Dionne   distance(_Iter __first, _Iter __last) {
93988682a3SNikolas Klauser     return std::distance(__first, __last);
94988682a3SNikolas Klauser   }
95988682a3SNikolas Klauser 
96b3afea1cSKonstantin Varlamov   template <class _Iter>
97*f6958523SNikolas Klauser   using __deref_t _LIBCPP_NODEBUG = decltype(*std::declval<_Iter&>());
98b3afea1cSKonstantin Varlamov 
99b3afea1cSKonstantin Varlamov   template <class _Iter>
100*f6958523SNikolas Klauser   using __move_t _LIBCPP_NODEBUG = decltype(std::move(*std::declval<_Iter&>()));
101b3afea1cSKonstantin Varlamov 
102295b951eSKonstantin Varlamov   template <class _Iter>
1039783f28cSLouis Dionne   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static void __validate_iter_reference() {
1049783f28cSLouis Dionne     static_assert(
1059783f28cSLouis Dionne         is_same<__deref_t<_Iter>, typename iterator_traits<__remove_cvref_t<_Iter> >::reference>::value,
106b3afea1cSKonstantin Varlamov         "It looks like your iterator's `iterator_traits<It>::reference` does not match the return type of "
107b3afea1cSKonstantin Varlamov         "dereferencing the iterator, i.e., calling `*it`. This is undefined behavior according to [input.iterators] "
108b3afea1cSKonstantin Varlamov         "and can lead to dangling reference issues at runtime, so we are flagging this.");
109b3afea1cSKonstantin Varlamov   }
110b3afea1cSKonstantin Varlamov 
111b3afea1cSKonstantin Varlamov   // iter_move
1129f3e3efdSNikolas Klauser   template <class _Iter, __enable_if_t<is_reference<__deref_t<_Iter> >::value, int> = 0>
1135146b57bSNikolas Klauser   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static
1149783f28cSLouis Dionne       // If the result of dereferencing `_Iter` is a reference type, deduce the result of calling `std::move` on it.
1159783f28cSLouis Dionne       // Note that the C++03 mode doesn't support `decltype(auto)` as the return type.
1169f3e3efdSNikolas Klauser       __move_t<_Iter>
1177abbd622SHui Xie       __iter_move(_Iter&& __i) {
118b3afea1cSKonstantin Varlamov     __validate_iter_reference<_Iter>();
119b3afea1cSKonstantin Varlamov 
120295b951eSKonstantin Varlamov     return std::move(*std::forward<_Iter>(__i));
121295b951eSKonstantin Varlamov   }
122295b951eSKonstantin Varlamov 
1239f3e3efdSNikolas Klauser   template <class _Iter, __enable_if_t<!is_reference<__deref_t<_Iter> >::value, int> = 0>
1245146b57bSNikolas Klauser   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static
125b3afea1cSKonstantin Varlamov       // If the result of dereferencing `_Iter` is a value type, deduce the return value of this function to also be a
1269783f28cSLouis Dionne       // value -- otherwise, after `operator*` returns a temporary, this function would return a dangling reference to
1279783f28cSLouis Dionne       // that temporary. Note that the C++03 mode doesn't support `auto` as the return type.
1289f3e3efdSNikolas Klauser       __deref_t<_Iter>
1297abbd622SHui Xie       __iter_move(_Iter&& __i) {
130b3afea1cSKonstantin Varlamov     __validate_iter_reference<_Iter>();
131b3afea1cSKonstantin Varlamov 
1327abbd622SHui Xie     return *std::forward<_Iter>(__i);
1337abbd622SHui Xie   }
1347abbd622SHui Xie 
135295b951eSKonstantin Varlamov   // iter_swap
136295b951eSKonstantin Varlamov   template <class _Iter1, class _Iter2>
1379783f28cSLouis Dionne   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static void iter_swap(_Iter1&& __a, _Iter2&& __b) {
138295b951eSKonstantin Varlamov     std::iter_swap(std::forward<_Iter1>(__a), std::forward<_Iter2>(__b));
139295b951eSKonstantin Varlamov   }
140295b951eSKonstantin Varlamov 
141295b951eSKonstantin Varlamov   // next
14296b674f2SHui Xie   template <class _Iterator>
1439783f28cSLouis Dionne   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX14 _Iterator next(_Iterator, _Iterator __last) {
14496b674f2SHui Xie     return __last;
14596b674f2SHui Xie   }
146101d1e9bSNikolas Klauser 
147101d1e9bSNikolas Klauser   template <class _Iter>
1489783f28cSLouis Dionne   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX14 __remove_cvref_t<_Iter>
1499783f28cSLouis Dionne   next(_Iter&& __it, typename iterator_traits<__remove_cvref_t<_Iter> >::difference_type __n = 1) {
1508ed702b8SKonstantin Varlamov     return std::next(std::forward<_Iter>(__it), __n);
1518ed702b8SKonstantin Varlamov   }
1528ed702b8SKonstantin Varlamov 
15336c746caSKonstantin Varlamov   // prev
15436c746caSKonstantin Varlamov   template <class _Iter>
1559783f28cSLouis Dionne   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX14 __remove_cvref_t<_Iter>
1569783f28cSLouis Dionne   prev(_Iter&& __iter, typename iterator_traits<__remove_cvref_t<_Iter> >::difference_type __n = 1) {
15736c746caSKonstantin Varlamov     return std::prev(std::forward<_Iter>(__iter), __n);
15836c746caSKonstantin Varlamov   }
15936c746caSKonstantin Varlamov 
1608ed702b8SKonstantin Varlamov   template <class _Iter>
1619783f28cSLouis Dionne   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX14 void __advance_to(_Iter& __first, _Iter __last) {
162101d1e9bSNikolas Klauser     __first = __last;
163101d1e9bSNikolas Klauser   }
164a0662176SIuri Chaer 
165a0662176SIuri Chaer   // advance with sentinel, a la std::ranges::advance
166a0662176SIuri Chaer   template <class _Iter>
167a0662176SIuri Chaer   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static __difference_type<_Iter>
168a0662176SIuri Chaer   __advance_to(_Iter& __iter, __difference_type<_Iter> __count, const _Iter& __sentinel) {
169a0662176SIuri Chaer     return _IterOps::__advance_to(__iter, __count, __sentinel, typename iterator_traits<_Iter>::iterator_category());
170a0662176SIuri Chaer   }
171a0662176SIuri Chaer 
172a0662176SIuri Chaer private:
173a0662176SIuri Chaer   // advance with sentinel, a la std::ranges::advance -- InputIterator specialization
174a0662176SIuri Chaer   template <class _InputIter>
175a0662176SIuri Chaer   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static __difference_type<_InputIter> __advance_to(
176a0662176SIuri Chaer       _InputIter& __iter, __difference_type<_InputIter> __count, const _InputIter& __sentinel, input_iterator_tag) {
177a0662176SIuri Chaer     __difference_type<_InputIter> __dist = 0;
178a0662176SIuri Chaer     for (; __dist < __count && __iter != __sentinel; ++__dist)
179a0662176SIuri Chaer       ++__iter;
180a0662176SIuri Chaer     return __count - __dist;
181a0662176SIuri Chaer   }
182a0662176SIuri Chaer 
183a0662176SIuri Chaer   // advance with sentinel, a la std::ranges::advance -- BidirectionalIterator specialization
184a0662176SIuri Chaer   template <class _BiDirIter>
185a0662176SIuri Chaer   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static __difference_type<_BiDirIter>
186a0662176SIuri Chaer   __advance_to(_BiDirIter& __iter,
187a0662176SIuri Chaer                __difference_type<_BiDirIter> __count,
188a0662176SIuri Chaer                const _BiDirIter& __sentinel,
189a0662176SIuri Chaer                bidirectional_iterator_tag) {
190a0662176SIuri Chaer     __difference_type<_BiDirIter> __dist = 0;
191a0662176SIuri Chaer     if (__count >= 0)
192a0662176SIuri Chaer       for (; __dist < __count && __iter != __sentinel; ++__dist)
193a0662176SIuri Chaer         ++__iter;
194a0662176SIuri Chaer     else
195a0662176SIuri Chaer       for (__count = -__count; __dist < __count && __iter != __sentinel; ++__dist)
196a0662176SIuri Chaer         --__iter;
197a0662176SIuri Chaer     return __count - __dist;
198a0662176SIuri Chaer   }
199a0662176SIuri Chaer 
200a0662176SIuri Chaer   // advance with sentinel, a la std::ranges::advance -- RandomIterator specialization
201a0662176SIuri Chaer   template <class _RandIter>
202a0662176SIuri Chaer   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static __difference_type<_RandIter>
203a0662176SIuri Chaer   __advance_to(_RandIter& __iter,
204a0662176SIuri Chaer                __difference_type<_RandIter> __count,
205a0662176SIuri Chaer                const _RandIter& __sentinel,
206a0662176SIuri Chaer                random_access_iterator_tag) {
207a0662176SIuri Chaer     auto __dist = _IterOps::distance(__iter, __sentinel);
208a0662176SIuri Chaer     _LIBCPP_ASSERT_VALID_INPUT_RANGE(
209a0662176SIuri Chaer         __count == 0 || (__dist < 0) == (__count < 0), "__sentinel must precede __iter when __count < 0");
210a0662176SIuri Chaer     if (__count < 0)
211a0662176SIuri Chaer       __dist = __dist > __count ? __dist : __count;
212a0662176SIuri Chaer     else
213a0662176SIuri Chaer       __dist = __dist < __count ? __dist : __count;
214a0662176SIuri Chaer     __iter += __dist;
215a0662176SIuri Chaer     return __count - __dist;
216a0662176SIuri Chaer   }
217988682a3SNikolas Klauser };
218988682a3SNikolas Klauser 
219eab7be5dSNikolas Klauser template <class _AlgPolicy, class _Iter>
220*f6958523SNikolas Klauser using __policy_iter_diff_t _LIBCPP_NODEBUG = typename _IterOps<_AlgPolicy>::template __difference_type<_Iter>;
221eab7be5dSNikolas Klauser 
222988682a3SNikolas Klauser _LIBCPP_END_NAMESPACE_STD
223988682a3SNikolas Klauser 
22492e4d679SNicole Rabjohn _LIBCPP_POP_MACROS
22592e4d679SNicole Rabjohn 
226295b951eSKonstantin Varlamov #endif // _LIBCPP___ALGORITHM_ITERATOR_OPERATIONS_H
227