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