|
30 | 30 | /// a FunctionRef. |
31 | 31 |
|
32 | 32 | // torch::executor: modified from llvm::function_ref |
33 | | -// see https://www.foonathan.net/2017/01/function-ref-implementation/ |
| 33 | +// - renamed to FunctionRef |
| 34 | +// - removed LLVM_GSL_POINTER and LLVM_LIFETIME_BOUND macro uses |
| 35 | +// - use namespaced internal::remove_cvref_t |
| 36 | + |
34 | 37 |
|
35 | 38 | #pragma once |
36 | 39 |
|
@@ -64,99 +67,43 @@ class FunctionRef; |
64 | 67 |
|
65 | 68 | template <typename Ret, typename... Params> |
66 | 69 | class FunctionRef<Ret(Params...)> { |
67 | | - Ret (*callback_)(const void* memory, Params... params) = nullptr; |
68 | | - union Storage { |
69 | | - void* callable; |
70 | | - Ret (*function)(Params...); |
71 | | - } storage_; |
| 70 | + Ret (*callback)(intptr_t callable, Params ...params) = nullptr; |
| 71 | + intptr_t callable; |
72 | 72 |
|
73 | | - public: |
74 | | - FunctionRef() = default; |
75 | | - explicit FunctionRef(std::nullptr_t) {} |
76 | | - |
77 | | - /** |
78 | | - * Case 1: A callable object passed by lvalue reference. |
79 | | - * Taking rvalue reference is error prone because the object will be always |
80 | | - * be destroyed immediately. |
81 | | - */ |
82 | | - template < |
83 | | - typename Callable, |
84 | | - // This is not the copy-constructor. |
85 | | - typename std::enable_if< |
86 | | - !std::is_same<internal::remove_cvref_t<Callable>, FunctionRef>::value, |
87 | | - int32_t>::type = 0, |
88 | | - // Avoid lvalue reference to non-capturing lambda. |
89 | | - typename std::enable_if< |
90 | | - !std::is_convertible<Callable, Ret (*)(Params...)>::value, |
91 | | - int32_t>::type = 0, |
92 | | - // Functor must be callable and return a suitable type. |
93 | | - // To make this container type safe, we need to ensure either: |
94 | | - // 1. The return type is void. |
95 | | - // 2. Or the resulting type from calling the callable is convertible to |
96 | | - // the declared return type. |
97 | | - typename std::enable_if< |
98 | | - std::is_void<Ret>::value || |
99 | | - std::is_convertible< |
100 | | - decltype(std::declval<Callable>()(std::declval<Params>()...)), |
101 | | - Ret>::value, |
102 | | - int32_t>::type = 0> |
103 | | - explicit FunctionRef(Callable& callable) |
104 | | - : callback_([](const void* memory, Params... params) { |
105 | | - auto& storage = *static_cast<const Storage*>(memory); |
106 | | - auto& callable = *static_cast<Callable*>(storage.callable); |
107 | | - return static_cast<Ret>(callable(std::forward<Params>(params)...)); |
108 | | - }) { |
109 | | - storage_.callable = &callable; |
| 73 | + template<typename Callable> |
| 74 | + static Ret callback_fn(intptr_t callable, Params ...params) { |
| 75 | + return (*reinterpret_cast<Callable*>(callable))( |
| 76 | + std::forward<Params>(params)...); |
110 | 77 | } |
111 | 78 |
|
112 | | - /** |
113 | | - * Case 2: A plain function pointer. |
114 | | - * Instead of storing an opaque pointer to underlying callable object, |
115 | | - * store a function pointer directly. |
116 | | - * Note that in the future a variant which coerces compatible function |
117 | | - * pointers could be implemented by erasing the storage type. |
118 | | - */ |
119 | | - /* implicit */ FunctionRef(Ret (*ptr)(Params...)) |
120 | | - : callback_([](const void* memory, Params... params) { |
121 | | - auto& storage = *static_cast<const Storage*>(memory); |
122 | | - return storage.function(std::forward<Params>(params)...); |
123 | | - }) { |
124 | | - storage_.function = ptr; |
125 | | - } |
| 79 | +public: |
| 80 | + FunctionRef() = default; |
| 81 | + FunctionRef(std::nullptr_t) {} |
126 | 82 |
|
127 | | - /** |
128 | | - * Case 3: Implicit conversion from lambda to FunctionRef. |
129 | | - * A common use pattern is like: |
130 | | - * void foo(FunctionRef<...>) {...} |
131 | | - * foo([](...){...}) |
132 | | - * Here constructors for non const lvalue reference or function pointer |
133 | | - * would not work because they do not cover implicit conversion from rvalue |
134 | | - * lambda. |
135 | | - * We need to define a constructor for capturing temporary callables and |
136 | | - * always try to convert the lambda to a function pointer behind the scene. |
137 | | - */ |
138 | | - template < |
139 | | - typename Function, |
| 83 | + template <typename Callable> |
| 84 | + FunctionRef( |
| 85 | + Callable &&callable, |
140 | 86 | // This is not the copy-constructor. |
141 | | - typename std::enable_if< |
142 | | - !std::is_same<Function, FunctionRef>::value, |
143 | | - int32_t>::type = 0, |
144 | | - // Function is convertible to pointer of (Params...) -> Ret. |
145 | | - typename std::enable_if< |
146 | | - std::is_convertible<Function, Ret (*)(Params...)>::value, |
147 | | - int32_t>::type = 0> |
148 | | - /* implicit */ FunctionRef(const Function& function) |
149 | | - : FunctionRef(static_cast<Ret (*)(Params...)>(function)) {} |
150 | | - |
151 | | - Ret operator()(Params... params) const { |
152 | | - return callback_(&storage_, std::forward<Params>(params)...); |
| 87 | + std::enable_if_t<!std::is_same<internal::remove_cvref_t<Callable>, |
| 88 | + FunctionRef>::value> * = nullptr, |
| 89 | + // Functor must be callable and return a suitable type. |
| 90 | + std::enable_if_t<std::is_void<Ret>::value || |
| 91 | + std::is_convertible<decltype(std::declval<Callable>()( |
| 92 | + std::declval<Params>()...)), |
| 93 | + Ret>::value> * = nullptr) |
| 94 | + : callback(callback_fn<std::remove_reference_t<Callable>>), |
| 95 | + callable(reinterpret_cast<intptr_t>(&callable)) {} |
| 96 | + |
| 97 | + Ret operator()(Params ...params) const { |
| 98 | + return callback(callable, std::forward<Params>(params)...); |
153 | 99 | } |
154 | 100 |
|
155 | | - explicit operator bool() const { |
156 | | - return callback_; |
| 101 | + explicit operator bool() const { return callback; } |
| 102 | + |
| 103 | + bool operator==(const FunctionRef<Ret(Params...)> &Other) const { |
| 104 | + return callable == Other.callable; |
157 | 105 | } |
158 | 106 | }; |
159 | | - |
160 | 107 | } // namespace pytree |
161 | 108 | } // namespace extension |
162 | 109 | } // namespace executorch |
|
0 commit comments