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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a6c3bf3 was b57a3ee, checked in by Dzejrou <dzejrou@…>, 7 years ago

cpp: refactored the library layout, everything from the impl directory was moved to the bits directory for the sake of consistency, updated copyright notices and include guards

  • Property mode set to 100644
File size: 11.5 KB
Line 
1/*
2 * Copyright (c) 2018 Jaroslav Jindrak
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#ifndef LIBCPP_BITS_FUNCTIONAL_FUNCTION
30#define LIBCPP_BITS_FUNCTIONAL_FUNCTION
31
32#include <__bits/functional/conditional_function_typedefs.hpp>
33#include <__bits/functional/reference_wrapper.hpp>
34#include <__bits/memory/allocator_arg.hpp>
35#include <__bits/memory/allocator_traits.hpp>
36#include <typeinfo>
37#include <type_traits>
38#include <utility>
39
40namespace std
41{
42 /**
43 * 20.9.12, polymorphic function adaptors:
44 */
45
46 namespace aux
47 {
48 // TODO: fix this
49 /* template<class, class T, class... Args> */
50 /* struct is_callable_impl: false_type */
51 /* { /1* DUMMY BODY *1/ }; */
52
53 /* template<class, class R, class... Args> */
54 /* struct is_callable_impl< */
55 /* void_t<decltype(aux::invoke(declval<R(Args...)>(), declval<Args>()..., R))>, */
56 /* R, Args... */
57 /* > : true_type */
58 /* { /1* DUMMY BODY *1/ }; */
59
60 /* template<class T> */
61 /* struct is_callable: is_callable_impl<void_t<>, T> */
62 /* { /1* DUMMY BODY *1/ }; */
63
64 template<class Callable, class R, class... Args>
65 R invoke_callable(Callable* clbl, Args&&... args)
66 {
67 return (*clbl)(forward<Args>(args)...);
68 }
69
70 template<class Callable>
71 void copy_callable(Callable* to, Callable* from)
72 {
73 new(to) Callable{*from};
74 }
75
76 template<class Callable>
77 void destroy_callable(Callable* clbl)
78 {
79 if (clbl)
80 clbl->~Callable();
81 }
82 }
83
84 // TODO: implement
85 class bad_function_call;
86
87 template<class>
88 class function; // undefined
89
90 /**
91 * Note: Ideally, this implementation wouldn't
92 * copy the target if it was a pointer to
93 * a function, but for the simplicity of the
94 * implementation, we do copy even in that
95 * case for now. It would be a nice optimization
96 * if this was changed in the future.
97 */
98 template<class R, class... Args>
99 class function<R(Args...)>
100 : public aux::conditional_function_typedefs<Args...>
101 {
102 public:
103 using result_type = R;
104
105 /**
106 * 20.9.12.2.1, construct/copy/destroy:
107 */
108
109 function() noexcept
110 : callable_{}, callable_size_{}, call_{},
111 copy_{}, dest_{}
112 { /* DUMMY BODY */ }
113
114 function(nullptr_t) noexcept
115 : function{}
116 { /* DUMMY BODY */ }
117
118 function(const function& other)
119 : callable_{}, callable_size_{other.callable_size_},
120 call_{other.call_}, copy_{other.copy_}, dest_{other.dest_}
121 {
122 callable_ = new uint8_t[callable_size_];
123 (*copy_)(callable_, other.callable_);
124 }
125
126 function(function&& other)
127 : callable_{other.callable_}, callable_size_{other.callable_size_},
128 call_{other.call_}, copy_{other.copy_}, dest_{other.dest_}
129 {
130 other.callable_ = nullptr;
131 other.callable_size_ = size_t{};
132 other.call_ = nullptr;
133 other.copy_ = nullptr;
134 other.dest_ = nullptr;
135 }
136
137 // TODO: shall not participate in overloading unless aux::is_callable<F>
138 template<class F>
139 function(F f)
140 : callable_{}, callable_size_{sizeof(F)},
141 call_{(call_t)aux::invoke_callable<F, R, Args...>},
142 copy_{(copy_t)aux::copy_callable<F>},
143 dest_{(dest_t)aux::destroy_callable<F>}
144 {
145 callable_ = new uint8_t[callable_size_];
146 (*copy_)(callable_, (uint8_t*)&f);
147 }
148
149 /**
150 * Note: For the moment we're ignoring the allocator
151 * for simplicity of the implementation.
152 */
153
154 template<class A>
155 function(allocator_arg_t, const A& a) noexcept
156 : function{}
157 { /* DUMMY BODY */ }
158
159 template<class A>
160 function(allocator_arg_t, const A& a, nullptr_t) noexcept
161 : function{}
162 { /* DUMMY BODY */ }
163
164 template<class A>
165 function(allocator_arg_t, const A& a, const function& other)
166 : function{other}
167 { /* DUMMY BODY */ }
168
169 template<class A>
170 function(allocator_arg_t, const A& a, function&& other)
171 : function{move(other)}
172 { /* DUMMY BODY */ }
173
174 // TODO: shall not participate in overloading unless aux::is_callable<F>
175 template<class F, class A>
176 function(allocator_arg_t, const A& a, F f)
177 : function{f}
178 { /* DUMMY BODY */ }
179
180 function& operator=(const function& rhs)
181 {
182 function{rhs}.swap(*this);
183
184 return *this;
185 }
186
187 /**
188 * Note: We have to copy call_, copy_
189 * and dest_ because they can be templated
190 * by a type F we don't know.
191 */
192 function& operator=(function&& rhs)
193 {
194 clear_();
195
196 callable_ = rhs.callable_;
197 callable_size_ = rhs.callable_size_;
198 call_ = rhs.call_;
199 copy_ = rhs.copy_;
200 dest_ = rhs.dest_;
201
202 rhs.callable_ = nullptr;
203 rhs.callable_size_ = size_t{};
204 rhs.call_ = nullptr;
205 rhs.copy_ = nullptr;
206 rhs.dest_ = nullptr;
207
208 return *this;
209 }
210
211 function& operator=(nullptr_t) noexcept
212 {
213 clear_();
214
215 return *this;
216 }
217
218 // TODO: shall not participate in overloading unless aux::is_callable<F>
219 template<class F>
220 function& operator=(F&& f)
221 {
222 callable_size_ = sizeof(F);
223 callable_ = new uint8_t[callable_size_];
224 call_ = aux::invoke_callable<F, R, Args...>;
225 copy_ = aux::copy_callable<F>;
226 dest_ = aux::destroy_callable<F>;
227
228 (*copy_)(callable_, (uint8_t*)&f);
229 }
230
231 template<class F>
232 function& operator=(reference_wrapper<F> ref) noexcept
233 {
234 return (*this) = ref.get();
235 }
236
237 ~function()
238 {
239 if (callable_)
240 {
241 (*dest_)(callable_);
242 delete[] callable_;
243 }
244 }
245
246 /**
247 * 20.9.12.2.2, function modifiers:
248 */
249
250 void swap(function& other) noexcept
251 {
252 std::swap(callable_, other.callable_);
253 std::swap(callable_size_, other.callable_size_);
254 std::swap(call_, other.call_);
255 std::swap(copy_, other.copy_);
256 std::swap(dest_, other.dest_);
257 }
258
259 template<class F, class A>
260 void assign(F&& f, const A& a)
261 {
262 function{allocator_arg, a, forward<F>(f)}.swap(*this);
263 }
264
265 /**
266 * 20.9.12.2.3, function capacity:
267 */
268
269 explicit operator bool() const noexcept
270 {
271 return callable_ != nullptr;
272 }
273
274 /**
275 * 20.9.12.2.4, function invocation:
276 */
277
278 result_type operator()(Args... args) const
279 {
280 // TODO: throw bad_function_call if !callable_ || !call_
281 if constexpr (is_same_v<R, void>)
282 (*call_)(callable_, forward<Args>(args)...);
283 else
284 return (*call_)(callable_, forward<Args>(args)...);
285 }
286
287 /**
288 * 20.9.12.2.5, function target access:
289 */
290
291 const type_info& target_type() const noexcept
292 {
293 return typeid(*callable_);
294 }
295
296 template<class T>
297 T* target() noexcept
298 {
299 if (target_type() == typeid(T))
300 return (T*)callable_;
301 else
302 return nullptr;
303 }
304
305 template<class T>
306 const T* target() const noexcept
307 {
308 if (target_type() == typeid(T))
309 return (T*)callable_;
310 else
311 return nullptr;
312 }
313
314 private:
315 using call_t = R(*)(uint8_t*, Args&&...);
316 using copy_t = void (*)(uint8_t*, uint8_t*);
317 using dest_t = void (*)(uint8_t*);
318
319 uint8_t* callable_;
320 size_t callable_size_;
321 call_t call_;
322 copy_t copy_;
323 dest_t dest_;
324
325 void clear_()
326 {
327 if (callable_)
328 {
329 (*dest_)(callable_);
330 delete[] callable_;
331 callable_ = nullptr;
332 }
333 }
334 };
335
336 /**
337 * 20.9.12.2.6, null pointer comparisons:
338 */
339
340 template<class R, class... Args>
341 bool operator==(const function<R(Args...)>& f, nullptr_t) noexcept
342 {
343 return !f;
344 }
345
346 template<class R, class... Args>
347 bool operator==(nullptr_t, const function<R(Args...)>& f) noexcept
348 {
349 return !f;
350 }
351
352 template<class R, class... Args>
353 bool operator!=(const function<R(Args...)>& f, nullptr_t) noexcept
354 {
355 return (bool)f;
356 }
357
358 template<class R, class... Args>
359 bool operator!=(nullptr_t, const function<R(Args...)>& f) noexcept
360 {
361 return (bool)f;
362 }
363
364 /**
365 * 20.9.12.2.7, specialized algorithms:
366 */
367
368 template<class R, class... Args>
369 void swap(function<R(Args...)>& f1, function<R(Args...)>& f2)
370 {
371 f1.swap(f2);
372 }
373
374 template<class R, class... Args, class Alloc>
375 struct uses_allocator<function<R(Args...)>, Alloc>
376 : true_type
377 { /* DUMMY BODY */ };
378}
379
380#endif
Note: See TracBrowser for help on using the repository browser.