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
13 #include <__functional/identity.h>
14 #include <__functional/invoke.h>
15 #include <__type_traits/decay.h>
16 #include <__type_traits/enable_if.h>
17 #include <__type_traits/invoke.h>
18 #include <__type_traits/is_member_pointer.h>
19 #include <__utility/declval.h>
20 #include <__utility/forward.h>
22 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
23 # pragma GCC system_header
26 _LIBCPP_BEGIN_NAMESPACE_STD
28 template <class _Pred
, class _Proj
>
29 struct _ProjectedPred
{
30 _Pred
& __pred
; // Can be a unary or a binary predicate.
33 _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI
_ProjectedPred(_Pred
& __pred_arg
, _Proj
& __proj_arg
)
34 : __pred(__pred_arg
), __proj(__proj_arg
) {}
37 typename __invoke_of
<_Pred
&, decltype(std::__invoke(std::declval
<_Proj
&>(), std::declval
<_Tp
>()))>::type
38 _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI
39 operator()(_Tp
&& __v
) const {
40 return std::__invoke(__pred
, std::__invoke(__proj
, std::forward
<_Tp
>(__v
)));
43 template <class _T1
, class _T2
>
44 typename __invoke_of
<_Pred
&,
45 decltype(std::__invoke(std::declval
<_Proj
&>(), std::declval
<_T1
>())),
46 decltype(std::__invoke(std::declval
<_Proj
&>(), std::declval
<_T2
>()))>::type _LIBCPP_CONSTEXPR
48 operator()(_T1
&& __lhs
, _T2
&& __rhs
) const {
50 __pred
, std::__invoke(__proj
, std::forward
<_T1
>(__lhs
)), std::__invoke(__proj
, std::forward
<_T2
>(__rhs
)));
57 __enable_if_t
<!(!is_member_pointer
<__decay_t
<_Pred
> >::value
&& __is_identity
<__decay_t
<_Proj
> >::value
), int> = 0>
58 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ProjectedPred
<_Pred
, _Proj
> __make_projected(_Pred
& __pred
, _Proj
& __proj
) {
59 return _ProjectedPred
<_Pred
, _Proj
>(__pred
, __proj
);
62 // Avoid creating the functor and just use the pristine comparator -- for certain algorithms, this would enable
63 // optimizations that rely on the type of the comparator. Additionally, this results in less layers of indirection in
64 // the call stack when the comparator is invoked, even in an unoptimized build.
68 __enable_if_t
<!is_member_pointer
<__decay_t
<_Pred
> >::value
&& __is_identity
<__decay_t
<_Proj
> >::value
, int> = 0>
69 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Pred
& __make_projected(_Pred
& __pred
, _Proj
&) {
73 _LIBCPP_END_NAMESPACE_STD
75 #if _LIBCPP_STD_VER >= 20
77 _LIBCPP_BEGIN_NAMESPACE_STD
81 template <class _Comp
, class _Proj1
, class _Proj2
>
82 _LIBCPP_HIDE_FROM_ABI
constexpr decltype(auto) __make_projected_comp(_Comp
& __comp
, _Proj1
& __proj1
, _Proj2
& __proj2
) {
83 if constexpr (__is_identity
<decay_t
<_Proj1
>>::value
&& __is_identity
<decay_t
<_Proj2
>>::value
&&
84 !is_member_pointer_v
<decay_t
<_Comp
>>) {
85 // Avoid creating the lambda and just use the pristine comparator -- for certain algorithms, this would enable
86 // optimizations that rely on the type of the comparator.
90 return [&](auto&& __lhs
, auto&& __rhs
) -> bool {
91 return std::invoke(__comp
,
92 std::invoke(__proj1
, std::forward
<decltype(__lhs
)>(__lhs
)),
93 std::invoke(__proj2
, std::forward
<decltype(__rhs
)>(__rhs
)));
100 _LIBCPP_END_NAMESPACE_STD
102 #endif // _LIBCPP_STD_VER >= 20
104 #endif // _LIBCPP___ALGORITHM_MAKE_PROJECTED_H