1ff3989e6SKonstantin Varlamov //===----------------------------------------------------------------------===// 2ff3989e6SKonstantin Varlamov // 3ff3989e6SKonstantin Varlamov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4ff3989e6SKonstantin Varlamov // See https://llvm.org/LICENSE.txt for license information. 5ff3989e6SKonstantin Varlamov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6ff3989e6SKonstantin Varlamov // 7ff3989e6SKonstantin Varlamov //===----------------------------------------------------------------------===// 8ff3989e6SKonstantin Varlamov 9ff3989e6SKonstantin Varlamov #ifndef _LIBCPP___ALGORITHM_MAKE_PROJECTED_H 10ff3989e6SKonstantin Varlamov #define _LIBCPP___ALGORITHM_MAKE_PROJECTED_H 11ff3989e6SKonstantin Varlamov 12ff3989e6SKonstantin Varlamov #include <__concepts/same_as.h> 13ff3989e6SKonstantin Varlamov #include <__config> 14ff3989e6SKonstantin Varlamov #include <__functional/identity.h> 15ff3989e6SKonstantin Varlamov #include <__functional/invoke.h> 161cdec6c9SHui Xie #include <__type_traits/decay.h> 17*2c766efcSKonstantin Varlamov #include <__type_traits/enable_if.h> 18*2c766efcSKonstantin Varlamov #include <__type_traits/integral_constant.h> 191cdec6c9SHui Xie #include <__type_traits/is_member_pointer.h> 20*2c766efcSKonstantin Varlamov #include <__type_traits/is_same.h> 21*2c766efcSKonstantin Varlamov #include <__utility/declval.h> 22ff3989e6SKonstantin Varlamov #include <__utility/forward.h> 23ff3989e6SKonstantin Varlamov 24ff3989e6SKonstantin Varlamov #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 25ff3989e6SKonstantin Varlamov # pragma GCC system_header 26ff3989e6SKonstantin Varlamov #endif 27ff3989e6SKonstantin Varlamov 28*2c766efcSKonstantin Varlamov _LIBCPP_BEGIN_NAMESPACE_STD 29*2c766efcSKonstantin Varlamov 30*2c766efcSKonstantin Varlamov template <class _Pred, class _Proj> 31*2c766efcSKonstantin Varlamov struct _ProjectedPred { 32*2c766efcSKonstantin Varlamov _Pred& __pred; // Can be a unary or a binary predicate. 33*2c766efcSKonstantin Varlamov _Proj& __proj; 34*2c766efcSKonstantin Varlamov _ProjectedPred_ProjectedPred35*2c766efcSKonstantin Varlamov _LIBCPP_CONSTEXPR _ProjectedPred(_Pred& __pred_arg, _Proj& __proj_arg) : __pred(__pred_arg), __proj(__proj_arg) {} 36*2c766efcSKonstantin Varlamov 37*2c766efcSKonstantin Varlamov template <class _Tp> 38*2c766efcSKonstantin Varlamov typename __invoke_of<_Pred&, 39*2c766efcSKonstantin Varlamov decltype(std::__invoke(std::declval<_Proj&>(), std::declval<_Tp>())) 40*2c766efcSKonstantin Varlamov >::type operator_ProjectedPred41*2c766efcSKonstantin Varlamov _LIBCPP_CONSTEXPR operator()(_Tp&& __v) const { 42*2c766efcSKonstantin Varlamov return std::__invoke(__pred, std::__invoke(__proj, std::forward<_Tp>(__v))); 43*2c766efcSKonstantin Varlamov } 44*2c766efcSKonstantin Varlamov 45*2c766efcSKonstantin Varlamov template <class _T1, class _T2> 46*2c766efcSKonstantin Varlamov typename __invoke_of<_Pred&, 47*2c766efcSKonstantin Varlamov decltype(std::__invoke(std::declval<_Proj&>(), std::declval<_T1>())), 48*2c766efcSKonstantin Varlamov decltype(std::__invoke(std::declval<_Proj&>(), std::declval<_T2>())) 49*2c766efcSKonstantin Varlamov >::type operator_ProjectedPred50*2c766efcSKonstantin Varlamov _LIBCPP_CONSTEXPR operator()(_T1&& __lhs, _T2&& __rhs) const { 51*2c766efcSKonstantin Varlamov return std::__invoke(__pred, 52*2c766efcSKonstantin Varlamov std::__invoke(__proj, std::forward<_T1>(__lhs)), 53*2c766efcSKonstantin Varlamov std::__invoke(__proj, std::forward<_T2>(__rhs))); 54*2c766efcSKonstantin Varlamov } 55*2c766efcSKonstantin Varlamov 56*2c766efcSKonstantin Varlamov }; 57*2c766efcSKonstantin Varlamov 58*2c766efcSKonstantin Varlamov template <class _Pred, class _Proj, class = void> 59*2c766efcSKonstantin Varlamov struct __can_use_pristine_comp : false_type {}; 60*2c766efcSKonstantin Varlamov 61*2c766efcSKonstantin Varlamov template <class _Pred, class _Proj> 62*2c766efcSKonstantin Varlamov struct __can_use_pristine_comp<_Pred, _Proj, __enable_if_t< 63*2c766efcSKonstantin Varlamov !is_member_pointer<typename decay<_Pred>::type>::value && ( 64*2c766efcSKonstantin Varlamov #if _LIBCPP_STD_VER > 17 65*2c766efcSKonstantin Varlamov is_same<typename decay<_Proj>::type, identity>::value || 66*2c766efcSKonstantin Varlamov #endif 67*2c766efcSKonstantin Varlamov is_same<typename decay<_Proj>::type, __identity>::value 68*2c766efcSKonstantin Varlamov ) 69*2c766efcSKonstantin Varlamov > > : true_type {}; 70*2c766efcSKonstantin Varlamov 71*2c766efcSKonstantin Varlamov template <class _Pred, class _Proj> 72*2c766efcSKonstantin Varlamov _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR static 73*2c766efcSKonstantin Varlamov __enable_if_t< 74*2c766efcSKonstantin Varlamov !__can_use_pristine_comp<_Pred, _Proj>::value, 75*2c766efcSKonstantin Varlamov _ProjectedPred<_Pred, _Proj> 76*2c766efcSKonstantin Varlamov > 77*2c766efcSKonstantin Varlamov __make_projected(_Pred& __pred, _Proj& __proj) { 78*2c766efcSKonstantin Varlamov return _ProjectedPred<_Pred, _Proj>(__pred, __proj); 79*2c766efcSKonstantin Varlamov } 80*2c766efcSKonstantin Varlamov 81*2c766efcSKonstantin Varlamov // Avoid creating the functor and just use the pristine comparator -- for certain algorithms, this would enable 82*2c766efcSKonstantin Varlamov // optimizations that rely on the type of the comparator. Additionally, this results in less layers of indirection in 83*2c766efcSKonstantin Varlamov // the call stack when the comparator is invoked, even in an unoptimized build. 84*2c766efcSKonstantin Varlamov template <class _Pred, class _Proj> 85*2c766efcSKonstantin Varlamov _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR static 86*2c766efcSKonstantin Varlamov __enable_if_t< 87*2c766efcSKonstantin Varlamov __can_use_pristine_comp<_Pred, _Proj>::value, 88*2c766efcSKonstantin Varlamov _Pred& 89*2c766efcSKonstantin Varlamov > 90*2c766efcSKonstantin Varlamov __make_projected(_Pred& __pred, _Proj&) { 91*2c766efcSKonstantin Varlamov return __pred; 92*2c766efcSKonstantin Varlamov } 93*2c766efcSKonstantin Varlamov 94*2c766efcSKonstantin Varlamov _LIBCPP_END_NAMESPACE_STD 95*2c766efcSKonstantin Varlamov 96ff3989e6SKonstantin Varlamov #if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) 97ff3989e6SKonstantin Varlamov 98ff3989e6SKonstantin Varlamov _LIBCPP_BEGIN_NAMESPACE_STD 99ff3989e6SKonstantin Varlamov 100ff3989e6SKonstantin Varlamov namespace ranges { 101ff3989e6SKonstantin Varlamov 1021cdec6c9SHui Xie template <class _Comp, class _Proj1, class _Proj2> 1031cdec6c9SHui Xie _LIBCPP_HIDE_FROM_ABI constexpr static 1041cdec6c9SHui Xie decltype(auto) __make_projected_comp(_Comp& __comp, _Proj1& __proj1, _Proj2& __proj2) { 1051cdec6c9SHui Xie if constexpr (same_as<decay_t<_Proj1>, identity> && same_as<decay_t<_Proj2>, identity> && 1061cdec6c9SHui Xie !is_member_pointer_v<decay_t<_Comp>>) { 1071cdec6c9SHui Xie // Avoid creating the lambda and just use the pristine comparator -- for certain algorithms, this would enable 1081cdec6c9SHui Xie // optimizations that rely on the type of the comparator. 1091cdec6c9SHui Xie return __comp; 1101cdec6c9SHui Xie 1111cdec6c9SHui Xie } else { 1121cdec6c9SHui Xie return [&](auto&& __lhs, auto&& __rhs) { 1131cdec6c9SHui Xie return std::invoke(__comp, 1141cdec6c9SHui Xie std::invoke(__proj1, std::forward<decltype(__lhs)>(__lhs)), 1151cdec6c9SHui Xie std::invoke(__proj2, std::forward<decltype(__rhs)>(__rhs))); 1161cdec6c9SHui Xie }; 1171cdec6c9SHui Xie } 1181cdec6c9SHui Xie } 1191cdec6c9SHui Xie 120ff3989e6SKonstantin Varlamov } // namespace ranges 121ff3989e6SKonstantin Varlamov 122ff3989e6SKonstantin Varlamov _LIBCPP_END_NAMESPACE_STD 123ff3989e6SKonstantin Varlamov 124ff3989e6SKonstantin Varlamov #endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) 125ff3989e6SKonstantin Varlamov 126ff3989e6SKonstantin Varlamov #endif // _LIBCPP___ALGORITHM_MAKE_PROJECTED_H 127