xref: /aosp_15_r20/external/pigweed/pw_function/public/pw_function/pointer.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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