mrs_lib
Various reusable classes, functions and utilities for use in MRS projects
Loading...
Searching...
No Matches
callback.hpp
Go to the documentation of this file.
1
2
3#ifndef MRS_LIB_UTILITY_CALLBACK_HPP_
4#define MRS_LIB_UTILITY_CALLBACK_HPP_
5
6#include <atomic>
7#include <concepts>
8#include <functional>
9#include <memory>
10#include <stdexcept>
11#include <type_traits>
12#include <type_traits>
13#include <utility>
14#include <variant>
15
16#include "mrs_lib/coro/task.hpp"
17#include "mrs_lib/utility/meta.hpp"
18#include "mrs_lib/utility/scope_cleanup.hpp"
19
20namespace mrs_lib
21{
22
27 {
33 class Reentrant
34 {
35 public:
36 explicit Reentrant() = default;
37 };
38
60 template <typename CallbackRetType = void>
62 {
63 public:
68 explicit CancelNew(std::function<CallbackRetType()> default_factory) : default_factory_(std::move(default_factory))
69 {
70 }
71
76 CallbackRetType create_value() const
77 {
78 return default_factory_();
79 }
80
81 private:
82 std::function<CallbackRetType()> default_factory_;
83 };
84
88 template <>
89 class CancelNew<void>
90 {
91 public:
95 explicit CancelNew() = default;
96
100 void create_value() const
101 {
102 }
103 };
104
108 template <typename F>
110
119 {
120 public:
124 explicit CancelNewDefault() = default;
125
130 {
131 return CancelNew<>{};
132 }
133
140 template <typename T>
141 requires std::default_initializable<T>
142 operator CancelNew<T>()
143 {
144 return CancelNew<T>([] { return T{}; });
145 }
146 };
147
148 } // namespace coro_callback_tags
149
156 template <typename CallbackRetType>
157 using CoroReentrantPolicyVariant = std::variant<coro_callback_tags::Reentrant, coro_callback_tags::CancelNew<CallbackRetType>>;
158
164 template <typename...>
166 {
167 static_assert(false, "Base template selected for CoroCallback");
168 };
169
170
185 template <typename CallbackRetType, typename... CallbackArgs>
186 class CoroCallback<CallbackRetType(CallbackArgs...)>
187 {
188 private:
189 using FunctionSignature = coro::Task<CallbackRetType>(CallbackArgs...);
190
191 public:
207 template <typename F, typename... BoundArgs>
208 requires((std::is_member_function_pointer_v<F> || (std::is_pointer_v<F> && std::is_function_v<std::remove_pointer_t<F>>))
209 && std::invocable<F, const std::decay_t<BoundArgs>&..., CallbackArgs...>
210 && std::same_as<coro::Task<CallbackRetType>, std::invoke_result_t<F, const std::decay_t<BoundArgs>&..., CallbackArgs...>>)
211 explicit CoroCallback(CoroReentrantPolicyVariant<CallbackRetType> reentrant_policy, F callback_ptr, BoundArgs&&... args)
212 : func_(bind_callback(std::move(reentrant_policy), callback_ptr, std::forward<BoundArgs>(args)...))
213 {
214 }
215
222 coro::Task<CallbackRetType> operator()(CallbackArgs... args) const
223 {
224 co_return co_await std::invoke(func_, std::forward<CallbackArgs>(args)...);
225 }
226
227 private:
236 template <typename F>
237 static std::function<FunctionSignature> wrap_callback(coro_callback_tags::Reentrant, F&& func)
238 {
239 return std::forward<F>(func);
240 }
241
250 template <typename F>
251 static std::function<FunctionSignature> wrap_callback(coro_callback_tags::CancelNew<CallbackRetType> cancel_new_policy, F&& func)
252 {
253 return [running = std::make_shared<std::atomic_bool>(false), cancel_new_policy = std::move(cancel_new_policy),
254 func = std::forward<F>(func)](CallbackArgs... args) -> coro::Task<CallbackRetType> {
255 bool was_running = running->exchange(true);
256 // !was_running <=> we set the state to running => we should start the callback
257 if (!was_running)
258 {
259 ScopeCleanup cleanup([&] { running->store(false); });
260 co_return co_await func(std::forward<CallbackArgs>(args)...);
261 } else
262 {
263 co_return cancel_new_policy.create_value();
264 }
265 };
266 }
267
278 template <typename F, typename... BoundArgs>
279 static std::function<FunctionSignature> bind_callback(CoroReentrantPolicyVariant<CallbackRetType> reentrant_policy, F callback_ptr, BoundArgs&&... args)
280 {
281 if (callback_ptr == nullptr)
282 {
283 throw std::logic_error("Cannot construct CoroCallback from nullptr.");
284 }
285
286 auto bound_callback = [callback = std::move(callback_ptr),
287 ... pre_args = std::forward<BoundArgs>(args)](CallbackArgs... args) -> coro::Task<CallbackRetType> {
288 co_return co_await std::invoke(callback, pre_args..., std::forward<CallbackArgs>(args)...);
289 };
290
291 return std::visit(
292 [&](auto&& reentrant_policy) -> std::function<FunctionSignature> {
293 return wrap_callback(std::forward<decltype(reentrant_policy)>(reentrant_policy), std::move(bound_callback));
294 },
295 reentrant_policy);
296 }
297
298 std::function<FunctionSignature> func_;
299 };
300
301 namespace internal
302 {
303
307 template <typename...>
309
316 template <typename Ret, typename... Params, typename... Args>
317 struct CallbackSignature<Ret, meta::TypeList<Params...>, meta::TypeList<Args...>>
318 {
319 private:
320 template <typename... InnerParams>
321 using FuncSignature = Ret(InnerParams...);
322
323 public:
324 using type = meta::ApplyT<FuncSignature, meta::DropT<meta::TypeList<Params...>, sizeof...(Args)>>;
325 };
326
333 template <typename Ret, typename Params, typename Args>
335
336 } // namespace internal
337
341 template <typename R, typename... Params, typename... Args, bool Noexcept>
342 CoroCallback(auto, mrs_lib::Task<R> (*)(Params...) noexcept(Noexcept), Args&&...) //
344
348 template <typename C1, typename C2, typename R, typename... Params, typename... Args, bool Noexcept>
349 CoroCallback(auto, mrs_lib::Task<R> (C1::*)(Params...) noexcept(Noexcept), C2, Args&&...) //
351
355 template <typename C1, typename C2, typename R, typename... Params, typename... Args, bool Noexcept>
356 CoroCallback(auto, mrs_lib::Task<R> (C1::*)(Params...) const noexcept(Noexcept), C2, Args&&...) //
358
359} // namespace mrs_lib
360
361#endif // MRS_LIB_UTILITY_CALLBACK_HPP_
CallbackSignature< Ret, Params, Args >::type CallbackSignatureT
Helper type alias for CallbackSignature<Ret, Params, Args>::type.
Definition callback.hpp:334
CoroCallback(CoroReentrantPolicyVariant< CallbackRetType > reentrant_policy, F callback_ptr, BoundArgs &&... args)
Constructor for binding coroutine callbacks.
Definition callback.hpp:211
coro::Task< CallbackRetType > operator()(CallbackArgs... args) const
Executes the callback.
Definition callback.hpp:222
Base template for CoroCallback.
Definition callback.hpp:166
Task type for creating coroutines.
Definition task.hpp:268
CancelNewDefault()=default
Default constructor.
void create_value() const
Returns void.
Definition callback.hpp:100
CancelNew()=default
Default constructor.
Policy tag for CoroCallback ignores new callbacks, when another is already running.
Definition callback.hpp:62
CallbackRetType create_value() const
Create a return value for a cancelled callback.
Definition callback.hpp:76
CancelNew(std::function< CallbackRetType()> default_factory)
Constructor accepting factory function.
Definition callback.hpp:68
Policy tag for reentrant CoroCallback.
Definition callback.hpp:34
Namespace for tag types used in CoroCallback.
Definition callback.hpp:27
CancelNew(F) -> CancelNew< std::invoke_result_t< F > >
Deduction guide to deduce CancelNew type from factory function.
Namespace containing metaprograming utilities.
Definition meta.hpp:11
Apply< F, List >::type ApplyT
Helper type alias for Apply<F, List>::type.
Definition meta.hpp:72
Drop< List, N >::type DropT
Helper type alias for Drop<List, N>::type.
Definition meta.hpp:49
All mrs_lib functions, classes, variables and definitions are contained in this namespace.
Definition attitude_converter.h:24
std::variant< coro_callback_tags::Reentrant, coro_callback_tags::CancelNew< CallbackRetType > > CoroReentrantPolicyVariant
Variant of CoroCallback reentrancy policies.
Definition callback.hpp:157
CoroCallback(auto, mrs_lib::Task< R >(*)(Params...) noexcept(Noexcept), Args &&...) -> CoroCallback< internal::CallbackSignatureT< R, meta::TypeList< Params... >, meta::TypeList< Args... > > >
Deduction guide for free functions.
Type trait to determine the signature of a callback function.
Definition callback.hpp:308
Struct for storing compile time list of types.
Definition meta.hpp:18