NexusForce 1.0.0
A rigorously engineered full-stack C++ backend library.
载入中...
搜索中...
未找到
signals.hpp
浏览该文件的文档.
1#ifndef NEFORCE_CORE_ASYNC_SIGNALS_HPP__
2#define NEFORCE_CORE_ASYNC_SIGNALS_HPP__
3
11
19NEFORCE_BEGIN_NAMESPACE__
20
26
35public:
36 virtual ~signal_base() = default;
37
41 virtual void disconnect_all() = 0;
42
46 virtual void block() = 0;
47
51 virtual void unblock() = 0;
52
56 NEFORCE_NODISCARD virtual bool is_blocked() const = 0;
57
61 NEFORCE_NODISCARD virtual size_t slot_count() const = 0;
62
69 virtual void emit_dynamic(const vector<reflect::meta_any>& args) = 0;
70
77 virtual void connect_dynamic(function<void(const vector<reflect::meta_any>&)> callback) = 0;
78};
79
80
87enum class callback_result {
90};
91
92
99struct oneshot_t {
100 constexpr oneshot_t() noexcept = default;
101};
102
106NEFORCE_INLINE17 constexpr oneshot_t oneshot{};
107
114enum class nshot_t : size_t {
115};
116
117
126private:
127 shared_ptr<bool> connected_;
128
129public:
134 connected_(_NEFORCE make_shared<bool>(true)) {}
135
142 void disconnect() noexcept {
143 if (connected_) {
144 *connected_ = false;
145 }
146 }
147
152 NEFORCE_NODISCARD bool connected() const noexcept { return connected_ && *connected_; }
153
158 NEFORCE_NODISCARD shared_ptr<bool> flag() const noexcept { return connected_; }
159};
160
161
169private:
170 connection conn_;
171
172public:
176 scope_connection() = default;
177
182 explicit scope_connection(connection conn) noexcept :
183 conn_(_NEFORCE move(conn)) {}
184
188 ~scope_connection() { conn_.disconnect(); }
189
190 scope_connection(const scope_connection&) = delete;
191 scope_connection& operator=(const scope_connection&) = delete;
192
198 conn_(_NEFORCE move(other.conn_)) {}
199
206 if (addressof(other) == this) {
207 return *this;
208 }
209 conn_.disconnect();
210 conn_ = _NEFORCE move(other.conn_);
211 return *this;
212 }
213
217 void disconnect() noexcept { conn_.disconnect(); }
218
223 NEFORCE_NODISCARD bool connected() const noexcept { return conn_.connected(); }
224
231 connection release() noexcept { return _NEFORCE move(conn_); }
232};
233
234
235template <typename... Types>
236struct signal;
237
244template <typename... Types>
246private:
247 shared_ptr<bool> blocked_flag_;
248 bool old_value_;
249 bool released_ = false;
250
251public:
256 explicit signal_blocker(signal<Types...>& sig) noexcept :
257 blocked_flag_(sig.block_flag()) {
258 old_value_ = *blocked_flag_;
259 *blocked_flag_ = true;
260 }
261
266 if (blocked_flag_ && !released_) {
267 *blocked_flag_ = old_value_;
268 }
269 }
270
271 signal_blocker(const signal_blocker&) = delete;
272 signal_blocker& operator=(const signal_blocker&) = delete;
273
279 void unblock() noexcept {
280 if (blocked_flag_ && !released_) {
281 *blocked_flag_ = old_value_;
282 released_ = true;
283 }
284 }
285};
286
287
295template <typename... Types>
296struct signal final : public signal_base {
297private:
302 struct slot_entry {
303 using callback_type = function<callback_result(Types...)>;
304
305 callback_type callback;
306 shared_ptr<bool> connected_flag;
307 int priority;
308
309 slot_entry(callback_type cb, shared_ptr<bool> flag, const int pri = 0) :
310 callback(_NEFORCE move(cb)),
311 connected_flag(_NEFORCE move(flag)),
312 priority(pri) {}
313 };
314
315 vector<slot_entry> slots_{};
316 shared_ptr<bool> blocked_flag_{_NEFORCE make_shared<bool>(false)};
317 mutable mutex mutex_;
318
319 template <typename T>
320 static shared_ptr<T> lock_if_weak(const weak_ptr<T>& self) {
321 return self.lock();
322 }
323 template <typename T>
324 static const shared_ptr<T>& lock_if_weak(const shared_ptr<T>& self) noexcept {
325 return self;
326 }
327 template <typename T>
328 static T* lock_if_weak(T* self) noexcept {
329 return self;
330 }
331
332 template <typename Func>
333 auto with_lock(Func&& func) const {
334 lock<mutex> lock(mutex_);
335 return _NEFORCE forward<Func>(func)();
336 }
337
338 template <typename Func>
339 auto with_lock(Func&& func) {
340 lock<mutex> lock(mutex_);
341 return _NEFORCE forward<Func>(func)();
342 }
343
352 template <typename Self, typename MemFn>
353 auto bind(Self self, MemFn memfn) {
354 return [self = _NEFORCE move(self), memfn](Types... args) {
355 auto ptr = signal::lock_if_weak(self);
356 if (ptr == nullptr) {
358 }
359 ((*ptr).*memfn)(_NEFORCE forward<Types>(args)...);
361 };
362 }
363
373 template <typename Self, typename MemFn>
374 auto bind(Self self, MemFn memfn, oneshot_t one) {
375 return [self = _NEFORCE move(self), memfn](Types... args) {
376 auto ptr = signal::lock_if_weak(self);
377 if (ptr == nullptr) {
379 }
380 ((*ptr).*memfn)(_NEFORCE forward<Types>(args)...);
382 };
383 }
384
394 template <typename Self, typename MemFn>
395 auto bind(Self self, MemFn memfn, nshot_t n) {
396 return [self = _NEFORCE move(self), memfn, n = static_cast<size_t>(n)](Types... args) mutable {
397 if (n == 0) {
399 }
400 auto ptr = signal::lock_if_weak(self);
401 if (ptr == nullptr) {
403 }
404 ((*ptr).*memfn)(_NEFORCE forward<Types>(args)...);
405 --n;
406 if (n == 0) {
408 }
410 };
411 }
412
420 template <typename Func>
421 enable_if_t<is_invocable_r_v<callback_result, Func, Types...>, connection> connect_impl(Func callback,
422 int priority) {
423 connection conn{};
424
425 auto it = slots_.begin();
426 while (it != slots_.end() && it->priority >= priority) {
427 ++it;
428 }
429 slots_.emplace(it, _NEFORCE move(callback), conn.flag(), priority);
430
431 return conn;
432 }
433
441 template <typename Func>
442 enable_if_t<!is_invocable_r_v<callback_result, Func, Types...>, connection> connect_impl(Func callback,
443 int priority) {
444 connection conn{};
445
446 auto wrapped = [callback = _NEFORCE move(callback)](Types... args) mutable {
447 callback(_NEFORCE forward<Types>(args)...);
449 };
450
451 auto it = slots_.begin();
452 while (it != slots_.end() && it->priority >= priority) {
453 ++it;
454 }
455 slots_.emplace(it, _NEFORCE move(wrapped), conn.flag(), priority);
456
457 return conn;
458 }
459
460 size_t slot_count_unlocked() const noexcept {
461 size_t count = 0;
462 for (const auto& slot: slots_) {
463 if (slot.connected_flag && *slot.connected_flag) {
464 ++count;
465 }
466 }
467 return count;
468 }
469
470 template <size_t... Is>
471 void emit_dynamic_impl(const vector<reflect::meta_any>& args, index_sequence<Is...> /*unused*/) {
472 this->emit(args[Is].template convert<Types>()...);
473 }
474
475public:
476 signal() = default;
477 ~signal() override = default;
478 signal(const signal&) = delete;
479 signal& operator=(const signal&) = delete;
480 signal(signal&&) = delete;
481 signal& operator=(signal&&) = delete;
482
493 template <typename Self, typename MemFn, typename... Tag>
494 connection connect(Self self, MemFn memfn, Tag... tag) {
495 return this->connect(_NEFORCE move(self), memfn, 0, tag...);
496 }
497
505 template <typename Func>
506 connection connect(Func callback, int priority = 0) {
507 return this->with_lock([this, callback = _NEFORCE move(callback), priority] {
508 return this->connect_impl(_NEFORCE move(callback), priority);
509 });
510 }
511
523 template <typename Self, typename MemFn, typename... Tag>
524 connection connect(Self self, MemFn memfn, int priority, Tag... tag) {
525 static_assert(sizeof...(Tag) <= 1, "only zero or one tag is allowed");
526
527 return this->with_lock([this, self = _NEFORCE move(self), memfn = _NEFORCE move(memfn), priority, tag...] {
528 connection conn{};
529
530 auto it = slots_.begin();
531 while (it != slots_.end() && it->priority >= priority) {
532 ++it;
533 }
534 slots_.emplace(it, this->bind(_NEFORCE move(self), memfn, tag...), conn.flag(), priority);
535
536 return conn;
537 });
538 }
539
547 void emit(Types... args) {
548 vector<slot_entry> snapshot;
549 {
550 lock<mutex> lk(mutex_);
551 if (is_blocked()) {
552 return;
553 }
554 snapshot = slots_;
555 }
556
557 for (auto& slot: snapshot) {
558 if (!slot.connected_flag || !(*slot.connected_flag)) {
559 continue;
560 }
561
562 const callback_result res = slot.callback(args...);
563 if (res == callback_result::erase) {
564 *slot.connected_flag = false;
565 }
566 }
567
568 {
569 lock<mutex> lk(mutex_);
570 slots_.erase(
571 _NEFORCE remove_if(slots_.begin(), slots_.end(),
572 [](const slot_entry& s) { return !s.connected_flag || !(*s.connected_flag); }),
573 slots_.end());
574 }
575 }
576
585 template <typename Executor>
586 void emit_executor(Executor& executor, Types... args) {
587 auto weak_flag = weak_ptr<bool>(blocked_flag_);
588 auto args_tuple = _NEFORCE make_tuple(_NEFORCE forward<Types>(args)...);
589
590 executor.post([this, weak_flag = _NEFORCE move(weak_flag), args_tuple = _NEFORCE move(args_tuple)]() mutable {
591 if (weak_flag.expired()) {
592 return;
593 }
594
595 _NEFORCE apply([this](auto&&... a) { this->emit(_NEFORCE forward<decltype(a)>(a)...); },
596 _NEFORCE move(args_tuple));
597 });
598 }
599
604 template <typename... Args>
605 void operator()(Args&&... args) {
606 this->emit(_NEFORCE forward<Args>(args)...);
607 }
608
612 void disconnect_all() override {
613 this->with_lock([this] { slots_.clear(); });
614 }
615
624 connection connect_signal(signal& other, int priority = 0) {
625 return this->connect(
626 [other_ptr = &other](Types... args) {
627 other_ptr->emit(args...);
628 return callback_result::keep;
629 },
630 priority);
631 }
632
641 connection connect_signal(signal* other, int priority = 0) {
642 return this->connect(
643 [other](Types... args) {
644 if (other) {
645 other->emit(args...);
646 }
648 },
649 priority);
650 }
651
663 template <typename Func, typename Predicate>
664 connection connect_if(Func callback, Predicate pred, int priority = 0) {
665 using result_type = invoke_result_t<Predicate, Types...>;
666 static_assert(is_boolean_v<result_type>, "only boolean results are allowed");
667
668 return this->connect(
669 [callback = _NEFORCE move(callback), pred = _NEFORCE move(pred)](Types... args) mutable {
670 if (pred(args...)) {
671 callback(_NEFORCE forward<Types>(args)...);
672 }
674 },
675 priority);
676 }
677
691 template <typename Self, typename MemFn, typename Predicate, typename... Tag>
692 connection connect_if(Self self, MemFn memfn, Predicate pred, int priority, Tag... tag) {
693 using result_type = invoke_result_t<Predicate, Types...>;
694 static_assert(is_boolean_v<result_type>, "only boolean results are allowed");
695 static_assert(sizeof...(Tag) <= 1, "only zero or one tag is allowed");
696
697 auto bound = this->bind(_NEFORCE move(self), memfn, tag...);
698
699 return this->connect(
700 [bound = _NEFORCE move(bound), pred = _NEFORCE move(pred)](Types... args) mutable {
701 if (pred(args...)) {
702 return bound(_NEFORCE forward<Types>(args)...);
703 }
705 },
706 priority);
707 }
708
720 template <typename Func, typename Filter>
721 connection connect_filtered(Func callback, Filter filter, int priority = 0) {
722 return this->connect(
723 [callback = _NEFORCE move(callback), filter = _NEFORCE move(filter)](Types... args) mutable {
724 auto filtered = filter(args...);
725 if (filtered) {
726 auto filtered_tuple = _NEFORCE make_tuple(_NEFORCE move(*filtered));
727 _NEFORCE apply(
728 [&callback](auto&&... filtered_args) {
729 callback(_NEFORCE forward<decltype(filtered_args)>(filtered_args)...);
730 },
731 _NEFORCE move(filtered_tuple));
732 }
734 },
735 priority);
736 }
737
749 template <typename Func, typename Transform>
750 connection connect_transformed(Func callback, Transform transform, int priority = 0) {
751 static_assert(is_invocable_v<Transform, Types...>, "only function inputs are allowed");
752
753 return this->connect(
754 [callback = _NEFORCE move(callback), transform = _NEFORCE move(transform)](Types... args) mutable {
755 callback(transform(_NEFORCE forward<Types>(args)...));
756 return callback_result::keep;
757 },
758 priority);
759 }
760
765 shared_ptr<bool> block_flag() const noexcept { return blocked_flag_; }
766
771 bool is_blocked() const noexcept override { return blocked_flag_ && *blocked_flag_; }
772
776 void block() override {
777 if (blocked_flag_) {
778 *blocked_flag_ = true;
779 }
780 }
781
785 void unblock() override {
786 if (blocked_flag_) {
787 *blocked_flag_ = false;
788 }
789 }
790
795 size_t slot_count() const noexcept override {
796 return this->with_lock([this] { return slot_count_unlocked(); });
797 }
798
805 void connect_dynamic(function<void(const vector<reflect::meta_any>&)> callback) override {
806 this->connect([cb = _NEFORCE move(callback)](Types... args) {
807 vector<reflect::meta_any> wrapped;
808 wrapped.reserve(sizeof...(Types));
809 (wrapped.emplace_back(_NEFORCE forward<Types>(args)), ...);
810 cb(wrapped);
811 return callback_result::keep;
812 });
813 }
814
819 void emit_dynamic(const vector<reflect::meta_any>& args) override {
820 if (args.size() < sizeof...(Types)) {
821 return;
822 }
823 emit_dynamic_impl(args, make_index_sequence<sizeof...(Types)>{});
824 }
825
830 NEFORCE_NODISCARD bool empty() const noexcept {
831 return this->with_lock([this] { return slot_count_unlocked() == 0; });
832 }
833};
834 // Signals
836
837NEFORCE_END_NAMESPACE__
838#endif // NEFORCE_CORE_ASYNC_SIGNALS_HPP__
元组应用函数
shared_ptr< bool > flag() const noexcept
获取连接标志的内部指针
bool connected() const noexcept
检查连接是否有效
connection()
默认构造函数,创建处于已连接状态的对象
void disconnect() noexcept
断开连接
多态执行器
void post(handler_type handler) const
投递 handler 到执行器
函数包装器主模板声明
锁管理器模板
非递归互斥锁
bool connected() const noexcept
检查连接是否有效
scope_connection & operator=(scope_connection &&other) noexcept
移动赋值运算符
scope_connection(scope_connection &&other) noexcept
移动构造函数
scope_connection(connection conn) noexcept
从连接构造
~scope_connection()
析构函数,自动断开连接
void disconnect() noexcept
手动断开连接
scope_connection()=default
默认构造函数
connection release() noexcept
释放连接所有权
共享智能指针类模板
信号类型擦除基类
virtual bool is_blocked() const =0
是否处于阻塞状态
virtual size_t slot_count() const =0
获取已连接槽数量
virtual void connect_dynamic(function< void(const vector< reflect::meta_any > &)> callback)=0
动态连接槽回调(类型擦除版本)
virtual void emit_dynamic(const vector< reflect::meta_any > &args)=0
通过 meta_any 参数列表触发信号(类型擦除版本)
virtual void block()=0
阻塞信号触发
virtual void unblock()=0
解除阻塞
virtual void disconnect_all()=0
断开所有连接
signal_blocker(signal< Types... > &sig) noexcept
构造函数,阻塞指定信号
~signal_blocker()
析构函数,恢复原状态
void unblock() noexcept
手动解除阻塞
动态大小数组容器
constexpr size_type size() const noexcept
获取当前元素数量
弱智能指针类模板
shared_ptr< T > lock() const noexcept
尝试获取共享智能指针
通用函数包装器
constexpr T * addressof(T &x) noexcept
获取对象的地址
constexpr T && forward(remove_reference_t< T > &x) noexcept
完美转发左值
constexpr bool is_boolean_v
is_boolean的便捷变量模板
constexpr iter_difference_t< Iterator > count(Iterator first, Iterator last, const T &value)
统计范围内等于指定值的元素数量
integer_sequence< size_t, Values... > index_sequence
索引序列
make_integer_sequence< size_t, Size > make_index_sequence
生成指定长度的索引序列
typename inner::__invoke_result_aux< F, Args... >::type invoke_result_t
invoke_result的便捷别名
constexpr bool is_invocable_v
is_invocable的便捷变量模板
constexpr bool is_invocable_r_v
is_invocable_r的便捷变量模板
constexpr size_t erase(Container &cont, const U &value)
从容器中删除所有等于指定值的元素
constexpr Iterator remove_if(Iterator first, Iterator last, Predicate pred)
移除范围中满足谓词的元素
enable_if_t<!is_unbounded_array_v< T > &&is_constructible_v< T, Args... >, shared_ptr< T > > make_shared(Args &&... args)
融合分配创建共享指针
constexpr Iterator2 transform(Iterator1 first, Iterator1 last, Iterator2 result, UnaryOperation op) noexcept(noexcept(++first) &&noexcept(++result) &&noexcept(*result=op(*first)))
对范围元素应用一元变换
constexpr Iterator2 move(Iterator1 first, Iterator1 last, Iterator2 result) noexcept(noexcept(inner::__move_aux(first, last, result)))
移动范围元素
callback_result
回调结果枚举
constexpr oneshot_t oneshot
一次性连接标签实例
nshot_t
多次连接标签
@ erase
调用后自动删除
constexpr decltype(auto) apply(Func &&f, Tuple &&t) noexcept(inner::__apply_unpack_tuple< _NEFORCE is_nothrow_invocable, Func, Tuple >::value)
将元组元素解包作为参数调用函数
constexpr tuple< unwrap_ref_decay_t< Types >... > make_tuple(Types &&... args)
从参数创建元组
typename enable_if< Test, T >::type enable_if_t
enable_if的便捷别名
互斥锁
类型擦除容器
删除算法
一次性连接标签
shared_ptr< bool > block_flag() const noexcept
获取阻塞标志
connection connect(Self self, MemFn memfn, Tag... tag)
连接成员函数(默认优先级0)
bool is_blocked() const noexcept override
void emit_executor(Executor &executor, Types... args)
执行器触发信号
void emit(Types... args)
触发信号
connection connect(Func callback, int priority=0)
连接普通函数/lambda
connection connect_filtered(Func callback, Filter filter, int priority=0)
过滤连接
void disconnect_all() override
断开所有连接
connection connect_transformed(Func callback, Transform transform, int priority=0)
变换连接
connection connect(Self self, MemFn memfn, int priority, Tag... tag)
连接成员函数
void connect_dynamic(function< void(const vector< reflect::meta_any > &)> callback) override
动态连接(类型擦除版本)
void unblock() override
解除阻塞
void emit_dynamic(const vector< reflect::meta_any > &args) override
通过 meta_any 触发信号(类型擦除版本)
connection connect_if(Func callback, Predicate pred, int priority=0)
条件连接
void operator()(Args &&... args)
函数调用操作符
bool empty() const noexcept
检查信号是否为空(无活跃槽)
connection connect_signal(signal &other, int priority=0)
连接另一个信号
size_t slot_count() const noexcept override
获取活跃槽的数量
connection connect_signal(signal *other, int priority=0)
连接另一个信号(指针版本)
void block() override
阻塞信号触发
connection connect_if(Self self, MemFn memfn, Predicate pred, int priority, Tag... tag)
条件连接(成员函数版本)
动态大小数组容器
弱智能指针实现