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 3506c3fb27SDimitry 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 41cb14a3feSDimitry 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 50cb14a3feSDimitry 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> 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> 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> 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