libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
callback.hpp
1#pragma once
2
3#include "../topic.hpp"
4
5namespace LibXR
6{
13{
20 template <typename Function>
22
30 template <typename Return, typename... Args>
31 struct FunctionTraits<Return (*)(Args...)>
32 {
33 using ReturnType = Return;
34 static constexpr size_t ARITY = sizeof...(Args);
35
40 template <size_t Index>
41 using Arg = std::tuple_element_t<Index, std::tuple<Args...>>;
42 };
43
50 template <typename T>
52 {
53 static constexpr bool VALUE = false;
54 };
55
63 template <typename Data>
65 {
66 static constexpr bool VALUE = true;
67 using DataType = Data;
68 };
69
75 template <typename T>
76 using RemoveCVRef = std::remove_cv_t<std::remove_reference_t<T>>;
77
83 template <typename T>
84 static constexpr bool IS_MESSAGE_VIEW =
86
92 template <typename T>
93 static constexpr bool IS_TYPED_DATA =
96
102 template <typename T>
103 static constexpr bool IS_CALLBACK_PAYLOAD =
106
112 template <typename T>
113 static constexpr bool IS_MUTABLE_MESSAGE_VIEW_REF =
114 IS_MESSAGE_VIEW<T> && std::is_lvalue_reference_v<T> &&
115 !std::is_const_v<std::remove_reference_t<T>>;
116
131 {
132 using RunFun = void (*)(const BlockHeader*, bool, MicrosecondTimestamp,
133 void*);
134
135 RunFun run = nullptr;
136 TypeID::ID payload_type_id = nullptr;
137 };
138
145 template <typename PayloadArg>
146 static TypeID::ID PayloadTypeID()
147 {
149 "LibXR::Topic::Callback does not accept MessageView<T>&; "
150 "use MessageView<T> or const MessageView<T>& instead.");
151
152 if constexpr (IS_MESSAGE_VIEW<PayloadArg>)
153 {
156 }
157 else
158 {
159 static_assert(IS_TYPED_DATA<PayloadArg>,
160 "LibXR::Topic::Callback payload must be Topic::MessageView<T>, "
161 "T, T&, or const T&.");
163 }
164 }
165
180 template <typename Function, typename BoundArg, typename PayloadArg>
181 static void InvokePayload(Function fun, BoundArg& arg, bool in_isr,
182 MicrosecondTimestamp timestamp, void* payload_addr)
183 {
184 if constexpr (IS_MESSAGE_VIEW<PayloadArg>)
185 {
187 using Data = typename View::DataType;
188 fun(in_isr, arg,
189 MessageView<Data>{timestamp, reinterpret_cast<Data*>(payload_addr)});
190 }
191 else
192 {
193 using Data = RemoveCVRef<PayloadArg>;
194 fun(in_isr, arg, *reinterpret_cast<Data*>(payload_addr));
195 }
196 }
197
205 template <typename Function, typename BoundArg, typename PayloadArg>
207 {
214 PayloadOnlyBlock(Function fun, BoundArg&& arg)
215 : BlockHeader{&Run, PayloadTypeID<PayloadArg>()},
216 fun_(fun),
217 arg_(std::move(arg))
218 {
219 }
220
230 static void Run(const BlockHeader* header, bool in_isr,
231 MicrosecondTimestamp timestamp, void* payload_addr)
232 {
233 auto* block = static_cast<const PayloadOnlyBlock*>(header);
235 block->fun_, const_cast<BoundArg&>(block->arg_), in_isr, timestamp,
236 payload_addr);
237 }
238
239 Function fun_;
240 BoundArg arg_;
241 };
242
251 template <typename Function, typename BoundArg, typename PayloadArg>
253 {
260 TimestampPayloadBlock(Function fun, BoundArg&& arg)
261 : BlockHeader{&Run, PayloadTypeID<PayloadArg>()},
262 fun_(fun),
263 arg_(std::move(arg))
264 {
265 }
266
276 static void Run(const BlockHeader* header, bool in_isr,
277 MicrosecondTimestamp timestamp, void* payload_addr)
278 {
279 auto* block = static_cast<const TimestampPayloadBlock*>(header);
280 if constexpr (IS_MESSAGE_VIEW<PayloadArg>)
281 {
283 using Data = typename View::DataType;
284 block->fun_(
285 in_isr, block->arg_, timestamp,
286 MessageView<Data>{timestamp, reinterpret_cast<Data*>(payload_addr)});
287 }
288 else
289 {
290 using Data = RemoveCVRef<PayloadArg>;
291 block->fun_(in_isr, block->arg_, timestamp,
292 *reinterpret_cast<Data*>(payload_addr));
293 }
294 }
295
296 Function fun_;
297 BoundArg arg_;
298 };
299
308 template <typename Function, typename BoundArg, size_t Arity>
309 struct Factory
310 {
311 static_assert(Arity == 3 || Arity == 4,
312 "LibXR::Topic::Callback function must be void(bool, Arg, Payload) "
313 "or void(bool, Arg, MicrosecondTimestamp, Payload).");
314 };
315
322 template <typename Function, typename BoundArg>
323 struct Factory<Function, BoundArg, 3>
324 {
327 typename Traits::template Arg<2>;
328
336 static BlockHeader* Create(Function fun, BoundArg&& arg)
337 {
338 static_assert(std::same_as<typename Traits::ReturnType, void>);
339 static_assert(std::same_as<typename Traits::template Arg<0>, bool>);
340 static_assert(std::same_as<typename Traits::template Arg<1>, BoundArg>);
341 static_assert(IS_CALLBACK_PAYLOAD<PayloadArg>);
342 return new PayloadOnlyBlock<Function, BoundArg, PayloadArg>(fun, std::move(arg));
343 }
344 };
345
352 template <typename Function, typename BoundArg>
353 struct Factory<Function, BoundArg, 4>
354 {
357 typename Traits::template Arg<2>;
359 typename Traits::template Arg<3>;
360
368 static BlockHeader* Create(Function fun, BoundArg&& arg)
369 {
370 static_assert(std::same_as<typename Traits::ReturnType, void>);
371 static_assert(std::same_as<typename Traits::template Arg<0>, bool>);
372 static_assert(std::same_as<typename Traits::template Arg<1>, BoundArg>);
373 static_assert(std::same_as<RemoveCVRef<TimestampArg>, MicrosecondTimestamp>);
374 static_assert(IS_CALLBACK_PAYLOAD<PayloadArg>);
376 std::move(arg));
377 }
378 };
379
388 static void EmptyRun(const BlockHeader* header, bool in_isr,
389 MicrosecondTimestamp timestamp, void* payload_addr)
390 {
391 UNUSED(header);
392 UNUSED(in_isr);
393 UNUSED(timestamp);
394 UNUSED(payload_addr);
395 }
396
398 &EmptyRun,
399 nullptr};
400
401 public:
405 Callback() = default;
406
414 Callback(const Callback& other) = default;
415
424 Callback& operator=(const Callback& other) = default;
425
437 template <typename BoundArg, typename Callable>
438 [[nodiscard]] static Callback Create(Callable fun, BoundArg arg)
439 {
440 using Function = decltype(+std::declval<Callable>());
441 using Traits = FunctionTraits<Function>;
442 static_assert(Traits::ARITY == 3 || Traits::ARITY == 4,
443 "LibXR::Topic::Callback::Create expects a capture-free callable "
444 "with bool and bound-argument parameters.");
445 return Callback(
447 }
448
456 void Run(bool in_isr, MicrosecondTimestamp timestamp, void* payload_addr) const
457 {
458 block_->run(block_, in_isr, timestamp, payload_addr);
459 }
460
466 TypeID::ID PayloadTypeID() const { return block_->payload_type_id; }
467
468 private:
475 explicit Callback(BlockHeader* block) : block_(block ? block : &empty_block_) {}
476
478};
479
486{
491 explicit CallbackBlock(Callback& callback) : cb(callback)
492 {
494 }
495
497};
498
507{
508 ASSERT(block_->data_.payload_type_id == cb.PayloadTypeID());
509
510 auto node = new (std::align_val_t(LibXR::CACHE_LINE_SIZE))
512 block_->data_.subers.Add(*node);
513}
514} // namespace LibXR
数据节点模板,继承自 BaseNode,用于存储具体数据类型。 Template data node that inherits from BaseNode to store specific data...
微秒时间戳 / Microsecond timestamp
Data data_
存储的数据 (Stored data).
Definition rbt.hpp:98
每次发布时直接执行函数的订阅句柄 / Subscription handle that runs a function on each publish
Definition callback.hpp:13
static constexpr bool IS_MESSAGE_VIEW
是否为带时间戳的类型化消息视图参数 / Whether one callback payload argument is a timestamped typed message view
Definition callback.hpp:84
Callback & operator=(const Callback &other)=default
拷贝赋值回调句柄 / Copy-assign one callback handle
static constexpr bool IS_CALLBACK_PAYLOAD
是否是回调接口允许的 payload 参数写法 / Whether one payload argument form is accepted by this callback interface
Definition callback.hpp:103
void Run(bool in_isr, MicrosecondTimestamp timestamp, void *payload_addr) const
执行回调 / Run the callback
Definition callback.hpp:456
Callback(const Callback &other)=default
拷贝构造回调句柄 / Copy-construct one callback handle
Callback(BlockHeader *block)
用指定执行块构造回调句柄 / Construct one callback handle from the given execution block
Definition callback.hpp:475
static constexpr bool IS_MUTABLE_MESSAGE_VIEW_REF
是否错误地使用了可变 MessageView<T>& / Whether one payload argument is an invalid mutable MessageView<T>&
Definition callback.hpp:113
static Callback Create(Callable fun, BoundArg arg)
创建一个回调订阅句柄 / Create a callback subscription handle
Definition callback.hpp:438
static void EmptyRun(const BlockHeader *header, bool in_isr, MicrosecondTimestamp timestamp, void *payload_addr)
空回调块的执行函数 / Execution function of the empty callback block
Definition callback.hpp:388
static BlockHeader empty_block_
空回调句柄共用的静态空执行块。Shared static empty execution block used by empty callback handles.
Definition callback.hpp:397
Callback()=default
构造一个空回调句柄 / Construct one empty callback handle
TypeID::ID PayloadTypeID() const
读取这个回调句柄期望的 payload 类型标识 / Read the payload type ID expected by this callback handle
Definition callback.hpp:466
std::remove_cv_t< std::remove_reference_t< T > > RemoveCVRef
去掉引用和 cv 限定后的规范类型 / Canonical type after removing reference and cv qualifiers
Definition callback.hpp:76
static constexpr bool IS_TYPED_DATA
是否把 payload 直接当成一个对象接收 / Whether one callback payload argument receives the payload directly as one o...
Definition callback.hpp:93
static void InvokePayload(Function fun, BoundArg &arg, bool in_isr, MicrosecondTimestamp timestamp, void *payload_addr)
按回调声明的参数形式,把当前消息拼成实参再调函数 / Build the actual call arguments from the current message in the form decla...
Definition callback.hpp:181
BlockHeader * block_
当前回调句柄绑定的执行块。Execution block bound to the current callback handle.
Definition callback.hpp:477
static TypeID::ID PayloadTypeID()
取回调 payload 参数对应的精确类型标识 / Get the exact type ID expected by one callback payload argument
Definition callback.hpp:146
@ CALLBACK
回调执行型订阅者。Callback-executing subscriber.
TopicHandle block_
当前 topic 视图绑定的状态块。Runtime state block bound to the current topic view.
Definition topic.hpp:533
void RegisterCallback(Callback &cb)
注册一个回调订阅者 / Register one callback subscriber
Definition callback.hpp:506
static ID GetID()
获取类型的唯一标识符 / Get a unique identifier for type T
topic 可承载 payload 的类型约束 / Type constraint for payloads carried by one topic
Definition topic.hpp:28
LibXR 命名空间
Definition ch32_can.hpp:14
constexpr size_t CACHE_LINE_SIZE
缓存行大小 / Cache line size
Definition libxr_def.hpp:56
回调句柄真正指向的那块数据的公共头 / Common header of the data block actually pointed to by one callback handle
Definition callback.hpp:131
TypeID::ID payload_type_id
该回调期望的主题负载类型标识。Expected topic payload type identifier.
Definition callback.hpp:136
RunFun run
当前块的执行函数。Execution function of the current block.
Definition callback.hpp:135
void(*)(const BlockHeader *, bool, MicrosecondTimestamp, void *) RunFun
所有具体回调块共用的执行入口。Shared execution entry used by all concrete callback blocks.
Definition callback.hpp:132
typename Traits::template Arg< 2 > PayloadArg
第三个参数,即负载参数类型。Third argument, namely the payload argument type.
Definition callback.hpp:326
static BlockHeader * Create(Function fun, BoundArg &&arg)
创建只转发负载的回调块 / Create one callback block that forwards only the payload
Definition callback.hpp:336
static BlockHeader * Create(Function fun, BoundArg &&arg)
创建同时转发时间戳和负载的回调块 / Create one callback block that forwards both timestamp and payload
Definition callback.hpp:368
typename Traits::template Arg< 3 > PayloadArg
第四个参数,即负载参数类型。Fourth argument, namely the payload argument type.
Definition callback.hpp:358
typename Traits::template Arg< 2 > TimestampArg
第三个参数,即时间戳参数类型。Third argument, namely the timestamp argument type.
Definition callback.hpp:356
看回调有几个参数,决定分配哪种回调块 / Choose which callback block to allocate from the callback parameter count
Definition callback.hpp:310
std::tuple_element_t< Index, std::tuple< Args... > > Arg
取出指定下标的参数类型 / Fetch the argument type at the given index
Definition callback.hpp:41
Return ReturnType
回调返回类型。Callback return type.
Definition callback.hpp:33
把一个无捕获回调函数拆成返回类型和参数类型 / Split one callback function without captures into its return type and paramet...
Definition callback.hpp:21
Data DataType
MessageView 对应的数据类型。Payload type behind the MessageView.
Definition callback.hpp:67
判断某个参数是否为 MessageView<T> / Tell whether one argument is MessageView<T>
Definition callback.hpp:52
static constexpr bool VALUE
默认不是 MessageView。Not a MessageView by default.
Definition callback.hpp:53
只转发负载的回调块 / Callback block that forwards only the payload
Definition callback.hpp:207
static void Run(const BlockHeader *header, bool in_isr, MicrosecondTimestamp timestamp, void *payload_addr)
根据块头指针取回具体块并执行回调 / Recover the concrete block from the block header pointer and run the callback
Definition callback.hpp:230
BoundArg arg_
绑定到回调中的参数副本。Stored copy of the bound argument.
Definition callback.hpp:240
Function fun_
目标回调函数。Target callback function.
Definition callback.hpp:239
PayloadOnlyBlock(Function fun, BoundArg &&arg)
构造一个只转发负载的具体回调块 / Construct one concrete callback block that forwards only the payload
Definition callback.hpp:214
同时转发时间戳和负载的回调块 / Callback block that forwards both timestamp and payload
Definition callback.hpp:253
BoundArg arg_
绑定到回调中的参数副本。Stored copy of the bound argument.
Definition callback.hpp:297
Function fun_
目标回调函数。Target callback function.
Definition callback.hpp:296
static void Run(const BlockHeader *header, bool in_isr, MicrosecondTimestamp timestamp, void *payload_addr)
根据块头指针取回具体块并执行带时间戳回调 / Recover the concrete block from the block header pointer and run the timestamp...
Definition callback.hpp:276
TimestampPayloadBlock(Function fun, BoundArg &&arg)
构造一个同时转发时间戳和负载的具体回调块 / Construct one concrete callback block that forwards both timestamp and payload
Definition callback.hpp:260
挂在 topic 订阅链表里的回调记录 / Callback record stored in the topic subscriber list
Definition callback.hpp:486
Callback cb
订阅的回调句柄。Subscribed callback handle.
Definition callback.hpp:496
CallbackBlock(Callback &callback)
构造一个回调订阅块 / Construct one callback subscriber block
Definition callback.hpp:491
带时间戳和 payload 指针的只读消息视图 / Read-only message view carrying a timestamp and a payload pointer
Definition topic.hpp:126
所有订阅块共用的公共头 / Common header shared by all subscriber blocks
Definition topic.hpp:207
SuberType type
订阅块的具体种类。Concrete kind of this subscriber block.
Definition topic.hpp:208