1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15
16 /// @file pw_function/pointer.h
17 ///
18 /// Traditional callback APIs often use a function pointer and `void*` context
19 /// argument. The context argument makes it possible to use the callback
20 /// function with non-global data. For example, the `qsort_s` and `bsearch_s`
21 /// functions take a pointer to a comparison function that has `void*` context
22 /// as its last parameter. @cpp_type{pw::Function} does not naturally work with
23 /// these kinds of APIs.
24 ///
25 /// The functions below make it simple to adapt a @cpp_type{pw::Function} for
26 /// use with APIs that accept a function pointer and `void*` context argument.
27
28 #include <utility>
29
30 #include "pw_function/internal/static_invoker.h"
31
32 namespace pw::function {
33
34 /// Returns a function pointer that invokes a `pw::Function`, lambda, or other
35 /// callable object from a `void*` context argument. This makes it possible to
36 /// use C++ callables with C-style APIs that take a function pointer and `void*`
37 /// context.
38 ///
39 /// The returned function pointer has the same return type and arguments as the
40 /// `pw::Function` or `pw::Callback`, except that the last parameter is a
41 /// `void*`. `GetFunctionPointerContextFirst` places the `void*` context
42 /// parameter first.
43 ///
44 /// The following example adapts a C++ lambda function for use with C-style API
45 /// that takes an `int (*)(int, void*)` function and a `void*` context.
46 ///
47 /// @code{.cpp}
48 ///
49 /// void TakesAFunctionPointer(int (*function)(int, void*), void* context);
50 ///
51 /// void UseFunctionPointerApiWithPwFunction() {
52 /// // Declare a callable object so a void* pointer can be obtained for it.
53 /// auto my_function = [captures](int value) {
54 /// // ...
55 /// return value + captures;
56 /// };
57 ///
58 /// // Invoke the API with the function pointer and callable pointer.
59 /// TakesAFunctionPointer(pw::function::GetFunctionPointer(my_function),
60 /// &my_function);
61 /// }
62 ///
63 /// @endcode
64 ///
65 /// The function returned from this must ONLY be used with the exact type for
66 /// which it was created! Function pointer / context APIs are not type safe.
67 template <typename FunctionType>
GetFunctionPointer()68 constexpr auto GetFunctionPointer() {
69 return internal::StaticInvoker<
70 FunctionType,
71 decltype(&FunctionType::operator())>::InvokeWithContextLast;
72 }
73
74 /// `GetFunctionPointer` overload that uses the type of the function passed to
75 /// this call.
76 template <typename FunctionType>
GetFunctionPointer(const FunctionType &)77 constexpr auto GetFunctionPointer(const FunctionType&) {
78 return GetFunctionPointer<FunctionType>();
79 }
80
81 /// Same as `GetFunctionPointer`, but the context argument is passed first.
82 /// Returns a `void(void*, int)` function for a `pw::Function<void(int)>`.
83 template <typename FunctionType>
GetFunctionPointerContextFirst()84 constexpr auto GetFunctionPointerContextFirst() {
85 return internal::StaticInvoker<
86 FunctionType,
87 decltype(&FunctionType::operator())>::InvokeWithContextFirst;
88 }
89
90 /// `GetFunctionPointerContextFirst` overload that uses the type of the function
91 /// passed to this call.
92 template <typename FunctionType>
GetFunctionPointerContextFirst(const FunctionType &)93 constexpr auto GetFunctionPointerContextFirst(const FunctionType&) {
94 return GetFunctionPointerContextFirst<FunctionType>();
95 }
96
97 } // namespace pw::function
98