source: mainline/uspace/lib/cpp/include/__bits/functional/bind.hpp@ c6f23a7

Last change on this file since c6f23a7 was b57ba05, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 3 years ago

Update headers in C++ files

  • Property mode set to 100644
File size: 7.5 KB
Line 
1/*
2 * SPDX-FileCopyrightText: 2019 Jaroslav Jindrak
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#ifndef LIBCPP_BITS_FUNCTIONAL_BIND
8#define LIBCPP_BITS_FUNCTIONAL_BIND
9
10#include <__bits/functional/function.hpp>
11#include <__bits/functional/invoke.hpp>
12#include <__bits/functional/reference_wrapper.hpp>
13#include <cassert>
14#include <tuple>
15#include <type_traits>
16#include <utility>
17
18namespace std
19{
20 /**
21 * 20.9.10, bind:
22 */
23
24 namespace aux
25 {
26 template<int N>
27 struct placeholder_t
28 {
29 constexpr placeholder_t() = default;
30 constexpr placeholder_t(const placeholder_t&) = default;
31 constexpr placeholder_t(placeholder_t&&) = default;
32 };
33 }
34
35 template<class T>
36 struct is_placeholder: integral_constant<int, 0>
37 { /* DUMMY BODY */ };
38
39 template<int N> // Note: const because they are all constexpr.
40 struct is_placeholder<const aux::placeholder_t<N>>
41 : integral_constant<int, N>
42 { /* DUMMY BODY */ };
43
44 template<class T>
45 inline constexpr int is_placeholder_v = is_placeholder<T>::value;
46
47 namespace aux
48 {
49 /**
50 * Note: Our internal bind return type has an extra type
51 * template parameter and an extra bool template parameter.
52 * We use this for the special version of bind that has
53 * the return type to have a result_type typedef
54 * (i.e. when the bool is true, the extra type parameter
55 * is typedefed as result_type - see the structure below).
56 * This is just a simplification of the implementation
57 * so that we don't need to have two return types for
58 * the two bind functions, because unlike function or
59 * mem_fn, we know exactly when to make the typedef.
60 */
61
62 template<class, bool = false>
63 struct bind_conditional_result_type
64 { /* DUMMY BODY */ };
65
66 template<class R>
67 struct bind_conditional_result_type<R, true>
68 {
69 using result_type = R;
70 };
71
72 template<class, bool, class, class...>
73 class bind_t;
74
75 /**
76 * Filter class that uses its overloaded operator[]
77 * to filter our placeholders, reference_wrappers and bind
78 * subexpressions and replace them with the correct
79 * arguments (extracts references, calls the subexpressions etc).
80 */
81 template<class... Args>
82 class bind_arg_filter
83 {
84 public:
85 bind_arg_filter(Args&&... args)
86 : args_{forward<Args>(args)...}
87 { /* DUMMY BODY */ }
88
89 template<class T>
90 constexpr decltype(auto) operator[](T&& t)
91 {
92 return forward<T>(t);
93 }
94
95 template<int N>
96 constexpr decltype(auto) operator[](const placeholder_t<N>)
97 { // Since placeholders are constexpr, this is the best match for them.
98 /**
99 * Come on, it's int! Why not use -1 as not placeholder
100 * and start them at 0? -.-
101 */
102 return get<N - 1>(args_);
103 }
104
105 template<class T>
106 constexpr T& operator[](reference_wrapper<T> ref)
107 {
108 return ref.get();
109 }
110
111 template<class R, bool B, class F, class... BindArgs>
112 constexpr decltype(auto) operator[](const bind_t<R, B, F, BindArgs...> b)
113 {
114 __unimplemented();
115 return b; // TODO: bind subexpressions
116 }
117
118
119 private:
120 tuple<Args...> args_;
121 };
122
123 template<class R, bool HasResultType, class F, class... Args>
124 class bind_t: public bind_conditional_result_type<R, HasResultType>
125 {
126 public:
127 template<class G, class... BoundArgs>
128 constexpr bind_t(G&& g, BoundArgs&&... args)
129 : func_{forward<F>(g)},
130 bound_args_{forward<Args>(args)...}
131 { /* DUMMY BODY */ }
132
133 constexpr bind_t(const bind_t& other) = default;
134 constexpr bind_t(bind_t&& other) = default;
135
136 template<class... ActualArgs>
137 constexpr decltype(auto) operator()(ActualArgs&&... args)
138 {
139 return invoke_(
140 make_index_sequence<sizeof...(Args)>{},
141 forward<ActualArgs>(args)...
142 );
143 }
144
145 private: // TODO: This has problem with member function pointers.
146 function<remove_reference_t<F>> func_;
147 tuple<decay_t<Args>...> bound_args_;
148
149 template<size_t... Is, class... ActualArgs>
150 constexpr decltype(auto) invoke_(
151 index_sequence<Is...>, ActualArgs&&... args
152 )
153 {
154 /**
155 * The expression filter[bound_args_[bind_arg_index<Is>()]]...
156 * here expands bind_arg_index to 0, 1, ... sizeof...(ActualArgs) - 1
157 * and then passes this variadic list of indices to the bound_args_
158 * tuple which extracts the bound args from it.
159 * Our filter will then have its operator[] called on each of them
160 * and filter out the placeholders, reference_wrappers etc and changes
161 * them to the actual arguments.
162 */
163 bind_arg_filter<ActualArgs...> filter{forward<ActualArgs>(args)...};
164
165 return aux::INVOKE(
166 func_,
167 filter[get<Is>(bound_args_)]...
168 );
169 }
170 };
171 }
172
173 template<class T>
174 struct is_bind_expression: false_type
175 { /* DUMMY BODY */ };
176
177 template<class R, bool B, class F, class... Args>
178 struct is_bind_expression<aux::bind_t<R, B, F, Args...>>
179 : true_type
180 { /* DUMMY BODY */ };
181
182 template<class F, class... Args>
183 aux::bind_t<void, false, F, Args...> bind(F&& f, Args&&... args)
184 {
185 return aux::bind_t<void, false, F, Args...>{forward<F>(f), forward<Args>(args)...};
186 }
187
188 template<class R, class F, class... Args>
189 aux::bind_t<R, true, F, Args...> bind(F&& f, Args&&... args)
190 {
191 return aux::bind_t<R, true, F, Args...>{forward<F>(f), forward<Args>(args)...};
192 }
193
194 namespace placeholders
195 {
196 /**
197 * Note: The number of placeholders is
198 * implementation defined, we've chosen
199 * 8 because it is a nice number
200 * and should be enough for any function
201 * call.
202 * Note: According to the C++14 standard, these
203 * are all extern non-const. We decided to use
204 * the C++17 form of them being inline constexpr
205 * because it is more convenient, makes sense
206 * and would eventually need to be upgraded
207 * anyway.
208 */
209 inline constexpr aux::placeholder_t<1> _1;
210 inline constexpr aux::placeholder_t<2> _2;
211 inline constexpr aux::placeholder_t<3> _3;
212 inline constexpr aux::placeholder_t<4> _4;
213 inline constexpr aux::placeholder_t<5> _5;
214 inline constexpr aux::placeholder_t<6> _6;
215 inline constexpr aux::placeholder_t<7> _7;
216 inline constexpr aux::placeholder_t<8> _8;
217 }
218}
219
220#endif
Note: See TracBrowser for help on using the repository browser.