1 | // -*- C++ -*- |
2 | //===----------------------------------------------------------------------===// |
3 | // |
4 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
5 | // See https://llvm.org/LICENSE.txt for license information. |
6 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
7 | // |
8 | //===----------------------------------------------------------------------===// |
9 | |
10 | #ifndef _LIBCPP___FUNCTIONAL_BIND_H |
11 | #define _LIBCPP___FUNCTIONAL_BIND_H |
12 | |
13 | #include <__config> |
14 | #include <__functional/weak_result_type.h> |
15 | #include <__fwd/functional.h> |
16 | #include <__type_traits/decay.h> |
17 | #include <__type_traits/invoke.h> |
18 | #include <__type_traits/is_reference_wrapper.h> |
19 | #include <__type_traits/is_void.h> |
20 | #include <tuple> |
21 | |
22 | #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
23 | # pragma GCC system_header |
24 | #endif |
25 | |
26 | _LIBCPP_BEGIN_NAMESPACE_STD |
27 | |
28 | template <class _Tp> |
29 | struct is_bind_expression |
30 | : _If< _IsSame<_Tp, __remove_cvref_t<_Tp> >::value, false_type, is_bind_expression<__remove_cvref_t<_Tp> > > {}; |
31 | |
32 | #if _LIBCPP_STD_VER >= 17 |
33 | template <class _Tp> |
34 | inline constexpr bool is_bind_expression_v = is_bind_expression<_Tp>::value; |
35 | #endif |
36 | |
37 | template <class _Tp> |
38 | struct is_placeholder |
39 | : _If< _IsSame<_Tp, __remove_cvref_t<_Tp> >::value, |
40 | integral_constant<int, 0>, |
41 | is_placeholder<__remove_cvref_t<_Tp> > > {}; |
42 | |
43 | #if _LIBCPP_STD_VER >= 17 |
44 | template <class _Tp> |
45 | inline constexpr int is_placeholder_v = is_placeholder<_Tp>::value; |
46 | #endif |
47 | |
48 | namespace placeholders { |
49 | |
50 | template <int _Np> |
51 | struct __ph {}; |
52 | |
53 | // C++17 recommends that we implement placeholders as `inline constexpr`, but allows |
54 | // implementing them as `extern <implementation-defined>`. Libc++ implements them as |
55 | // `extern const` in all standard modes to avoid an ABI break in C++03: making them |
56 | // `inline constexpr` requires removing their definition in the shared library to |
57 | // avoid ODR violations, which is an ABI break. |
58 | // |
59 | // In practice, since placeholders are empty, `extern const` is almost impossible |
60 | // to distinguish from `inline constexpr` from a usage stand point. |
61 | _LIBCPP_EXPORTED_FROM_ABI extern const __ph<1> _1; |
62 | _LIBCPP_EXPORTED_FROM_ABI extern const __ph<2> _2; |
63 | _LIBCPP_EXPORTED_FROM_ABI extern const __ph<3> _3; |
64 | _LIBCPP_EXPORTED_FROM_ABI extern const __ph<4> _4; |
65 | _LIBCPP_EXPORTED_FROM_ABI extern const __ph<5> _5; |
66 | _LIBCPP_EXPORTED_FROM_ABI extern const __ph<6> _6; |
67 | _LIBCPP_EXPORTED_FROM_ABI extern const __ph<7> _7; |
68 | _LIBCPP_EXPORTED_FROM_ABI extern const __ph<8> _8; |
69 | _LIBCPP_EXPORTED_FROM_ABI extern const __ph<9> _9; |
70 | _LIBCPP_EXPORTED_FROM_ABI extern const __ph<10> _10; |
71 | |
72 | } // namespace placeholders |
73 | |
74 | template <int _Np> |
75 | struct is_placeholder<placeholders::__ph<_Np> > : public integral_constant<int, _Np> {}; |
76 | |
77 | #ifndef _LIBCPP_CXX03_LANG |
78 | |
79 | template <class _Tp, class _Uj> |
80 | inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp& __mu(reference_wrapper<_Tp> __t, _Uj&) { |
81 | return __t.get(); |
82 | } |
83 | |
84 | template <class _Ti, class... _Uj, size_t... _Indx> |
85 | inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __invoke_result_t<_Ti&, _Uj...> |
86 | __mu_expand(_Ti& __ti, tuple<_Uj...>& __uj, __tuple_indices<_Indx...>) { |
87 | return __ti(std::forward<_Uj>(std::get<_Indx>(__uj))...); |
88 | } |
89 | |
90 | template <class _Ti, class... _Uj, __enable_if_t<is_bind_expression<_Ti>::value, int> = 0> |
91 | inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __invoke_result_t<_Ti&, _Uj...> |
92 | __mu(_Ti& __ti, tuple<_Uj...>& __uj) { |
93 | typedef typename __make_tuple_indices<sizeof...(_Uj)>::type __indices; |
94 | return std::__mu_expand(__ti, __uj, __indices()); |
95 | } |
96 | |
97 | template <bool _IsPh, class _Ti, class _Uj> |
98 | struct __mu_return2 {}; |
99 | |
100 | template <class _Ti, class _Uj> |
101 | struct __mu_return2<true, _Ti, _Uj> { |
102 | typedef typename tuple_element<is_placeholder<_Ti>::value - 1, _Uj>::type type; |
103 | }; |
104 | |
105 | template <class _Ti, class _Uj, __enable_if_t<0 < is_placeholder<_Ti>::value, int> = 0> |
106 | inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 |
107 | typename __mu_return2<0 < is_placeholder<_Ti>::value, _Ti, _Uj>::type |
108 | __mu(_Ti&, _Uj& __uj) { |
109 | const size_t __indx = is_placeholder<_Ti>::value - 1; |
110 | return std::forward<typename tuple_element<__indx, _Uj>::type>(std::get<__indx>(__uj)); |
111 | } |
112 | |
113 | template <class _Ti, |
114 | class _Uj, |
115 | __enable_if_t<!is_bind_expression<_Ti>::value && is_placeholder<_Ti>::value == 0 && |
116 | !__is_reference_wrapper<_Ti>::value, |
117 | int> = 0> |
118 | inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Ti& __mu(_Ti& __ti, _Uj&) { |
119 | return __ti; |
120 | } |
121 | |
122 | template <class _Ti, bool _IsReferenceWrapper, bool _IsBindEx, bool _IsPh, class _TupleUj> |
123 | struct __mu_return_impl; |
124 | |
125 | template <bool _Invokable, class _Ti, class... _Uj> |
126 | struct __mu_return_invokable // false |
127 | { |
128 | typedef __nat type; |
129 | }; |
130 | |
131 | template <class _Ti, class... _Uj> |
132 | struct __mu_return_invokable<true, _Ti, _Uj...> { |
133 | using type _LIBCPP_NODEBUG = __invoke_result_t<_Ti&, _Uj...>; |
134 | }; |
135 | |
136 | template <class _Ti, class... _Uj> |
137 | struct __mu_return_impl<_Ti, false, true, false, tuple<_Uj...> > |
138 | : public __mu_return_invokable<__is_invocable_v<_Ti&, _Uj...>, _Ti, _Uj...> {}; |
139 | |
140 | template <class _Ti, class _TupleUj> |
141 | struct __mu_return_impl<_Ti, false, false, true, _TupleUj> { |
142 | typedef typename tuple_element<is_placeholder<_Ti>::value - 1, _TupleUj>::type&& type; |
143 | }; |
144 | |
145 | template <class _Ti, class _TupleUj> |
146 | struct __mu_return_impl<_Ti, true, false, false, _TupleUj> { |
147 | typedef typename _Ti::type& type; |
148 | }; |
149 | |
150 | template <class _Ti, class _TupleUj> |
151 | struct __mu_return_impl<_Ti, false, false, false, _TupleUj> { |
152 | typedef _Ti& type; |
153 | }; |
154 | |
155 | template <class _Ti, class _TupleUj> |
156 | struct __mu_return |
157 | : public __mu_return_impl< |
158 | _Ti, |
159 | __is_reference_wrapper<_Ti>::value, |
160 | is_bind_expression<_Ti>::value, |
161 | 0 < is_placeholder<_Ti>::value && is_placeholder<_Ti>::value <= tuple_size<_TupleUj>::value, |
162 | _TupleUj> {}; |
163 | |
164 | template <class _Fp, class _BoundArgs, class _TupleUj> |
165 | struct __is_valid_bind_return { |
166 | static const bool value = false; |
167 | }; |
168 | |
169 | template <class _Fp, class... _BoundArgs, class _TupleUj> |
170 | struct __is_valid_bind_return<_Fp, tuple<_BoundArgs...>, _TupleUj> { |
171 | static const bool value = __is_invocable_v<_Fp, typename __mu_return<_BoundArgs, _TupleUj>::type...>; |
172 | }; |
173 | |
174 | template <class _Fp, class... _BoundArgs, class _TupleUj> |
175 | struct __is_valid_bind_return<_Fp, const tuple<_BoundArgs...>, _TupleUj> { |
176 | static const bool value = __is_invocable_v<_Fp, typename __mu_return<const _BoundArgs, _TupleUj>::type...>; |
177 | }; |
178 | |
179 | template <class _Fp, class _BoundArgs, class _TupleUj, bool = __is_valid_bind_return<_Fp, _BoundArgs, _TupleUj>::value> |
180 | struct __bind_return; |
181 | |
182 | template <class _Fp, class... _BoundArgs, class _TupleUj> |
183 | struct __bind_return<_Fp, tuple<_BoundArgs...>, _TupleUj, true> { |
184 | using type _LIBCPP_NODEBUG = __invoke_result_t<_Fp&, typename __mu_return<_BoundArgs, _TupleUj>::type...>; |
185 | }; |
186 | |
187 | template <class _Fp, class... _BoundArgs, class _TupleUj> |
188 | struct __bind_return<_Fp, const tuple<_BoundArgs...>, _TupleUj, true> { |
189 | using type _LIBCPP_NODEBUG = __invoke_result_t<_Fp&, typename __mu_return<const _BoundArgs, _TupleUj>::type...>; |
190 | }; |
191 | |
192 | template <class _Fp, class _BoundArgs, size_t... _Indx, class _Args> |
193 | inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 typename __bind_return<_Fp, _BoundArgs, _Args>::type |
194 | __apply_functor(_Fp& __f, _BoundArgs& __bound_args, __tuple_indices<_Indx...>, _Args&& __args) { |
195 | return std::__invoke(__f, std::__mu(std::get<_Indx>(__bound_args), __args)...); |
196 | } |
197 | |
198 | template <class _Fp, class... _BoundArgs> |
199 | class __bind : public __weak_result_type<__decay_t<_Fp> > { |
200 | protected: |
201 | using _Fd _LIBCPP_NODEBUG = __decay_t<_Fp>; |
202 | typedef tuple<__decay_t<_BoundArgs>...> _Td; |
203 | |
204 | private: |
205 | _Fd __f_; |
206 | _Td __bound_args_; |
207 | |
208 | typedef typename __make_tuple_indices<sizeof...(_BoundArgs)>::type __indices; |
209 | |
210 | public: |
211 | template < |
212 | class _Gp, |
213 | class... _BA, |
214 | __enable_if_t<is_constructible<_Fd, _Gp>::value && !is_same<__libcpp_remove_reference_t<_Gp>, __bind>::value, |
215 | int> = 0> |
216 | _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit __bind(_Gp&& __f, _BA&&... __bound_args) |
217 | : __f_(std::forward<_Gp>(__f)), __bound_args_(std::forward<_BA>(__bound_args)...) {} |
218 | |
219 | template <class... _Args> |
220 | _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 typename __bind_return<_Fd, _Td, tuple<_Args&&...> >::type |
221 | operator()(_Args&&... __args) { |
222 | return std::__apply_functor(__f_, __bound_args_, __indices(), tuple<_Args&&...>(std::forward<_Args>(__args)...)); |
223 | } |
224 | |
225 | template <class... _Args> |
226 | _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 |
227 | typename __bind_return<const _Fd, const _Td, tuple<_Args&&...> >::type |
228 | operator()(_Args&&... __args) const { |
229 | return std::__apply_functor(__f_, __bound_args_, __indices(), tuple<_Args&&...>(std::forward<_Args>(__args)...)); |
230 | } |
231 | }; |
232 | |
233 | template <class _Fp, class... _BoundArgs> |
234 | struct is_bind_expression<__bind<_Fp, _BoundArgs...> > : public true_type {}; |
235 | |
236 | template <class _Rp, class _Fp, class... _BoundArgs> |
237 | class __bind_r : public __bind<_Fp, _BoundArgs...> { |
238 | typedef __bind<_Fp, _BoundArgs...> base; |
239 | typedef typename base::_Fd _Fd; |
240 | typedef typename base::_Td _Td; |
241 | |
242 | public: |
243 | typedef _Rp result_type; |
244 | |
245 | template < |
246 | class _Gp, |
247 | class... _BA, |
248 | __enable_if_t<is_constructible<_Fd, _Gp>::value && !is_same<__libcpp_remove_reference_t<_Gp>, __bind_r>::value, |
249 | int> = 0> |
250 | _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit __bind_r(_Gp&& __f, _BA&&... __bound_args) |
251 | : base(std::forward<_Gp>(__f), std::forward<_BA>(__bound_args)...) {} |
252 | |
253 | template < |
254 | class... _Args, |
255 | __enable_if_t<is_convertible<typename __bind_return<_Fd, _Td, tuple<_Args&&...> >::type, result_type>::value || |
256 | is_void<_Rp>::value, |
257 | int> = 0> |
258 | _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 result_type operator()(_Args&&... __args) { |
259 | return std::__invoke_r<_Rp>(static_cast<base&>(*this), std::forward<_Args>(__args)...); |
260 | } |
261 | |
262 | template <class... _Args, |
263 | __enable_if_t<is_convertible<typename __bind_return<const _Fd, const _Td, tuple<_Args&&...> >::type, |
264 | result_type>::value || |
265 | is_void<_Rp>::value, |
266 | int> = 0> |
267 | _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 result_type operator()(_Args&&... __args) const { |
268 | return std::__invoke_r<_Rp>(static_cast<base const&>(*this), std::forward<_Args>(__args)...); |
269 | } |
270 | }; |
271 | |
272 | template <class _Rp, class _Fp, class... _BoundArgs> |
273 | struct is_bind_expression<__bind_r<_Rp, _Fp, _BoundArgs...> > : public true_type {}; |
274 | |
275 | template <class _Fp, class... _BoundArgs> |
276 | inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bind<_Fp, _BoundArgs...> |
277 | bind(_Fp&& __f, _BoundArgs&&... __bound_args) { |
278 | typedef __bind<_Fp, _BoundArgs...> type; |
279 | return type(std::forward<_Fp>(__f), std::forward<_BoundArgs>(__bound_args)...); |
280 | } |
281 | |
282 | template <class _Rp, class _Fp, class... _BoundArgs> |
283 | inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bind_r<_Rp, _Fp, _BoundArgs...> |
284 | bind(_Fp&& __f, _BoundArgs&&... __bound_args) { |
285 | typedef __bind_r<_Rp, _Fp, _BoundArgs...> type; |
286 | return type(std::forward<_Fp>(__f), std::forward<_BoundArgs>(__bound_args)...); |
287 | } |
288 | |
289 | #endif // _LIBCPP_CXX03_LANG |
290 | |
291 | _LIBCPP_END_NAMESPACE_STD |
292 | |
293 | #endif // _LIBCPP___FUNCTIONAL_BIND_H |
294 | |