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

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

cpp: changed internal to bits to avoid include space pollusion, fixed old std::hel:: bugs in files that weren't touched since

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