1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef LIB_FIT_INCLUDE_LIB_FIT_FUNCTION_H_
6 #define LIB_FIT_INCLUDE_LIB_FIT_FUNCTION_H_
7
8 #include <type_traits>
9
10 #include "internal/function.h"
11 #include "internal/utility.h"
12 #include "traits.h"
13
14 namespace fit {
15
16 template <size_t inline_target_size, bool require_inline, typename FunctionType>
17 class function_impl {
18 static_assert(std::is_function<FunctionType>::value,
19 "fit::function must be instantiated with a function type, such as void() or "
20 "int(char*, bool)");
21 };
22
23 template <size_t inline_target_size, bool require_inline, typename FunctionType>
24 class callback_impl {
25 static_assert(std::is_function<FunctionType>::value,
26 "fit::callback must be instantiated with a function type, such as void() or "
27 "int(char*, bool)");
28 };
29
30 // The default size allowance for storing a target inline within a function
31 // object, in bytes. This default allows for inline storage of targets
32 // as big as two pointers, such as an object pointer and a pointer to a member
33 // function.
34 constexpr size_t default_inline_target_size = sizeof(void*) * 2;
35
36 // A |fit::function| is a move-only polymorphic function wrapper.
37 //
38 // If you need a class with similar characteristics that also ensures
39 // "run-once" semantics (such as callbacks shared with timeouts, or for
40 // service requests with redundant, failover, or fallback service providers),
41 // see |fit::callback|.
42 //
43 // |fit::function<T>| behaves like |std::function<T>| except that it is
44 // move-only instead of copyable, so it can hold targets that cannot be copied,
45 // such as mutable lambdas, and immutable lambdas that capture move-only
46 // objects.
47 //
48 // Targets of up to |inline_target_size| bytes in size are stored inline within
49 // the function object without incurring any heap allocation. Larger callable
50 // objects will be moved to the heap as required. |inline_target_size| is
51 // rounded up to a multiple of sizeof(void*).
52 //
53 // See also |fit::inline_function<T, size>| for more control over allocation
54 // behavior.
55 //
56 // SYNOPSIS
57 //
58 // |T| is the function's signature. e.g. void(int, std::string).
59 //
60 // |inline_target_size| is the minimum size of target that is guaranteed to
61 // fit within a function without requiring heap allocation.
62 // Defaults to |default_inline_target_size|.
63 //
64 // Class members are documented in |fit::function_impl|, below.
65 //
66 // EXAMPLES
67 //
68 // -
69 // https://fuchsia.googlesource.com/fuchsia/+/HEAD/sdk/lib/fit/test/examples/function_example1.cc
70 // -
71 // https://fuchsia.googlesource.com/fuchsia/+/HEAD/sdk/lib/fit/test/examples/function_example2.cc
72 //
73 template <typename T, size_t inline_target_size = default_inline_target_size>
74 using function = function_impl<internal::RoundUpToWord(inline_target_size),
75 /*require_inline=*/false, T>;
76
77 // A move-only callable object wrapper that forces callables to be stored inline
78 // and never performs heap allocation.
79 //
80 // Behaves just like |fit::function<T, inline_target_size>| except that
81 // attempting to store a target larger than |inline_target_size| will fail to
82 // compile.
83 template <typename T, size_t inline_target_size = default_inline_target_size>
84 using inline_function = function_impl<internal::RoundUpToWord(inline_target_size),
85 /*require_inline=*/true, T>;
86
87 // Synonym for a function which takes no arguments and produces no result.
88 using closure = function<void()>;
89
90 // A |fit::callback| is a move-only polymorphic function wrapper that also
91 // ensures "run-once" semantics (such as callbacks shared with timeouts, or for
92 // service requests with redundant, failover, or fallback service providers).
93 // A |fit::callback| releases it's resources after the first call, and can be
94 // inspected before calling, so a potential caller can know if it should call
95 // the function, or skip the call because the target was already called.
96 //
97 // If you need a move-only function class with typical function characteristics,
98 // that permits multiple invocations of the same function, see |fit::function|.
99 //
100 // |fit::callback<T>| behaves like |std::function<T>| except:
101 //
102 // 1. It is move-only instead of copyable, so it can hold targets that cannot
103 // be copied, such as mutable lambdas, and immutable lambdas that capture
104 // move-only objects.
105 // 2. On the first call to invoke a |fit::callback|, the target function held
106 // by the |fit::callback| cannot be called again.
107 //
108 // When a |fit::callback| is invoked for the first time, the target function is
109 // released and destructed, along with any resources owned by that function
110 // (typically the objects captured by a lambda).
111 //
112 // A |fit::callback| in the "already called" state has the same state as a
113 // |fit::callback| that has been assigned to |nullptr|. It can be compared to
114 // |nullptr| (via "==" or "!=", and its "operator bool()" returns false, which
115 // provides a convenient way to gate whether or not the |fit::callback| should
116 // be called. (Note that invoking an empty |fit::callback| or |fit::function|
117 // will cause a program abort!)
118 //
119 // As an example, sharing |fit::callback| between both a service and a timeout
120 // might look something like this:
121 //
122 // void service_with_timeout(fit::callback<void(bool)> cb, uint timeout_ms) {
123 // service_request([cb = cb.share()]() mutable { if (cb) cb(false); });
124 // timeout(timeout_ms, [cb = std::move(cb)]() mutable { if (cb) cb(true); });
125 // }
126 //
127 // Since |fit::callback| objects are move-only, and not copyable, duplicate
128 // references to the same |fit::callback| can be obtained via share(), as shown
129 // in the example above. This method converts the |fit::callback| into a
130 // reference-counted version of the |fit::callback| and returns a copy of the
131 // reference as another |fit::callback| with the same target function.
132 //
133 // What is notable about |fit::callback<T>.share()| is that invoking any shared
134 // copy will "nullify" all shared copies, as shown in the example.
135 //
136 // Note that |fit::callback| is NOT thread-safe by default. If multi-threaded
137 // support is required, you would need to implement your own mutex, or similar
138 // guard, before checking and calling a |fit::callback|.
139 //
140 // Targets of up to |inline_target_size| bytes in size are stored inline within
141 // the callback object without incurring any heap allocation. Larger callable
142 // objects will be moved to the heap as required. |inline_target_size| is
143 // rounded up to a multiple of sizeof(void*).
144 //
145 // See also |fit::inline_callback<T, size>| for more control over allocation
146 // behavior.
147 //
148 // SYNOPSIS
149 //
150 // |T| is the callback's signature. e.g. void(int, std::string).
151 //
152 // |inline_target_size| is the minimum size of target that is guaranteed to
153 // fit within a callback without requiring heap allocation.
154 // Defaults to |default_inline_target_size|.
155 //
156 // Class members are documented in |fit::callback_impl|, below.
157 //
158 template <typename T, size_t inline_target_size = default_inline_target_size>
159 using callback =
160 callback_impl<internal::RoundUpToWord(inline_target_size), /*require_inline=*/false, T>;
161
162 // A move-only, run-once, callable object wrapper that forces callables to be
163 // stored inline and never performs heap allocation.
164 //
165 // Behaves just like |fit::callback<T, inline_target_size>| except that
166 // attempting to store a target larger than |inline_target_size| will fail to
167 // compile.
168 template <typename T, size_t inline_target_size = default_inline_target_size>
169 using inline_callback = callback_impl<internal::RoundUpToWord(inline_target_size),
170 /*require_inline=*/true, T>;
171
172 template <size_t inline_target_size, bool require_inline, typename Result, typename... Args>
173 class function_impl<inline_target_size, require_inline, Result(Args...)> final
174 : private ::fit::internal::function_base<inline_target_size, require_inline, Result(Args...)> {
175 using base = ::fit::internal::function_base<inline_target_size, require_inline, Result(Args...)>;
176
177 // function_base requires private access during share()
178 friend class ::fit::internal::function_base<inline_target_size, require_inline, Result(Args...)>;
179
180 // supports target() for shared functions
181 friend const void* ::fit::internal::get_target_type_id<>(
182 const function_impl<inline_target_size, require_inline, Result(Args...)>&);
183
184 template <typename U>
185 using not_self_type = ::fit::internal::not_same_type<function_impl, U>;
186
187 template <typename... Conditions>
188 using requires_conditions = ::fit::internal::requires_conditions<Conditions...>;
189
190 template <typename... Conditions>
191 using assignment_requires_conditions =
192 ::fit::internal::assignment_requires_conditions<function_impl&, Conditions...>;
193
194 public:
195 // The function's result type.
196 using typename base::result_type;
197
198 // Initializes an empty (null) function. Attempting to call an empty
199 // function will abort the program.
200 constexpr function_impl() = default;
201
202 // Creates a function with an empty target (same outcome as the default
203 // constructor).
function_impl(decltype (nullptr))204 constexpr function_impl(decltype(nullptr)) : base(nullptr) {}
205
206 // Creates a function bound to the specified function pointer.
207 // If target == nullptr, assigns an empty target.
function_impl(Result (* function_target)(Args...))208 function_impl(Result (*function_target)(Args...)) : base(function_target) {}
209
210 // Creates a function bound to the specified callable object.
211 // If target == nullptr, assigns an empty target.
212 //
213 // For functors, we need to capture the raw type but also restrict on the
214 // existence of an appropriate operator () to resolve overloads and implicit
215 // casts properly.
216 //
217 // Note that specializations of this template method that take fit::callback
218 // objects as the target Callable are deleted (see below).
219 template <typename Callable,
220 requires_conditions<
221 std::is_convertible<decltype(std::declval<Callable&>()(std::declval<Args>()...)),
222 result_type>,
223 not_self_type<Callable>> = true>
function_impl(Callable && function_target)224 function_impl(Callable&& function_target) : base(std::forward<Callable>(function_target)) {}
225
226 // Deletes the specializations of function_impl(Callable) that would allow
227 // a |fit::function| to be constructed from a |fit::callback|. This prevents
228 // unexpected behavior of a |fit::function| that would otherwise fail after
229 // one call. To explicitly allow this, simply wrap the |fit::callback| in a
230 // pass-through lambda before passing it to the |fit::function|.
231 template <size_t other_inline_target_size, bool other_require_inline>
232 function_impl(
233 ::fit::callback_impl<other_inline_target_size, other_require_inline, Result(Args...)>) =
234 delete;
235
236 // Creates a function with a target moved from another function,
237 // leaving the other function with an empty target.
function_impl(function_impl && other)238 function_impl(function_impl&& other) noexcept : base(static_cast<base&&>(other)) {}
239
240 // Destroys the function, releasing its target.
241 ~function_impl() = default;
242
243 // Assigns the function to an empty target. Attempting to invoke the
244 // function will abort the program.
decltype(nullptr)245 function_impl& operator=(decltype(nullptr)) {
246 base::assign_null();
247 return *this;
248 }
249
250 // Assigns the function to the specified callable object. If target ==
251 // nullptr, assigns an empty target.
252 //
253 // For functors, we need to capture the raw type but also restrict on the
254 // existence of an appropriate operator () to resolve overloads and implicit
255 // casts properly.
256 //
257 // Note that specializations of this template method that take fit::callback
258 // objects as the target Callable are deleted (see below).
259 template <typename Callable>
260 // NOLINTNEXTLINE(misc-unconventional-assign-operator)
261 assignment_requires_conditions<
262 std::is_convertible<decltype(std::declval<Callable&>()(std::declval<Args>()...)),
263 result_type>,
264 not_self_type<Callable>>
265 operator=(Callable&& function_target) {
266 base::assign_callable(std::forward<Callable>(function_target));
267 return *this;
268 }
269
270 // Deletes the specializations of operator=(Callable) that would allow
271 // a |fit::function| to be assigned from a |fit::callback|. This
272 // prevents unexpected behavior of a |fit::function| that would otherwise
273 // fail after one call. To explicitly allow this, simply wrap the
274 // |fit::callback| in a pass-through lambda before assigning it to the
275 // |fit::function|.
276 template <size_t other_inline_target_size, bool other_require_inline>
277 function_impl& operator=(
278 ::fit::callback_impl<other_inline_target_size, other_require_inline, Result(Args...)>) =
279 delete;
280
281 // Move assignment
282 function_impl& operator=(function_impl&& other) noexcept {
283 if (&other == this)
284 return *this;
285 base::assign_function(static_cast<base&&>(other));
286 return *this;
287 }
288
289 // Swaps the functions' targets.
swap(function_impl & other)290 void swap(function_impl& other) { base::swap(other); }
291
292 // Returns a pointer to the function's target.
293 using base::target;
294
295 // Returns true if the function has a non-empty target.
296 using base::operator bool;
297
298 // Invokes the function's target.
299 // Aborts if the function's target is empty.
operator()300 Result operator()(Args... args) const { return base::invoke(std::forward<Args>(args)...); }
301
302 // Returns a new function object that invokes the same target.
303 // The target itself is not copied; it is moved to the heap and its
304 // lifetime is extended until all references have been released.
305 //
306 // Note: This method is not supported on |fit::inline_function<>|
307 // because it may incur a heap allocation which is contrary to
308 // the stated purpose of |fit::inline_function<>|.
share()309 function_impl share() {
310 function_impl copy;
311 base::template share_with<function_impl>(copy);
312 return copy;
313 }
314 };
315
316 template <size_t inline_target_size, bool require_inline, typename FunctionType>
swap(function_impl<inline_target_size,require_inline,FunctionType> & a,function_impl<inline_target_size,require_inline,FunctionType> & b)317 void swap(function_impl<inline_target_size, require_inline, FunctionType>& a,
318 function_impl<inline_target_size, require_inline, FunctionType>& b) {
319 a.swap(b);
320 }
321
322 template <size_t inline_target_size, bool require_inline, typename FunctionType>
323 bool operator==(const function_impl<inline_target_size, require_inline, FunctionType>& f,
324 decltype(nullptr)) {
325 return !f;
326 }
327 template <size_t inline_target_size, bool require_inline, typename FunctionType>
328 bool operator==(decltype(nullptr),
329 const function_impl<inline_target_size, require_inline, FunctionType>& f) {
330 return !f;
331 }
332 template <size_t inline_target_size, bool require_inline, typename FunctionType>
333 bool operator!=(const function_impl<inline_target_size, require_inline, FunctionType>& f,
334 decltype(nullptr)) {
335 return !!f;
336 }
337 template <size_t inline_target_size, bool require_inline, typename FunctionType>
338 bool operator!=(decltype(nullptr),
339 const function_impl<inline_target_size, require_inline, FunctionType>& f) {
340 return !!f;
341 }
342
343 template <size_t inline_target_size, bool require_inline, typename Result, typename... Args>
344 class callback_impl<inline_target_size, require_inline, Result(Args...)> final
345 : private ::fit::internal::function_base<inline_target_size, require_inline, Result(Args...)> {
346 using base = ::fit::internal::function_base<inline_target_size, require_inline, Result(Args...)>;
347
348 // function_base requires private access during share()
349 friend class ::fit::internal::function_base<inline_target_size, require_inline, Result(Args...)>;
350
351 // supports target() for shared functions
352 friend const void* ::fit::internal::get_target_type_id<>(
353 const callback_impl<inline_target_size, require_inline, Result(Args...)>&);
354
355 template <typename U>
356 using not_self_type = ::fit::internal::not_same_type<callback_impl, U>;
357
358 template <typename... Conditions>
359 using requires_conditions = ::fit::internal::requires_conditions<Conditions...>;
360
361 template <typename... Conditions>
362 using assignment_requires_conditions =
363 ::fit::internal::assignment_requires_conditions<callback_impl&, Conditions...>;
364
365 public:
366 // The callback function's result type.
367 using typename base::result_type;
368
369 // Initializes an empty (null) callback. Attempting to call an empty
370 // callback will abort the program.
371 constexpr callback_impl() = default;
372
373 // Creates a callback with an empty target (same outcome as the default
374 // constructor).
callback_impl(decltype (nullptr))375 constexpr callback_impl(decltype(nullptr)) : base(nullptr) {}
376
377 // Creates a callback bound to the specified function pointer.
378 // If target == nullptr, assigns an empty target.
callback_impl(Result (* callback_target)(Args...))379 callback_impl(Result (*callback_target)(Args...)) : base(callback_target) {}
380
381 // Creates a callback bound to the specified callable object.
382 // If target == nullptr, assigns an empty target.
383 //
384 // For functors, we need to capture the raw type but also restrict on the
385 // existence of an appropriate operator () to resolve overloads and implicit
386 // casts properly.
387 template <typename Callable,
388 requires_conditions<
389 std::is_convertible<decltype(std::declval<Callable&>()(std::declval<Args>()...)),
390 result_type>,
391 not_self_type<Callable>> = true>
callback_impl(Callable && callback_target)392 callback_impl(Callable&& callback_target) : base(std::forward<Callable>(callback_target)) {}
393
394 // Creates a callback with a target moved from another callback,
395 // leaving the other callback with an empty target.
callback_impl(callback_impl && other)396 callback_impl(callback_impl&& other) noexcept : base(static_cast<base&&>(other)) {}
397
398 // Destroys the callback, releasing its target.
399 ~callback_impl() = default;
400
401 // Assigns the callback to an empty target. Attempting to invoke the
402 // callback will abort the program.
decltype(nullptr)403 callback_impl& operator=(decltype(nullptr)) {
404 base::assign_null();
405 return *this;
406 }
407
408 // Assigns the callback to the specified callable object. If target ==
409 // nullptr, assigns an empty target.
410 //
411 // For functors, we need to capture the raw type but also restrict on the
412 // existence of an appropriate operator () to resolve overloads and implicit
413 // casts properly.
414 template <typename Callable>
415 // NOLINTNEXTLINE(misc-unconventional-assign-operator)
416 assignment_requires_conditions<
417 std::is_convertible<decltype(std::declval<Callable&>()(std::declval<Args>()...)),
418 result_type>,
419 not_self_type<Callable>>
420 operator=(Callable&& callback_target) {
421 base::assign_callable(std::forward<Callable>(callback_target));
422 return *this;
423 }
424
425 // Move assignment
426 callback_impl& operator=(callback_impl&& other) noexcept {
427 if (&other == this)
428 return *this;
429 base::assign_function(static_cast<base&&>(other));
430 return *this;
431 }
432
433 // Swaps the callbacks' targets.
swap(callback_impl & other)434 void swap(callback_impl& other) { base::swap(other); }
435
436 // Returns a pointer to the callback's target.
437 using base::target;
438
439 // Returns true if the callback has a non-empty target.
440 using base::operator bool;
441
442 // Invokes the callback's target.
443 // Aborts if the callback's target is empty.
444 // |fit::callback| must be non-const to invoke. Before the target function
445 // is actually called, the fit::callback will be set to the default empty
446 // state (== nullptr, and operator bool() will subsequently return |false|).
447 // The target function will then be released after the function is called.
448 // If the callback was shared, any remaining copies will also be cleared.
operator()449 Result operator()(Args... args) {
450 auto temp = std::move(*this);
451 return temp.invoke(std::forward<Args>(args)...);
452 }
453
454 // Returns a new callback object that invokes the same target.
455 // The target itself is not copied; it is moved to the heap and its
456 // lifetime is extended until all references have been released.
457 // For |fit::callback| (unlike fit::function), the first invocation of the
458 // callback will release all references to the target. All callbacks
459 // derived from the same original callback (via share()) will be cleared,
460 // as if set to |nullptr|, and "operator bool()" will return false.
461 //
462 // Note: This method is not supported on |fit::inline_function<>|
463 // because it may incur a heap allocation which is contrary to
464 // the stated purpose of |fit::inline_function<>|.
share()465 callback_impl share() {
466 callback_impl copy;
467 base::template share_with<callback_impl>(copy);
468 return copy;
469 }
470 };
471
472 template <size_t inline_target_size, bool require_inline, typename FunctionType>
swap(callback_impl<inline_target_size,require_inline,FunctionType> & a,callback_impl<inline_target_size,require_inline,FunctionType> & b)473 void swap(callback_impl<inline_target_size, require_inline, FunctionType>& a,
474 callback_impl<inline_target_size, require_inline, FunctionType>& b) {
475 a.swap(b);
476 }
477
478 template <size_t inline_target_size, bool require_inline, typename FunctionType>
479 bool operator==(const callback_impl<inline_target_size, require_inline, FunctionType>& f,
480 decltype(nullptr)) {
481 return !f;
482 }
483 template <size_t inline_target_size, bool require_inline, typename FunctionType>
484 bool operator==(decltype(nullptr),
485 const callback_impl<inline_target_size, require_inline, FunctionType>& f) {
486 return !f;
487 }
488 template <size_t inline_target_size, bool require_inline, typename FunctionType>
489 bool operator!=(const callback_impl<inline_target_size, require_inline, FunctionType>& f,
490 decltype(nullptr)) {
491 return !!f;
492 }
493 template <size_t inline_target_size, bool require_inline, typename FunctionType>
494 bool operator!=(decltype(nullptr),
495 const callback_impl<inline_target_size, require_inline, FunctionType>& f) {
496 return !!f;
497 }
498
499 // Returns a Callable object that invokes a member function of an object.
500 // When used in a fit::function, this heap allocates (the returned lambda is
501 // 3*sizeof(void*)).
502 //
503 // Deprecated in favor of the bind_member definition below that will inline into a
504 // fit::function without heap allocating. The new bind_member definition is only
505 // supported on C++17 and up. On C++14, a plain lambda should be used instead.
506 template <typename R, typename T, typename... Args>
bind_member(T * instance,R (T::* fn)(Args...))507 auto bind_member(T* instance, R (T::*fn)(Args...)) {
508 // Use explicit type on the return to ensure perfect forwarding of references.
509 return [instance, fn](Args... args) -> R { return (instance->*fn)(std::forward<Args>(args)...); };
510 }
511
512 // C++17 due to use of 'auto' template parameters and lambda parameters.
513 #if __cplusplus >= 201703L
514 namespace internal {
515 // Performs the call for bind_member but captures the arguments of the method.
516 // This ensure that the correct overload of |method| is called.
517 template <auto method, typename T, typename... Args>
make_the_call(T * instance,parameter_pack<Args...>)518 auto make_the_call(T* instance, parameter_pack<Args...>) {
519 // Use decltype(auto) on the return to ensure perfect forwarding of references.
520 return [instance](Args... args) -> decltype(auto) {
521 return (instance->*method)(std::forward<decltype(args)>(args)...);
522 };
523 }
524 } // namespace internal
525
526 // Returns a Callable object that invokes a member function of an object.
527 // In other words, returns a closure 'f' for which calling f(args) is equivalent to
528 // calling obj.method(args).
529 //
530 // Usage: fit::bind_member<&ObjType::MethodName>(&obj)
531 template <auto method, typename T>
bind_member(T * instance)532 auto bind_member(T* instance) {
533 return internal::make_the_call<method>(instance,
534 typename callable_traits<decltype(method)>::args{});
535 }
536 #endif // __cplusplus >= 201703L
537
538 } // namespace fit
539
540 #endif // LIB_FIT_INCLUDE_LIB_FIT_FUNCTION_H_
541