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