1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef _LIBCPP___ALGORITHM_MAKE_PROJECTED_H
10 #define _LIBCPP___ALGORITHM_MAKE_PROJECTED_H
12 #include <__concepts/same_as.h>
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>
24 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
25 # pragma GCC system_header
28 _LIBCPP_BEGIN_NAMESPACE_STD
30 template <class _Pred
, class _Proj
>
31 struct _ProjectedPred
{
32 _Pred
& __pred
; // Can be a unary or a binary predicate.
35 _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI
_ProjectedPred(_Pred
& __pred_arg
, _Proj
& __proj_arg
)
36 : __pred(__pred_arg
), __proj(__proj_arg
) {}
39 typename __invoke_of
<_Pred
&,
40 decltype(std::__invoke(std::declval
<_Proj
&>(), std::declval
<_Tp
>()))
42 _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI
operator()(_Tp
&& __v
) const {
43 return std::__invoke(__pred
, std::__invoke(__proj
, std::forward
<_Tp
>(__v
)));
46 template <class _T1
, class _T2
>
47 typename __invoke_of
<_Pred
&,
48 decltype(std::__invoke(std::declval
<_Proj
&>(), std::declval
<_T1
>())),
49 decltype(std::__invoke(std::declval
<_Proj
&>(), std::declval
<_T2
>()))
51 _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI
operator()(_T1
&& __lhs
, _T2
&& __rhs
) const {
52 return std::__invoke(__pred
,
53 std::__invoke(__proj
, std::forward
<_T1
>(__lhs
)),
54 std::__invoke(__proj
, std::forward
<_T2
>(__rhs
)));
59 template <class _Pred
,
61 __enable_if_t
<!(!is_member_pointer
<__decay_t
<_Pred
> >::value
&&
62 __is_identity
<__decay_t
<_Proj
> >::value
),
64 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ProjectedPred
<_Pred
, _Proj
>
65 __make_projected(_Pred
& __pred
, _Proj
& __proj
) {
66 return _ProjectedPred
<_Pred
, _Proj
>(__pred
, __proj
);
69 // Avoid creating the functor and just use the pristine comparator -- for certain algorithms, this would enable
70 // optimizations that rely on the type of the comparator. Additionally, this results in less layers of indirection in
71 // the call stack when the comparator is invoked, even in an unoptimized build.
72 template <class _Pred
,
74 __enable_if_t
<!is_member_pointer
<__decay_t
<_Pred
> >::value
&&
75 __is_identity
<__decay_t
<_Proj
> >::value
,
77 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Pred
& __make_projected(_Pred
& __pred
, _Proj
&) {
81 _LIBCPP_END_NAMESPACE_STD
83 #if _LIBCPP_STD_VER >= 20
85 _LIBCPP_BEGIN_NAMESPACE_STD
89 template <class _Comp
, class _Proj1
, class _Proj2
>
90 _LIBCPP_HIDE_FROM_ABI
constexpr
91 decltype(auto) __make_projected_comp(_Comp
& __comp
, _Proj1
& __proj1
, _Proj2
& __proj2
) {
92 if constexpr (__is_identity
<decay_t
<_Proj1
>>::value
&& __is_identity
<decay_t
<_Proj2
>>::value
&&
93 !is_member_pointer_v
<decay_t
<_Comp
>>) {
94 // Avoid creating the lambda and just use the pristine comparator -- for certain algorithms, this would enable
95 // optimizations that rely on the type of the comparator.
99 return [&](auto&& __lhs
, auto&& __rhs
) {
100 return std::invoke(__comp
,
101 std::invoke(__proj1
, std::forward
<decltype(__lhs
)>(__lhs
)),
102 std::invoke(__proj2
, std::forward
<decltype(__rhs
)>(__rhs
)));
107 } // namespace ranges
109 _LIBCPP_END_NAMESPACE_STD
111 #endif // _LIBCPP_STD_VER >= 20
113 #endif // _LIBCPP___ALGORITHM_MAKE_PROJECTED_H