xref: /freebsd-src/contrib/llvm-project/libcxx/include/__algorithm/iterator_operations.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
181ad6265SDimitry Andric //===----------------------------------------------------------------------===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric 
9753f127fSDimitry Andric #ifndef _LIBCPP___ALGORITHM_ITERATOR_OPERATIONS_H
10753f127fSDimitry Andric #define _LIBCPP___ALGORITHM_ITERATOR_OPERATIONS_H
1181ad6265SDimitry Andric 
12753f127fSDimitry Andric #include <__algorithm/iter_swap.h>
1361cfbce3SDimitry Andric #include <__algorithm/ranges_iterator_concept.h>
14*0fca6ea1SDimitry Andric #include <__assert>
1581ad6265SDimitry Andric #include <__config>
1681ad6265SDimitry Andric #include <__iterator/advance.h>
1781ad6265SDimitry Andric #include <__iterator/distance.h>
1861cfbce3SDimitry Andric #include <__iterator/incrementable_traits.h>
19753f127fSDimitry Andric #include <__iterator/iter_move.h>
20753f127fSDimitry Andric #include <__iterator/iter_swap.h>
2181ad6265SDimitry Andric #include <__iterator/iterator_traits.h>
22753f127fSDimitry Andric #include <__iterator/next.h>
2361cfbce3SDimitry Andric #include <__iterator/prev.h>
2461cfbce3SDimitry Andric #include <__iterator/readable_traits.h>
25bdd1243dSDimitry Andric #include <__type_traits/enable_if.h>
26bdd1243dSDimitry Andric #include <__type_traits/is_reference.h>
27bdd1243dSDimitry Andric #include <__type_traits/is_same.h>
28bdd1243dSDimitry Andric #include <__type_traits/remove_cvref.h>
2961cfbce3SDimitry Andric #include <__utility/declval.h>
30753f127fSDimitry Andric #include <__utility/forward.h>
31753f127fSDimitry Andric #include <__utility/move.h>
3281ad6265SDimitry Andric 
3381ad6265SDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
3481ad6265SDimitry Andric #  pragma GCC system_header
3581ad6265SDimitry Andric #endif
3681ad6265SDimitry Andric 
3706c3fb27SDimitry Andric _LIBCPP_PUSH_MACROS
3806c3fb27SDimitry Andric #include <__undef_macros>
3906c3fb27SDimitry Andric 
4081ad6265SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
4181ad6265SDimitry Andric 
42cb14a3feSDimitry Andric template <class _AlgPolicy>
43cb14a3feSDimitry Andric struct _IterOps;
44753f127fSDimitry Andric 
4506c3fb27SDimitry Andric #if _LIBCPP_STD_VER >= 20
46753f127fSDimitry Andric struct _RangeAlgPolicy {};
47753f127fSDimitry Andric 
48753f127fSDimitry Andric template <>
49753f127fSDimitry Andric struct _IterOps<_RangeAlgPolicy> {
5061cfbce3SDimitry Andric   template <class _Iter>
5161cfbce3SDimitry Andric   using __value_type = iter_value_t<_Iter>;
5261cfbce3SDimitry Andric 
5361cfbce3SDimitry Andric   template <class _Iter>
5461cfbce3SDimitry Andric   using __iterator_category = ranges::__iterator_concept<_Iter>;
5561cfbce3SDimitry Andric 
5661cfbce3SDimitry Andric   template <class _Iter>
5761cfbce3SDimitry Andric   using __difference_type = iter_difference_t<_Iter>;
5861cfbce3SDimitry Andric 
5981ad6265SDimitry Andric   static constexpr auto advance      = ranges::advance;
6081ad6265SDimitry Andric   static constexpr auto distance     = ranges::distance;
61753f127fSDimitry Andric   static constexpr auto __iter_move  = ranges::iter_move;
62753f127fSDimitry Andric   static constexpr auto iter_swap    = ranges::iter_swap;
63753f127fSDimitry Andric   static constexpr auto next         = ranges::next;
6461cfbce3SDimitry Andric   static constexpr auto prev         = ranges::prev;
65753f127fSDimitry Andric   static constexpr auto __advance_to = ranges::advance;
6681ad6265SDimitry Andric };
67fcaf7f86SDimitry Andric 
6881ad6265SDimitry Andric #endif
6981ad6265SDimitry Andric 
70753f127fSDimitry Andric struct _ClassicAlgPolicy {};
7181ad6265SDimitry Andric 
72753f127fSDimitry Andric template <>
73753f127fSDimitry Andric struct _IterOps<_ClassicAlgPolicy> {
7461cfbce3SDimitry Andric   template <class _Iter>
7561cfbce3SDimitry Andric   using __value_type = typename iterator_traits<_Iter>::value_type;
7661cfbce3SDimitry Andric 
7761cfbce3SDimitry Andric   template <class _Iter>
7861cfbce3SDimitry Andric   using __iterator_category = typename iterator_traits<_Iter>::iterator_category;
7961cfbce3SDimitry Andric 
8061cfbce3SDimitry Andric   template <class _Iter>
8161cfbce3SDimitry Andric   using __difference_type = typename iterator_traits<_Iter>::difference_type;
8261cfbce3SDimitry Andric 
83753f127fSDimitry Andric   // advance
84753f127fSDimitry Andric   template <class _Iter, class _Distance>
85cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static void advance(_Iter& __iter, _Distance __count) {
86753f127fSDimitry Andric     std::advance(__iter, __count);
8781ad6265SDimitry Andric   }
8881ad6265SDimitry Andric 
89753f127fSDimitry Andric   // distance
90753f127fSDimitry Andric   template <class _Iter>
91cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static typename iterator_traits<_Iter>::difference_type
92cb14a3feSDimitry Andric   distance(_Iter __first, _Iter __last) {
9381ad6265SDimitry Andric     return std::distance(__first, __last);
9481ad6265SDimitry Andric   }
9581ad6265SDimitry Andric 
9661cfbce3SDimitry Andric   template <class _Iter>
9761cfbce3SDimitry Andric   using __deref_t = decltype(*std::declval<_Iter&>());
9861cfbce3SDimitry Andric 
9961cfbce3SDimitry Andric   template <class _Iter>
10061cfbce3SDimitry Andric   using __move_t = decltype(std::move(*std::declval<_Iter&>()));
10161cfbce3SDimitry Andric 
102753f127fSDimitry Andric   template <class _Iter>
103cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static void __validate_iter_reference() {
104cb14a3feSDimitry Andric     static_assert(
105cb14a3feSDimitry Andric         is_same<__deref_t<_Iter>, typename iterator_traits<__remove_cvref_t<_Iter> >::reference>::value,
10661cfbce3SDimitry Andric         "It looks like your iterator's `iterator_traits<It>::reference` does not match the return type of "
10761cfbce3SDimitry Andric         "dereferencing the iterator, i.e., calling `*it`. This is undefined behavior according to [input.iterators] "
10861cfbce3SDimitry Andric         "and can lead to dangling reference issues at runtime, so we are flagging this.");
10961cfbce3SDimitry Andric   }
11061cfbce3SDimitry Andric 
11161cfbce3SDimitry Andric   // iter_move
1125f757f3fSDimitry Andric   template <class _Iter, __enable_if_t<is_reference<__deref_t<_Iter> >::value, int> = 0>
113bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static
114cb14a3feSDimitry Andric       // If the result of dereferencing `_Iter` is a reference type, deduce the result of calling `std::move` on it.
115cb14a3feSDimitry Andric       // Note that the C++03 mode doesn't support `decltype(auto)` as the return type.
1165f757f3fSDimitry Andric       __move_t<_Iter>
117fcaf7f86SDimitry Andric       __iter_move(_Iter&& __i) {
11861cfbce3SDimitry Andric     __validate_iter_reference<_Iter>();
11961cfbce3SDimitry Andric 
120753f127fSDimitry Andric     return std::move(*std::forward<_Iter>(__i));
121753f127fSDimitry Andric   }
122753f127fSDimitry Andric 
1235f757f3fSDimitry Andric   template <class _Iter, __enable_if_t<!is_reference<__deref_t<_Iter> >::value, int> = 0>
124bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static
12561cfbce3SDimitry Andric       // If the result of dereferencing `_Iter` is a value type, deduce the return value of this function to also be a
126cb14a3feSDimitry Andric       // value -- otherwise, after `operator*` returns a temporary, this function would return a dangling reference to
127cb14a3feSDimitry Andric       // that temporary. Note that the C++03 mode doesn't support `auto` as the return type.
1285f757f3fSDimitry Andric       __deref_t<_Iter>
129fcaf7f86SDimitry Andric       __iter_move(_Iter&& __i) {
13061cfbce3SDimitry Andric     __validate_iter_reference<_Iter>();
13161cfbce3SDimitry Andric 
132fcaf7f86SDimitry Andric     return *std::forward<_Iter>(__i);
133fcaf7f86SDimitry Andric   }
134fcaf7f86SDimitry Andric 
135753f127fSDimitry Andric   // iter_swap
136753f127fSDimitry Andric   template <class _Iter1, class _Iter2>
137cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static void iter_swap(_Iter1&& __a, _Iter2&& __b) {
138753f127fSDimitry Andric     std::iter_swap(std::forward<_Iter1>(__a), std::forward<_Iter2>(__b));
139753f127fSDimitry Andric   }
140753f127fSDimitry Andric 
141753f127fSDimitry Andric   // next
142753f127fSDimitry Andric   template <class _Iterator>
143cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX14 _Iterator next(_Iterator, _Iterator __last) {
144753f127fSDimitry Andric     return __last;
145753f127fSDimitry Andric   }
146753f127fSDimitry Andric 
147753f127fSDimitry Andric   template <class _Iter>
148cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX14 __remove_cvref_t<_Iter>
149cb14a3feSDimitry Andric   next(_Iter&& __it, typename iterator_traits<__remove_cvref_t<_Iter> >::difference_type __n = 1) {
150fcaf7f86SDimitry Andric     return std::next(std::forward<_Iter>(__it), __n);
151fcaf7f86SDimitry Andric   }
152fcaf7f86SDimitry Andric 
15361cfbce3SDimitry Andric   // prev
15461cfbce3SDimitry Andric   template <class _Iter>
155cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX14 __remove_cvref_t<_Iter>
156cb14a3feSDimitry Andric   prev(_Iter&& __iter, typename iterator_traits<__remove_cvref_t<_Iter> >::difference_type __n = 1) {
15761cfbce3SDimitry Andric     return std::prev(std::forward<_Iter>(__iter), __n);
15861cfbce3SDimitry Andric   }
15961cfbce3SDimitry Andric 
160fcaf7f86SDimitry Andric   template <class _Iter>
161cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX14 void __advance_to(_Iter& __first, _Iter __last) {
162753f127fSDimitry Andric     __first = __last;
163753f127fSDimitry Andric   }
164*0fca6ea1SDimitry Andric 
165*0fca6ea1SDimitry Andric   // advance with sentinel, a la std::ranges::advance
166*0fca6ea1SDimitry Andric   template <class _Iter>
167*0fca6ea1SDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static __difference_type<_Iter>
168*0fca6ea1SDimitry Andric   __advance_to(_Iter& __iter, __difference_type<_Iter> __count, const _Iter& __sentinel) {
169*0fca6ea1SDimitry Andric     return _IterOps::__advance_to(__iter, __count, __sentinel, typename iterator_traits<_Iter>::iterator_category());
170*0fca6ea1SDimitry Andric   }
171*0fca6ea1SDimitry Andric 
172*0fca6ea1SDimitry Andric private:
173*0fca6ea1SDimitry Andric   // advance with sentinel, a la std::ranges::advance -- InputIterator specialization
174*0fca6ea1SDimitry Andric   template <class _InputIter>
175*0fca6ea1SDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static __difference_type<_InputIter> __advance_to(
176*0fca6ea1SDimitry Andric       _InputIter& __iter, __difference_type<_InputIter> __count, const _InputIter& __sentinel, input_iterator_tag) {
177*0fca6ea1SDimitry Andric     __difference_type<_InputIter> __dist = 0;
178*0fca6ea1SDimitry Andric     for (; __dist < __count && __iter != __sentinel; ++__dist)
179*0fca6ea1SDimitry Andric       ++__iter;
180*0fca6ea1SDimitry Andric     return __count - __dist;
181*0fca6ea1SDimitry Andric   }
182*0fca6ea1SDimitry Andric 
183*0fca6ea1SDimitry Andric   // advance with sentinel, a la std::ranges::advance -- BidirectionalIterator specialization
184*0fca6ea1SDimitry Andric   template <class _BiDirIter>
185*0fca6ea1SDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static __difference_type<_BiDirIter>
186*0fca6ea1SDimitry Andric   __advance_to(_BiDirIter& __iter,
187*0fca6ea1SDimitry Andric                __difference_type<_BiDirIter> __count,
188*0fca6ea1SDimitry Andric                const _BiDirIter& __sentinel,
189*0fca6ea1SDimitry Andric                bidirectional_iterator_tag) {
190*0fca6ea1SDimitry Andric     __difference_type<_BiDirIter> __dist = 0;
191*0fca6ea1SDimitry Andric     if (__count >= 0)
192*0fca6ea1SDimitry Andric       for (; __dist < __count && __iter != __sentinel; ++__dist)
193*0fca6ea1SDimitry Andric         ++__iter;
194*0fca6ea1SDimitry Andric     else
195*0fca6ea1SDimitry Andric       for (__count = -__count; __dist < __count && __iter != __sentinel; ++__dist)
196*0fca6ea1SDimitry Andric         --__iter;
197*0fca6ea1SDimitry Andric     return __count - __dist;
198*0fca6ea1SDimitry Andric   }
199*0fca6ea1SDimitry Andric 
200*0fca6ea1SDimitry Andric   // advance with sentinel, a la std::ranges::advance -- RandomIterator specialization
201*0fca6ea1SDimitry Andric   template <class _RandIter>
202*0fca6ea1SDimitry Andric   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static __difference_type<_RandIter>
203*0fca6ea1SDimitry Andric   __advance_to(_RandIter& __iter,
204*0fca6ea1SDimitry Andric                __difference_type<_RandIter> __count,
205*0fca6ea1SDimitry Andric                const _RandIter& __sentinel,
206*0fca6ea1SDimitry Andric                random_access_iterator_tag) {
207*0fca6ea1SDimitry Andric     auto __dist = _IterOps::distance(__iter, __sentinel);
208*0fca6ea1SDimitry Andric     _LIBCPP_ASSERT_VALID_INPUT_RANGE(
209*0fca6ea1SDimitry Andric         __count == 0 || (__dist < 0) == (__count < 0), "__sentinel must precede __iter when __count < 0");
210*0fca6ea1SDimitry Andric     if (__count < 0)
211*0fca6ea1SDimitry Andric       __dist = __dist > __count ? __dist : __count;
212*0fca6ea1SDimitry Andric     else
213*0fca6ea1SDimitry Andric       __dist = __dist < __count ? __dist : __count;
214*0fca6ea1SDimitry Andric     __iter += __dist;
215*0fca6ea1SDimitry Andric     return __count - __dist;
216*0fca6ea1SDimitry Andric   }
21781ad6265SDimitry Andric };
21881ad6265SDimitry Andric 
21981ad6265SDimitry Andric _LIBCPP_END_NAMESPACE_STD
22081ad6265SDimitry Andric 
22106c3fb27SDimitry Andric _LIBCPP_POP_MACROS
22206c3fb27SDimitry Andric 
223753f127fSDimitry Andric #endif // _LIBCPP___ALGORITHM_ITERATOR_OPERATIONS_H
224