xref: /llvm-project/libcxx/include/__algorithm/iterator_operations.h (revision b3afea1ce0bd3c9293edae67c1839318eecdd7bf)
1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef _LIBCPP___ALGORITHM_ITERATOR_OPERATIONS_H
10 #define _LIBCPP___ALGORITHM_ITERATOR_OPERATIONS_H
11 
12 #include <__algorithm/iter_swap.h>
13 #include <__config>
14 #include <__iterator/advance.h>
15 #include <__iterator/distance.h>
16 #include <__iterator/iter_move.h>
17 #include <__iterator/iter_swap.h>
18 #include <__iterator/iterator_traits.h>
19 #include <__iterator/next.h>
20 #include <__utility/declval.h>
21 #include <__utility/forward.h>
22 #include <__utility/move.h>
23 #include <type_traits>
24 
25 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
26 #  pragma GCC system_header
27 #endif
28 
29 _LIBCPP_BEGIN_NAMESPACE_STD
30 
31 template <class _AlgPolicy> struct _IterOps;
32 
33 #if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
34 struct _RangeAlgPolicy {};
35 
36 template <>
37 struct _IterOps<_RangeAlgPolicy> {
38   static constexpr auto advance = ranges::advance;
39   static constexpr auto distance = ranges::distance;
40   static constexpr auto __iter_move = ranges::iter_move;
41   static constexpr auto iter_swap = ranges::iter_swap;
42   static constexpr auto next = ranges::next;
43   static constexpr auto __advance_to = ranges::advance;
44 };
45 
46 #endif
47 
48 struct _ClassicAlgPolicy {};
49 
50 template <>
51 struct _IterOps<_ClassicAlgPolicy> {
52 
53   // advance
54   template <class _Iter, class _Distance>
55   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
56   static void advance(_Iter& __iter, _Distance __count) {
57     std::advance(__iter, __count);
58   }
59 
60   // distance
61   template <class _Iter>
62   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
63   static typename iterator_traits<_Iter>::difference_type distance(_Iter __first, _Iter __last) {
64     return std::distance(__first, __last);
65   }
66 
67   template <class _Iter>
68   using __deref_t = decltype(*std::declval<_Iter&>());
69 
70   template <class _Iter>
71   using __move_t = decltype(std::move(*std::declval<_Iter&>()));
72 
73   template <class _Iter>
74   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
75   static void __validate_iter_reference() {
76     static_assert(is_same<__deref_t<_Iter>, typename iterator_traits<__uncvref_t<_Iter> >::reference>::value,
77         "It looks like your iterator's `iterator_traits<It>::reference` does not match the return type of "
78         "dereferencing the iterator, i.e., calling `*it`. This is undefined behavior according to [input.iterators] "
79         "and can lead to dangling reference issues at runtime, so we are flagging this.");
80   }
81 
82   // iter_move
83   template <class _Iter>
84   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 static
85   // If the result of dereferencing `_Iter` is a reference type, deduce the result of calling `std::move` on it. Note
86   // that the C++03 mode doesn't support `decltype(auto)` as the return type.
87   __enable_if_t<
88       is_reference<__deref_t<_Iter> >::value,
89       __move_t<_Iter> >
90   __iter_move(_Iter&& __i) {
91     __validate_iter_reference<_Iter>();
92 
93     return std::move(*std::forward<_Iter>(__i));
94   }
95 
96   template <class _Iter>
97   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 static
98   // If the result of dereferencing `_Iter` is a value type, deduce the return value of this function to also be a
99   // value -- otherwise, after `operator*` returns a temporary, this function would return a dangling reference to that
100   // temporary. Note that the C++03 mode doesn't support `auto` as the return type.
101   __enable_if_t<
102       !is_reference<__deref_t<_Iter> >::value,
103       __deref_t<_Iter> >
104   __iter_move(_Iter&& __i) {
105     __validate_iter_reference<_Iter>();
106 
107     return *std::forward<_Iter>(__i);
108   }
109 
110   // iter_swap
111   template <class _Iter1, class _Iter2>
112   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
113   static void iter_swap(_Iter1&& __a, _Iter2&& __b) {
114     std::iter_swap(std::forward<_Iter1>(__a), std::forward<_Iter2>(__b));
115   }
116 
117   // next
118   template <class _Iterator>
119   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_AFTER_CXX11
120   _Iterator next(_Iterator, _Iterator __last) {
121     return __last;
122   }
123 
124   template <class _Iter>
125   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_AFTER_CXX11
126   __uncvref_t<_Iter> next(_Iter&& __it,
127                           typename iterator_traits<__uncvref_t<_Iter> >::difference_type __n = 1){
128     return std::next(std::forward<_Iter>(__it), __n);
129   }
130 
131   template <class _Iter>
132   _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_AFTER_CXX11
133   void __advance_to(_Iter& __first, _Iter __last) {
134     __first = __last;
135   }
136 };
137 
138 _LIBCPP_END_NAMESPACE_STD
139 
140 #endif // _LIBCPP___ALGORITHM_ITERATOR_OPERATIONS_H
141