xref: /llvm-project/libcxx/include/__iterator/prev.h (revision a5d919b4b2f24c582838659fe7f30073e7285524)
10dc7fd1bSChristopher Di Bella // -*- C++ -*-
20dc7fd1bSChristopher Di Bella //===----------------------------------------------------------------------===//
30dc7fd1bSChristopher Di Bella //
40dc7fd1bSChristopher Di Bella // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
50dc7fd1bSChristopher Di Bella // See https://llvm.org/LICENSE.txt for license information.
60dc7fd1bSChristopher Di Bella // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
70dc7fd1bSChristopher Di Bella //
80dc7fd1bSChristopher Di Bella //===----------------------------------------------------------------------===//
90dc7fd1bSChristopher Di Bella 
100dc7fd1bSChristopher Di Bella #ifndef _LIBCPP___ITERATOR_PREV_H
110dc7fd1bSChristopher Di Bella #define _LIBCPP___ITERATOR_PREV_H
120dc7fd1bSChristopher Di Bella 
13f87aa19bSLouis Dionne #include <__assert>
140dc7fd1bSChristopher Di Bella #include <__config>
150dc7fd1bSChristopher Di Bella #include <__iterator/advance.h>
160dc7fd1bSChristopher Di Bella #include <__iterator/concepts.h>
170dc7fd1bSChristopher Di Bella #include <__iterator/incrementable_traits.h>
18332da1c2SChristopher Di Bella #include <__iterator/iterator_traits.h>
19e0a66116SNikolas Klauser #include <__type_traits/enable_if.h>
20*a5d919b4SHui #include <__utility/move.h>
210dc7fd1bSChristopher Di Bella 
220dc7fd1bSChristopher Di Bella #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
230dc7fd1bSChristopher Di Bella #  pragma GCC system_header
240dc7fd1bSChristopher Di Bella #endif
250dc7fd1bSChristopher Di Bella 
26*a5d919b4SHui _LIBCPP_PUSH_MACROS
27*a5d919b4SHui #include <__undef_macros>
28*a5d919b4SHui 
290dc7fd1bSChristopher Di Bella _LIBCPP_BEGIN_NAMESPACE_STD
300dc7fd1bSChristopher Di Bella 
31475bd19eSNikolas Klauser template <class _InputIter, __enable_if_t<__has_input_iterator_category<_InputIter>::value, int> = 0>
32e9c0c660SMarc Auberer [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _InputIter
33*a5d919b4SHui prev(_InputIter __x, typename iterator_traits<_InputIter>::difference_type __n) {
344f215fddSKonstantin Varlamov   // Calling `advance` with a negative value on a non-bidirectional iterator is a no-op in the current implementation.
354f215fddSKonstantin Varlamov   // Note that this check duplicates the similar check in `std::advance`.
364f215fddSKonstantin Varlamov   _LIBCPP_ASSERT_PEDANTIC(__n <= 0 || __has_bidirectional_iterator_category<_InputIter>::value,
37bf92bdadSChristopher Di Bella                           "Attempt to prev(it, n) with a positive n on a non-bidirectional iterator");
3877a00c0dSLouis Dionne   std::advance(__x, -__n);
39bf92bdadSChristopher Di Bella   return __x;
40bf92bdadSChristopher Di Bella }
41bf92bdadSChristopher Di Bella 
42*a5d919b4SHui // LWG 3197
43*a5d919b4SHui // It is unclear what the implications of "BidirectionalIterator" in the standard are.
44*a5d919b4SHui // However, calling std::prev(non-bidi-iterator) is obviously an error and we should catch it at compile time.
45*a5d919b4SHui template <class _InputIter, __enable_if_t<__has_input_iterator_category<_InputIter>::value, int> = 0>
46*a5d919b4SHui [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _InputIter prev(_InputIter __it) {
47*a5d919b4SHui   static_assert(__has_bidirectional_iterator_category<_InputIter>::value,
48*a5d919b4SHui                 "Attempt to prev(it) with a non-bidirectional iterator");
49*a5d919b4SHui   return std::prev(std::move(__it), 1);
50*a5d919b4SHui }
51*a5d919b4SHui 
524f15267dSNikolas Klauser #if _LIBCPP_STD_VER >= 20
530dc7fd1bSChristopher Di Bella 
546ce732cbSArthur O'Dwyer // [range.iter.op.prev]
556ce732cbSArthur O'Dwyer 
560dc7fd1bSChristopher Di Bella namespace ranges {
57d10dc5a0SChristopher Di Bella struct __prev {
580dc7fd1bSChristopher Di Bella   template <bidirectional_iterator _Ip>
59e9c0c660SMarc Auberer   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Ip operator()(_Ip __x) const {
600dc7fd1bSChristopher Di Bella     --__x;
610dc7fd1bSChristopher Di Bella     return __x;
620dc7fd1bSChristopher Di Bella   }
630dc7fd1bSChristopher Di Bella 
640dc7fd1bSChristopher Di Bella   template <bidirectional_iterator _Ip>
65e9c0c660SMarc Auberer   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Ip operator()(_Ip __x, iter_difference_t<_Ip> __n) const {
660dc7fd1bSChristopher Di Bella     ranges::advance(__x, -__n);
670dc7fd1bSChristopher Di Bella     return __x;
680dc7fd1bSChristopher Di Bella   }
690dc7fd1bSChristopher Di Bella 
700dc7fd1bSChristopher Di Bella   template <bidirectional_iterator _Ip>
71e9c0c660SMarc Auberer   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Ip
72e9c0c660SMarc Auberer   operator()(_Ip __x, iter_difference_t<_Ip> __n, _Ip __bound_iter) const {
735a4f177cSPeter Kasting     ranges::advance(__x, -__n, __bound_iter);
740dc7fd1bSChristopher Di Bella     return __x;
750dc7fd1bSChristopher Di Bella   }
760dc7fd1bSChristopher Di Bella };
770dc7fd1bSChristopher Di Bella 
786ce732cbSArthur O'Dwyer inline namespace __cpo {
79d10dc5a0SChristopher Di Bella inline constexpr auto prev = __prev{};
806ce732cbSArthur O'Dwyer } // namespace __cpo
810dc7fd1bSChristopher Di Bella } // namespace ranges
820dc7fd1bSChristopher Di Bella 
834f15267dSNikolas Klauser #endif // _LIBCPP_STD_VER >= 20
840dc7fd1bSChristopher Di Bella 
850dc7fd1bSChristopher Di Bella _LIBCPP_END_NAMESPACE_STD
860dc7fd1bSChristopher Di Bella 
87*a5d919b4SHui _LIBCPP_POP_MACROS
88*a5d919b4SHui 
890dc7fd1bSChristopher Di Bella #endif // _LIBCPP___ITERATOR_PREV_H
90