181ad6265SDimitry Andric //===----------------------------------------------------------------------===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric
981ad6265SDimitry Andric #ifndef _LIBCPP___ALGORITHM_MAKE_PROJECTED_H
1081ad6265SDimitry Andric #define _LIBCPP___ALGORITHM_MAKE_PROJECTED_H
1181ad6265SDimitry Andric
1281ad6265SDimitry Andric #include <__concepts/same_as.h>
1381ad6265SDimitry Andric #include <__config>
1481ad6265SDimitry Andric #include <__functional/identity.h>
1581ad6265SDimitry Andric #include <__functional/invoke.h>
16753f127fSDimitry Andric #include <__type_traits/decay.h>
1761cfbce3SDimitry Andric #include <__type_traits/enable_if.h>
1861cfbce3SDimitry Andric #include <__type_traits/integral_constant.h>
19753f127fSDimitry Andric #include <__type_traits/is_member_pointer.h>
2061cfbce3SDimitry Andric #include <__type_traits/is_same.h>
2161cfbce3SDimitry Andric #include <__utility/declval.h>
2281ad6265SDimitry Andric #include <__utility/forward.h>
2381ad6265SDimitry Andric
2481ad6265SDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
2581ad6265SDimitry Andric # pragma GCC system_header
2681ad6265SDimitry Andric #endif
2781ad6265SDimitry Andric
2861cfbce3SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
2961cfbce3SDimitry Andric
3061cfbce3SDimitry Andric template <class _Pred, class _Proj>
3161cfbce3SDimitry Andric struct _ProjectedPred {
3261cfbce3SDimitry Andric _Pred& __pred; // Can be a unary or a binary predicate.
3361cfbce3SDimitry Andric _Proj& __proj;
3461cfbce3SDimitry Andric
_ProjectedPred_ProjectedPred3506c3fb27SDimitry Andric _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI _ProjectedPred(_Pred& __pred_arg, _Proj& __proj_arg)
3606c3fb27SDimitry Andric : __pred(__pred_arg), __proj(__proj_arg) {}
3761cfbce3SDimitry Andric
3861cfbce3SDimitry Andric template <class _Tp>
39*0fca6ea1SDimitry Andric typename __invoke_of<_Pred&, decltype(std::__invoke(std::declval<_Proj&>(), std::declval<_Tp>()))>::type
40*0fca6ea1SDimitry Andric _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI
operator_ProjectedPred41cb14a3feSDimitry Andric operator()(_Tp&& __v) const {
4261cfbce3SDimitry Andric return std::__invoke(__pred, std::__invoke(__proj, std::forward<_Tp>(__v)));
4361cfbce3SDimitry Andric }
4461cfbce3SDimitry Andric
4561cfbce3SDimitry Andric template <class _T1, class _T2>
4661cfbce3SDimitry Andric typename __invoke_of<_Pred&,
4761cfbce3SDimitry Andric decltype(std::__invoke(std::declval<_Proj&>(), std::declval<_T1>())),
48*0fca6ea1SDimitry Andric decltype(std::__invoke(std::declval<_Proj&>(), std::declval<_T2>()))>::type _LIBCPP_CONSTEXPR
49*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI
operator_ProjectedPred50cb14a3feSDimitry Andric operator()(_T1&& __lhs, _T2&& __rhs) const {
51cb14a3feSDimitry Andric return std::__invoke(
52cb14a3feSDimitry Andric __pred, std::__invoke(__proj, std::forward<_T1>(__lhs)), std::__invoke(__proj, std::forward<_T2>(__rhs)));
5361cfbce3SDimitry Andric }
5461cfbce3SDimitry Andric };
5561cfbce3SDimitry Andric
56cb14a3feSDimitry Andric template <
57cb14a3feSDimitry Andric class _Pred,
5806c3fb27SDimitry Andric class _Proj,
59cb14a3feSDimitry Andric __enable_if_t<!(!is_member_pointer<__decay_t<_Pred> >::value && __is_identity<__decay_t<_Proj> >::value), int> = 0>
__make_projected(_Pred & __pred,_Proj & __proj)60cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ProjectedPred<_Pred, _Proj> __make_projected(_Pred& __pred, _Proj& __proj) {
6161cfbce3SDimitry Andric return _ProjectedPred<_Pred, _Proj>(__pred, __proj);
6261cfbce3SDimitry Andric }
6361cfbce3SDimitry Andric
6461cfbce3SDimitry Andric // Avoid creating the functor and just use the pristine comparator -- for certain algorithms, this would enable
6561cfbce3SDimitry Andric // optimizations that rely on the type of the comparator. Additionally, this results in less layers of indirection in
6661cfbce3SDimitry Andric // the call stack when the comparator is invoked, even in an unoptimized build.
67cb14a3feSDimitry Andric template <
68cb14a3feSDimitry Andric class _Pred,
6906c3fb27SDimitry Andric class _Proj,
70cb14a3feSDimitry Andric __enable_if_t<!is_member_pointer<__decay_t<_Pred> >::value && __is_identity<__decay_t<_Proj> >::value, int> = 0>
__make_projected(_Pred & __pred,_Proj &)7106c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Pred& __make_projected(_Pred& __pred, _Proj&) {
7261cfbce3SDimitry Andric return __pred;
7361cfbce3SDimitry Andric }
7461cfbce3SDimitry Andric
7561cfbce3SDimitry Andric _LIBCPP_END_NAMESPACE_STD
7661cfbce3SDimitry Andric
7706c3fb27SDimitry Andric #if _LIBCPP_STD_VER >= 20
7881ad6265SDimitry Andric
7981ad6265SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
8081ad6265SDimitry Andric
8181ad6265SDimitry Andric namespace ranges {
8281ad6265SDimitry Andric
83753f127fSDimitry Andric template <class _Comp, class _Proj1, class _Proj2>
decltype(auto)84cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) __make_projected_comp(_Comp& __comp, _Proj1& __proj1, _Proj2& __proj2) {
8506c3fb27SDimitry Andric if constexpr (__is_identity<decay_t<_Proj1>>::value && __is_identity<decay_t<_Proj2>>::value &&
86753f127fSDimitry Andric !is_member_pointer_v<decay_t<_Comp>>) {
87753f127fSDimitry Andric // Avoid creating the lambda and just use the pristine comparator -- for certain algorithms, this would enable
88753f127fSDimitry Andric // optimizations that rely on the type of the comparator.
89753f127fSDimitry Andric return __comp;
90753f127fSDimitry Andric
91753f127fSDimitry Andric } else {
925f757f3fSDimitry Andric return [&](auto&& __lhs, auto&& __rhs) -> bool {
93753f127fSDimitry Andric return std::invoke(__comp,
94753f127fSDimitry Andric std::invoke(__proj1, std::forward<decltype(__lhs)>(__lhs)),
95753f127fSDimitry Andric std::invoke(__proj2, std::forward<decltype(__rhs)>(__rhs)));
96753f127fSDimitry Andric };
97753f127fSDimitry Andric }
98753f127fSDimitry Andric }
99753f127fSDimitry Andric
10081ad6265SDimitry Andric } // namespace ranges
10181ad6265SDimitry Andric
10281ad6265SDimitry Andric _LIBCPP_END_NAMESPACE_STD
10381ad6265SDimitry Andric
10406c3fb27SDimitry Andric #endif // _LIBCPP_STD_VER >= 20
10581ad6265SDimitry Andric
10681ad6265SDimitry Andric #endif // _LIBCPP___ALGORITHM_MAKE_PROJECTED_H
107