xref: /llvm-project/libcxx/include/__cxx03/__algorithm/unwrap_iter.h (revision ce7771902dc50d900de639d499a60486b83f70e0)
1e78f53d1SNikolas Klauser //===----------------------------------------------------------------------===//
2e78f53d1SNikolas Klauser //
3e78f53d1SNikolas Klauser // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e78f53d1SNikolas Klauser // See https://llvm.org/LICENSE.txt for license information.
5e78f53d1SNikolas Klauser // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e78f53d1SNikolas Klauser //
7e78f53d1SNikolas Klauser //===----------------------------------------------------------------------===//
8e78f53d1SNikolas Klauser 
9*ce777190SNikolas Klauser #ifndef _LIBCPP___CXX03___ALGORITHM_UNWRAP_ITER_H
10*ce777190SNikolas Klauser #define _LIBCPP___CXX03___ALGORITHM_UNWRAP_ITER_H
11e78f53d1SNikolas Klauser 
1273fbae83SNikolas Klauser #include <__cxx03/__config>
1373fbae83SNikolas Klauser #include <__cxx03/__iterator/iterator_traits.h>
1473fbae83SNikolas Klauser #include <__cxx03/__memory/pointer_traits.h>
1573fbae83SNikolas Klauser #include <__cxx03/__type_traits/enable_if.h>
1673fbae83SNikolas Klauser #include <__cxx03/__type_traits/is_constructible.h>
1773fbae83SNikolas Klauser #include <__cxx03/__utility/declval.h>
1873fbae83SNikolas Klauser #include <__cxx03/__utility/move.h>
19e78f53d1SNikolas Klauser 
20e78f53d1SNikolas Klauser #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
21e78f53d1SNikolas Klauser #  pragma GCC system_header
22e78f53d1SNikolas Klauser #endif
23e78f53d1SNikolas Klauser 
24e78f53d1SNikolas Klauser _LIBCPP_PUSH_MACROS
2573fbae83SNikolas Klauser #include <__cxx03/__undef_macros>
26e78f53d1SNikolas Klauser 
27e78f53d1SNikolas Klauser _LIBCPP_BEGIN_NAMESPACE_STD
28e78f53d1SNikolas Klauser 
29e78f53d1SNikolas Klauser // TODO: Change the name of __unwrap_iter_impl to something more appropriate
30e78f53d1SNikolas Klauser // The job of __unwrap_iter is to remove iterator wrappers (like reverse_iterator or __wrap_iter),
31e78f53d1SNikolas Klauser // to reduce the number of template instantiations and to enable pointer-based optimizations e.g. in std::copy.
32e78f53d1SNikolas Klauser //
33e78f53d1SNikolas Klauser // Some algorithms (e.g. std::copy, but not std::sort) need to convert an
34e78f53d1SNikolas Klauser // "unwrapped" result back into the original iterator type. Doing that is the job of __rewrap_iter.
35e78f53d1SNikolas Klauser 
36e78f53d1SNikolas Klauser // Default case - we can't unwrap anything
37e78f53d1SNikolas Klauser template <class _Iter, bool = __libcpp_is_contiguous_iterator<_Iter>::value>
38e78f53d1SNikolas Klauser struct __unwrap_iter_impl {
39e78f53d1SNikolas Klauser   static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Iter __rewrap(_Iter, _Iter __iter) { return __iter; }
40e78f53d1SNikolas Klauser   static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Iter __unwrap(_Iter __i) _NOEXCEPT { return __i; }
41e78f53d1SNikolas Klauser };
42e78f53d1SNikolas Klauser 
43e78f53d1SNikolas Klauser // TODO(hardening): make sure that the following unwrapping doesn't unexpectedly turn hardened iterators into raw
44e78f53d1SNikolas Klauser // pointers.
45e78f53d1SNikolas Klauser 
46e78f53d1SNikolas Klauser // It's a contiguous iterator, so we can use a raw pointer instead
47e78f53d1SNikolas Klauser template <class _Iter>
48e78f53d1SNikolas Klauser struct __unwrap_iter_impl<_Iter, true> {
49e78f53d1SNikolas Klauser   using _ToAddressT = decltype(std::__to_address(std::declval<_Iter>()));
50e78f53d1SNikolas Klauser 
51e78f53d1SNikolas Klauser   static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Iter __rewrap(_Iter __orig_iter, _ToAddressT __unwrapped_iter) {
52e78f53d1SNikolas Klauser     return __orig_iter + (__unwrapped_iter - std::__to_address(__orig_iter));
53e78f53d1SNikolas Klauser   }
54e78f53d1SNikolas Klauser 
55e78f53d1SNikolas Klauser   static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ToAddressT __unwrap(_Iter __i) _NOEXCEPT {
56e78f53d1SNikolas Klauser     return std::__to_address(__i);
57e78f53d1SNikolas Klauser   }
58e78f53d1SNikolas Klauser };
59e78f53d1SNikolas Klauser 
60e78f53d1SNikolas Klauser template <class _Iter,
61e78f53d1SNikolas Klauser           class _Impl                                             = __unwrap_iter_impl<_Iter>,
62e78f53d1SNikolas Klauser           __enable_if_t<is_copy_constructible<_Iter>::value, int> = 0>
63e78f53d1SNikolas Klauser inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 decltype(_Impl::__unwrap(std::declval<_Iter>()))
64e78f53d1SNikolas Klauser __unwrap_iter(_Iter __i) _NOEXCEPT {
65e78f53d1SNikolas Klauser   return _Impl::__unwrap(__i);
66e78f53d1SNikolas Klauser }
67e78f53d1SNikolas Klauser 
68e78f53d1SNikolas Klauser // Allow input_iterators to be passed to __unwrap_iter (but not __rewrap_iter)
69e78f53d1SNikolas Klauser #if _LIBCPP_STD_VER >= 20
70e78f53d1SNikolas Klauser template <class _Iter, __enable_if_t<!is_copy_constructible<_Iter>::value, int> = 0>
71e78f53d1SNikolas Klauser inline _LIBCPP_HIDE_FROM_ABI constexpr _Iter __unwrap_iter(_Iter __i) noexcept {
72e78f53d1SNikolas Klauser   return __i;
73e78f53d1SNikolas Klauser }
74e78f53d1SNikolas Klauser #endif
75e78f53d1SNikolas Klauser 
76e78f53d1SNikolas Klauser template <class _OrigIter, class _Iter, class _Impl = __unwrap_iter_impl<_OrigIter> >
77e78f53d1SNikolas Klauser _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _OrigIter __rewrap_iter(_OrigIter __orig_iter, _Iter __iter) _NOEXCEPT {
78e78f53d1SNikolas Klauser   return _Impl::__rewrap(std::move(__orig_iter), std::move(__iter));
79e78f53d1SNikolas Klauser }
80e78f53d1SNikolas Klauser 
81e78f53d1SNikolas Klauser _LIBCPP_END_NAMESPACE_STD
82e78f53d1SNikolas Klauser 
83e78f53d1SNikolas Klauser _LIBCPP_POP_MACROS
84e78f53d1SNikolas Klauser 
85*ce777190SNikolas Klauser #endif // _LIBCPP___CXX03___ALGORITHM_UNWRAP_ITER_H
86