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/invoke.h>
20 #include <__type_traits/is_member_pointer.h>
21 #include <__type_traits/is_same.h>
22 #include <__utility/declval.h>
23 #include <__utility/forward.h>
25 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
26 # pragma GCC system_header
29 _LIBCPP_BEGIN_NAMESPACE_STD
31 template <class _Pred
, class _Proj
>
32 struct _ProjectedPred
{
33 _Pred
& __pred
; // Can be a unary or a binary predicate.
36 _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI
_ProjectedPred(_Pred
& __pred_arg
, _Proj
& __proj_arg
)
37 : __pred(__pred_arg
), __proj(__proj_arg
) {}
40 typename __invoke_of
<_Pred
&, decltype(std::__invoke(std::declval
<_Proj
&>(), std::declval
<_Tp
>()))>::type
41 _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI
42 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
>()))>::type _LIBCPP_CONSTEXPR
51 operator()(_T1
&& __lhs
, _T2
&& __rhs
) const {
53 __pred
, std::__invoke(__proj
, std::forward
<_T1
>(__lhs
)), std::__invoke(__proj
, std::forward
<_T2
>(__rhs
)));
60 __enable_if_t
<!(!is_member_pointer
<__decay_t
<_Pred
> >::value
&& __is_identity
<__decay_t
<_Proj
> >::value
), int> = 0>
61 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ProjectedPred
<_Pred
, _Proj
> __make_projected(_Pred
& __pred
, _Proj
& __proj
) {
62 return _ProjectedPred
<_Pred
, _Proj
>(__pred
, __proj
);
65 // Avoid creating the functor and just use the pristine comparator -- for certain algorithms, this would enable
66 // optimizations that rely on the type of the comparator. Additionally, this results in less layers of indirection in
67 // the call stack when the comparator is invoked, even in an unoptimized build.
71 __enable_if_t
<!is_member_pointer
<__decay_t
<_Pred
> >::value
&& __is_identity
<__decay_t
<_Proj
> >::value
, int> = 0>
72 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Pred
& __make_projected(_Pred
& __pred
, _Proj
&) {
76 _LIBCPP_END_NAMESPACE_STD
78 #if _LIBCPP_STD_VER >= 20
80 _LIBCPP_BEGIN_NAMESPACE_STD
84 template <class _Comp
, class _Proj1
, class _Proj2
>
85 _LIBCPP_HIDE_FROM_ABI
constexpr decltype(auto) __make_projected_comp(_Comp
& __comp
, _Proj1
& __proj1
, _Proj2
& __proj2
) {
86 if constexpr (__is_identity
<decay_t
<_Proj1
>>::value
&& __is_identity
<decay_t
<_Proj2
>>::value
&&
87 !is_member_pointer_v
<decay_t
<_Comp
>>) {
88 // Avoid creating the lambda and just use the pristine comparator -- for certain algorithms, this would enable
89 // optimizations that rely on the type of the comparator.
93 return [&](auto&& __lhs
, auto&& __rhs
) -> bool {
94 return std::invoke(__comp
,
95 std::invoke(__proj1
, std::forward
<decltype(__lhs
)>(__lhs
)),
96 std::invoke(__proj2
, std::forward
<decltype(__rhs
)>(__rhs
)));
101 } // namespace ranges
103 _LIBCPP_END_NAMESPACE_STD
105 #endif // _LIBCPP_STD_VER >= 20
107 #endif // _LIBCPP___ALGORITHM_MAKE_PROJECTED_H