xref: /freebsd-src/contrib/llvm-project/libcxx/include/__algorithm/make_projected.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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