xref: /freebsd/contrib/llvm-project/libcxx/include/__algorithm/make_projected.h (revision a2fda816eb054d5873be223ef2461741dfcc253c)
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_MAKE_PROJECTED_H
10  #define _LIBCPP___ALGORITHM_MAKE_PROJECTED_H
11  
12  #include <__concepts/same_as.h>
13  #include <__config>
14  #include <__functional/identity.h>
15  #include <__functional/invoke.h>
16  #include <__type_traits/decay.h>
17  #include <__type_traits/enable_if.h>
18  #include <__type_traits/integral_constant.h>
19  #include <__type_traits/is_member_pointer.h>
20  #include <__type_traits/is_same.h>
21  #include <__utility/declval.h>
22  #include <__utility/forward.h>
23  
24  #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
25  #  pragma GCC system_header
26  #endif
27  
28  _LIBCPP_BEGIN_NAMESPACE_STD
29  
30  template <class _Pred, class _Proj>
31  struct _ProjectedPred {
32    _Pred& __pred; // Can be a unary or a binary predicate.
33    _Proj& __proj;
34  
35    _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI _ProjectedPred(_Pred& __pred_arg, _Proj& __proj_arg)
36        : __pred(__pred_arg), __proj(__proj_arg) {}
37  
38    template <class _Tp>
39    typename __invoke_of<_Pred&, decltype(std::__invoke(std::declval<_Proj&>(), std::declval<_Tp>())) >::
40        type _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI
41        operator()(_Tp&& __v) const {
42      return std::__invoke(__pred, std::__invoke(__proj, std::forward<_Tp>(__v)));
43    }
44  
45    template <class _T1, class _T2>
46    typename __invoke_of<_Pred&,
47                         decltype(std::__invoke(std::declval<_Proj&>(), std::declval<_T1>())),
48                         decltype(std::__invoke(std::declval<_Proj&>(),
49                                                std::declval<_T2>())) >::type _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI
50    operator()(_T1&& __lhs, _T2&& __rhs) const {
51      return std::__invoke(
52          __pred, std::__invoke(__proj, std::forward<_T1>(__lhs)), std::__invoke(__proj, std::forward<_T2>(__rhs)));
53    }
54  };
55  
56  template <
57      class _Pred,
58      class _Proj,
59      __enable_if_t<!(!is_member_pointer<__decay_t<_Pred> >::value && __is_identity<__decay_t<_Proj> >::value), int> = 0>
60  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ProjectedPred<_Pred, _Proj> __make_projected(_Pred& __pred, _Proj& __proj) {
61    return _ProjectedPred<_Pred, _Proj>(__pred, __proj);
62  }
63  
64  // Avoid creating the functor and just use the pristine comparator -- for certain algorithms, this would enable
65  // optimizations that rely on the type of the comparator. Additionally, this results in less layers of indirection in
66  // the call stack when the comparator is invoked, even in an unoptimized build.
67  template <
68      class _Pred,
69      class _Proj,
70      __enable_if_t<!is_member_pointer<__decay_t<_Pred> >::value && __is_identity<__decay_t<_Proj> >::value, int> = 0>
71  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Pred& __make_projected(_Pred& __pred, _Proj&) {
72    return __pred;
73  }
74  
75  _LIBCPP_END_NAMESPACE_STD
76  
77  #if _LIBCPP_STD_VER >= 20
78  
79  _LIBCPP_BEGIN_NAMESPACE_STD
80  
81  namespace ranges {
82  
83  template <class _Comp, class _Proj1, class _Proj2>
84  _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) __make_projected_comp(_Comp& __comp, _Proj1& __proj1, _Proj2& __proj2) {
85    if constexpr (__is_identity<decay_t<_Proj1>>::value && __is_identity<decay_t<_Proj2>>::value &&
86                  !is_member_pointer_v<decay_t<_Comp>>) {
87      // Avoid creating the lambda and just use the pristine comparator -- for certain algorithms, this would enable
88      // optimizations that rely on the type of the comparator.
89      return __comp;
90  
91    } else {
92      return [&](auto&& __lhs, auto&& __rhs) -> bool {
93        return std::invoke(__comp,
94                           std::invoke(__proj1, std::forward<decltype(__lhs)>(__lhs)),
95                           std::invoke(__proj2, std::forward<decltype(__rhs)>(__rhs)));
96      };
97    }
98  }
99  
100  } // namespace ranges
101  
102  _LIBCPP_END_NAMESPACE_STD
103  
104  #endif // _LIBCPP_STD_VER >= 20
105  
106  #endif // _LIBCPP___ALGORITHM_MAKE_PROJECTED_H
107