source: mainline/uspace/lib/cpp/include/__bits/functional/function.hpp@ e49d0ac

Last change on this file since e49d0ac 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: 10.1 KB
Line 
1/*
2 * SPDX-FileCopyrightText: 2018 Jaroslav Jindrak
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#ifndef LIBCPP_BITS_FUNCTIONAL_FUNCTION
8#define LIBCPP_BITS_FUNCTIONAL_FUNCTION
9
10#include <__bits/functional/conditional_function_typedefs.hpp>
11#include <__bits/functional/reference_wrapper.hpp>
12#include <__bits/memory/allocator_arg.hpp>
13#include <__bits/memory/allocator_traits.hpp>
14#include <typeinfo>
15#include <type_traits>
16#include <utility>
17
18namespace std
19{
20 /**
21 * 20.9.12, polymorphic function adaptors:
22 */
23
24 namespace aux
25 {
26 // TODO: fix this
27 /* template<class, class T, class... Args> */
28 /* struct is_callable_impl: false_type */
29 /* { /1* DUMMY BODY *1/ }; */
30
31 /* template<class, class R, class... Args> */
32 /* struct is_callable_impl< */
33 /* void_t<decltype(aux::invoke(declval<R(Args...)>(), declval<Args>()..., R))>, */
34 /* R, Args... */
35 /* > : true_type */
36 /* { /1* DUMMY BODY *1/ }; */
37
38 /* template<class T> */
39 /* struct is_callable: is_callable_impl<void_t<>, T> */
40 /* { /1* DUMMY BODY *1/ }; */
41
42 template<class Callable, class R, class... Args>
43 R invoke_callable(Callable* clbl, Args&&... args)
44 {
45 return (*clbl)(forward<Args>(args)...);
46 }
47
48 template<class Callable>
49 void copy_callable(Callable* to, Callable* from)
50 {
51 new(to) Callable{*from};
52 }
53
54 template<class Callable>
55 void destroy_callable(Callable* clbl)
56 {
57 if (clbl)
58 clbl->~Callable();
59 }
60 }
61
62 // TODO: implement
63 class bad_function_call;
64
65 template<class>
66 class function; // undefined
67
68 /**
69 * Note: Ideally, this implementation wouldn't
70 * copy the target if it was a pointer to
71 * a function, but for the simplicity of the
72 * implementation, we do copy even in that
73 * case for now. It would be a nice optimization
74 * if this was changed in the future.
75 */
76 template<class R, class... Args>
77 class function<R(Args...)>
78 : public aux::conditional_function_typedefs<Args...>
79 {
80 public:
81 using result_type = R;
82
83 /**
84 * 20.9.12.2.1, construct/copy/destroy:
85 */
86
87 function() noexcept
88 : callable_{}, callable_size_{}, call_{},
89 copy_{}, dest_{}
90 { /* DUMMY BODY */ }
91
92 function(nullptr_t) noexcept
93 : function{}
94 { /* DUMMY BODY */ }
95
96 function(const function& other)
97 : callable_{}, callable_size_{other.callable_size_},
98 call_{other.call_}, copy_{other.copy_}, dest_{other.dest_}
99 {
100 callable_ = new uint8_t[callable_size_];
101 (*copy_)(callable_, other.callable_);
102 }
103
104 function(function&& other)
105 : callable_{other.callable_}, callable_size_{other.callable_size_},
106 call_{other.call_}, copy_{other.copy_}, dest_{other.dest_}
107 {
108 other.callable_ = nullptr;
109 other.callable_size_ = size_t{};
110 other.call_ = nullptr;
111 other.copy_ = nullptr;
112 other.dest_ = nullptr;
113 }
114
115 // TODO: shall not participate in overloading unless aux::is_callable<F>
116 template<class F>
117 function(F f)
118 : callable_{}, callable_size_{sizeof(F)},
119 call_{(call_t)aux::invoke_callable<F, R, Args...>},
120 copy_{(copy_t)aux::copy_callable<F>},
121 dest_{(dest_t)aux::destroy_callable<F>}
122 {
123 callable_ = new uint8_t[callable_size_];
124 (*copy_)(callable_, (uint8_t*)&f);
125 }
126
127 /**
128 * Note: For the moment we're ignoring the allocator
129 * for simplicity of the implementation.
130 */
131
132 template<class A>
133 function(allocator_arg_t, const A& a) noexcept
134 : function{}
135 { /* DUMMY BODY */ }
136
137 template<class A>
138 function(allocator_arg_t, const A& a, nullptr_t) noexcept
139 : function{}
140 { /* DUMMY BODY */ }
141
142 template<class A>
143 function(allocator_arg_t, const A& a, const function& other)
144 : function{other}
145 { /* DUMMY BODY */ }
146
147 template<class A>
148 function(allocator_arg_t, const A& a, function&& other)
149 : function{move(other)}
150 { /* DUMMY BODY */ }
151
152 // TODO: shall not participate in overloading unless aux::is_callable<F>
153 template<class F, class A>
154 function(allocator_arg_t, const A& a, F f)
155 : function{f}
156 { /* DUMMY BODY */ }
157
158 function& operator=(const function& rhs)
159 {
160 function{rhs}.swap(*this);
161
162 return *this;
163 }
164
165 /**
166 * Note: We have to copy call_, copy_
167 * and dest_ because they can be templated
168 * by a type F we don't know.
169 */
170 function& operator=(function&& rhs)
171 {
172 clear_();
173
174 callable_ = rhs.callable_;
175 callable_size_ = rhs.callable_size_;
176 call_ = rhs.call_;
177 copy_ = rhs.copy_;
178 dest_ = rhs.dest_;
179
180 rhs.callable_ = nullptr;
181 rhs.callable_size_ = size_t{};
182 rhs.call_ = nullptr;
183 rhs.copy_ = nullptr;
184 rhs.dest_ = nullptr;
185
186 return *this;
187 }
188
189 function& operator=(nullptr_t) noexcept
190 {
191 clear_();
192
193 return *this;
194 }
195
196 // TODO: shall not participate in overloading unless aux::is_callable<F>
197 template<class F>
198 function& operator=(F&& f)
199 {
200 callable_size_ = sizeof(F);
201 callable_ = new uint8_t[callable_size_];
202 call_ = aux::invoke_callable<F, R, Args...>;
203 copy_ = aux::copy_callable<F>;
204 dest_ = aux::destroy_callable<F>;
205
206 (*copy_)(callable_, (uint8_t*)&f);
207 }
208
209 template<class F>
210 function& operator=(reference_wrapper<F> ref) noexcept
211 {
212 return (*this) = ref.get();
213 }
214
215 ~function()
216 {
217 if (callable_)
218 {
219 (*dest_)(callable_);
220 delete[] callable_;
221 }
222 }
223
224 /**
225 * 20.9.12.2.2, function modifiers:
226 */
227
228 void swap(function& other) noexcept
229 {
230 std::swap(callable_, other.callable_);
231 std::swap(callable_size_, other.callable_size_);
232 std::swap(call_, other.call_);
233 std::swap(copy_, other.copy_);
234 std::swap(dest_, other.dest_);
235 }
236
237 template<class F, class A>
238 void assign(F&& f, const A& a)
239 {
240 function{allocator_arg, a, forward<F>(f)}.swap(*this);
241 }
242
243 /**
244 * 20.9.12.2.3, function capacity:
245 */
246
247 explicit operator bool() const noexcept
248 {
249 return callable_ != nullptr;
250 }
251
252 /**
253 * 20.9.12.2.4, function invocation:
254 */
255
256 result_type operator()(Args... args) const
257 {
258 // TODO: throw bad_function_call if !callable_ || !call_
259 if constexpr (is_same_v<R, void>)
260 (*call_)(callable_, forward<Args>(args)...);
261 else
262 return (*call_)(callable_, forward<Args>(args)...);
263 }
264
265 /**
266 * 20.9.12.2.5, function target access:
267 */
268
269 const type_info& target_type() const noexcept
270 {
271 return typeid(*callable_);
272 }
273
274 template<class T>
275 T* target() noexcept
276 {
277 if (target_type() == typeid(T))
278 return (T*)callable_;
279 else
280 return nullptr;
281 }
282
283 template<class T>
284 const T* target() const noexcept
285 {
286 if (target_type() == typeid(T))
287 return (T*)callable_;
288 else
289 return nullptr;
290 }
291
292 private:
293 using call_t = R(*)(uint8_t*, Args&&...);
294 using copy_t = void (*)(uint8_t*, uint8_t*);
295 using dest_t = void (*)(uint8_t*);
296
297 uint8_t* callable_;
298 size_t callable_size_;
299 call_t call_;
300 copy_t copy_;
301 dest_t dest_;
302
303 void clear_()
304 {
305 if (callable_)
306 {
307 (*dest_)(callable_);
308 delete[] callable_;
309 callable_ = nullptr;
310 }
311 }
312 };
313
314 /**
315 * 20.9.12.2.6, null pointer comparisons:
316 */
317
318 template<class R, class... Args>
319 bool operator==(const function<R(Args...)>& f, nullptr_t) noexcept
320 {
321 return !f;
322 }
323
324 template<class R, class... Args>
325 bool operator==(nullptr_t, const function<R(Args...)>& f) noexcept
326 {
327 return !f;
328 }
329
330 template<class R, class... Args>
331 bool operator!=(const function<R(Args...)>& f, nullptr_t) noexcept
332 {
333 return (bool)f;
334 }
335
336 template<class R, class... Args>
337 bool operator!=(nullptr_t, const function<R(Args...)>& f) noexcept
338 {
339 return (bool)f;
340 }
341
342 /**
343 * 20.9.12.2.7, specialized algorithms:
344 */
345
346 template<class R, class... Args>
347 void swap(function<R(Args...)>& f1, function<R(Args...)>& f2)
348 {
349 f1.swap(f2);
350 }
351
352 template<class R, class... Args, class Alloc>
353 struct uses_allocator<function<R(Args...)>, Alloc>
354 : true_type
355 { /* DUMMY BODY */ };
356}
357
358#endif
Note: See TracBrowser for help on using the repository browser.