19 #ifndef LIB_CS_SIGNAL_H
20 #define LIB_CS_SIGNAL_H
27 #include <type_traits>
29 #include <unordered_set>
39 enum class ConnectionKind {
43 BlockingQueuedConnection
46 enum class DisconnectKind {
51 template <
class Iter1,
class Iter2,
class T>
52 Iter1 find(Iter1 iter1,
const Iter2 &iter2,
const T &value)
54 while (iter1 != iter2) {
55 if (value == *iter1) {
65 template<
class Sender,
class SignalClass,
class ...SignalArgs,
class Receiver,
66 class SlotClass,
class ...SlotArgs,
class SlotReturn>
67 bool connect(
const Sender &sender,
void (SignalClass::*signalMethod)(SignalArgs...),
68 const Receiver &receiver, SlotReturn (SlotClass::*slotMethod)(SlotArgs...),
69 ConnectionKind type = ConnectionKind::AutoConnection,
bool uniqueConnection =
false);
71 template<
class Sender,
class SignalClass,
class ...SignalArgs,
class Receiver,
class T>
72 bool connect(
const Sender &sender,
void (SignalClass::*signalMethod)(SignalArgs...),
73 const Receiver &receiver, T slotLambda,
74 ConnectionKind type = ConnectionKind::AutoConnection,
bool uniqueConnection =
false);
76 template<
class Sender,
class Receiver>
77 bool connect(
const Sender &sender, std::unique_ptr<Internal::BentoAbstract> signalMethod_Bento,
78 const Receiver &receiver, std::unique_ptr<Internal::BentoAbstract> slotMethod_Bento,
79 ConnectionKind type = ConnectionKind::AutoConnection,
bool uniqueConnection =
false);
85 virtual ~SignalBase();
88 static Internal::BentoAbstract *&get_threadLocal_currentSignal();
90 int internal_cntConnections(
const SlotBase *receiver,
91 const Internal::BentoAbstract &signalMethod_Bento)
const;
93 std::set<SlotBase *> internal_receiverList(
94 const Internal::BentoAbstract &signalMethod_Bento)
const;
98 static std::mutex &get_mutex_beingDestroyed();
99 static std::unordered_set<
const SignalBase *> &get_beingDestroyed();
102 mutable int m_activateBusy = 0;
104 struct ConnectStruct {
105 std::unique_ptr<
const Internal::BentoAbstract> signalMethod;
106 const SlotBase *receiver;
107 std::unique_ptr<
const Internal::BentoAbstract> slotMethod;
112 mutable libguarded::SharedList<ConnectStruct> m_connectList;
114 void addConnection(std::unique_ptr<
const Internal::BentoAbstract> signalMethod,
const SlotBase *,
115 std::unique_ptr<
const Internal::BentoAbstract> slotMethod, ConnectionKind type,
116 libguarded::SharedList<ConnectStruct>::write_handle &senderListHandle)
const;
118 virtual void handleException(std::exception_ptr data);
120 template<
class Sender,
class SignalClass,
class ...SignalArgTypes,
class ...Ts>
121 friend void activate(Sender &sender,
void (SignalClass::*signal)(SignalArgTypes...), Ts &&... Vs);
123 template<
class Sender,
class SignalClass,
class ...SignalArgs,
class Receiver,
124 class SlotClass,
class ...SlotArgs,
class SlotReturn>
125 friend bool connect(
const Sender &sender,
void (SignalClass::*signalMethod)(SignalArgs...),
126 const Receiver &receiver, SlotReturn (SlotClass::*slotMethod)(SlotArgs...),
127 ConnectionKind type,
bool uniqueConnection);
129 template<
class Sender,
class SignalClass,
class ...SignalArgs,
class Receiver,
class T>
130 friend bool connect(
const Sender &sender,
void (SignalClass::*signalMethod)(SignalArgs...),
131 const Receiver &receiver, T slotLambda,
132 ConnectionKind type,
bool uniqueConnection);
134 template<
class Sender,
class Receiver>
135 friend bool connect(
const Sender &sender, std::unique_ptr<Internal::BentoAbstract> signalMethod_Bento,
136 const Receiver &receiver, std::unique_ptr<Internal::BentoAbstract> slotMethod_Bento,
137 ConnectionKind type,
bool uniqueConnection);
139 template<
class Sender,
class Receiver>
140 friend bool internal_disconnect(
const Sender &sender,
const Internal::BentoAbstract *signalBento,
141 const Receiver *receiver,
const Internal::BentoAbstract *slotBento);
143 friend class SlotBase;
146 template<
class Sender,
class SignalClass,
class ...SignalArgTypes,
class ...Ts>
147 void activate(Sender &sender,
void (SignalClass::*signal)(SignalArgTypes...), Ts &&... Vs)
150 static_assert( std::is_convertible<std::tuple<Ts...>, std::tuple<SignalArgTypes...>>::value,
151 "activate(): Signal parameter mismatch.");
153 Internal::Bento<
void (SignalClass::*)(SignalArgTypes...)> signal_Bento(signal);
156 const SignalBase *senderPtr = &sender;
159 CsSignal::Internal::TeaCup_Data<SignalArgTypes...> dataPack(
false, std::forward<Ts>(Vs)...);
161 SignalBase *priorSender = SlotBase::get_threadLocal_currentSender();
162 SlotBase::get_threadLocal_currentSender() = &sender;
164 Internal::BentoAbstract *priorSignal = SignalBase::get_threadLocal_currentSignal();
165 SignalBase::get_threadLocal_currentSignal() = &signal_Bento;
168 auto senderListHandle = sender.m_connectList.lock_read();
170 for (
const auto &connection : *senderListHandle) {
172 if (*(connection.signalMethod) != signal_Bento) {
177 SlotBase *receiver =
const_cast<SlotBase *>(connection.receiver);
180 const std::unique_ptr<
const CsSignal::Internal::BentoAbstract> &slot_Bento = connection.slotMethod;
182 bool receiverInSameThread = receiver->compareThreads();
184 int old_activateBusy = sender.m_activateBusy;
185 sender.m_activateBusy++;
189 if ( (connection.type == ConnectionKind::AutoConnection && ! receiverInSameThread) ||
190 (connection.type == ConnectionKind::QueuedConnection)) {
193 PendingSlot tempObj(&sender, signal_Bento.clone(), receiver, slot_Bento->clone(),
194 std::make_unique<CsSignal::Internal::TeaCup_Data<SignalArgTypes...>>(
true, std::forward<Ts>(Vs)... ));
196 receiver->queueSlot(std::move(tempObj), ConnectionKind::QueuedConnection);
198 }
else if (connection.type == ConnectionKind::BlockingQueuedConnection) {
201 PendingSlot tempObj(&sender, signal_Bento.clone(), receiver, slot_Bento->clone(),
202 std::make_unique<CsSignal::Internal::TeaCup_Data<SignalArgTypes...>>(
false, std::forward<Ts>(Vs)... ));
204 receiver->queueSlot(std::move(tempObj), ConnectionKind::BlockingQueuedConnection);
206 }
else if (connection.type == ConnectionKind::DirectConnection || connection.type == ConnectionKind::AutoConnection) {
210 slot_Bento->invoke(receiver, &dataPack);
213 std::lock_guard<std::mutex> lock(SignalBase::get_mutex_beingDestroyed());
215 if (SignalBase::get_beingDestroyed().count(senderPtr)) {
217 SlotBase::get_threadLocal_currentSender() = priorSender;
218 SignalBase::get_threadLocal_currentSignal() = priorSignal;
220 if (old_activateBusy == 0) {
221 SignalBase::get_beingDestroyed().erase(senderPtr);
228 SlotBase::get_threadLocal_currentSender() = priorSender;
229 SignalBase::get_threadLocal_currentSignal() = priorSignal;
231 std::lock_guard<std::mutex> lock(SignalBase::get_mutex_beingDestroyed());
233 if (SignalBase::get_beingDestroyed().count(senderPtr)) {
236 if (old_activateBusy == 0) {
237 SignalBase::get_beingDestroyed().erase(senderPtr);
243 sender.handleException(std::current_exception());
244 SlotBase::get_threadLocal_currentSender() = &sender;
250 sender.m_activateBusy--;
252 }
catch (std::exception &) {
253 SlotBase::get_threadLocal_currentSender() = priorSender;
254 SignalBase::get_threadLocal_currentSignal() = priorSignal;
256 std::throw_with_nested(std::invalid_argument(
"activate(): Failed to obtain sender lock"));
260 SlotBase::get_threadLocal_currentSender() = priorSender;
261 SignalBase::get_threadLocal_currentSignal() = priorSignal;
265 template<
class Sender,
class SignalClass,
class ...SignalArgs,
class Receiver,
class SlotClass,
266 class ...SlotArgs,
class SlotReturn>
267 bool connect(
const Sender &sender,
void (SignalClass::*signalMethod)(SignalArgs...),
268 const Receiver &receiver, SlotReturn (SlotClass::*slotMethod)(SlotArgs...),
269 ConnectionKind type,
bool uniqueConnection)
283 static_assert( std::is_base_of<SignalClass, Sender>::value,
284 "connect(): Signal was not a child class of Sender");
287 static_assert( std::is_base_of<SlotClass, Receiver>::value,
288 "connect(): Slot was not a child class of Receiver");
291 static_assert( Internal::cs_check_connect_args<
void (*)(SignalArgs...),
void (*)(SlotArgs...) >::value,
292 "connect(): Incompatible signal/slot arguments");
294 if (signalMethod ==
nullptr) {
295 throw std::invalid_argument(
"connect() Can not connect, signal is null");
298 if (slotMethod ==
nullptr) {
299 throw std::invalid_argument(
"connect(): Can not connect, slot is null");
302 std::unique_ptr<Internal::Bento<
void (SignalClass::*)(SignalArgs...)>>
303 signalMethod_Bento(
new Internal::Bento<
void (SignalClass::*)(SignalArgs...)>(signalMethod));
305 std::unique_ptr<Internal::Bento<SlotReturn (SlotClass::*)(SlotArgs...)>>
306 slotMethod_Bento(
new Internal::Bento<SlotReturn (SlotClass::*)(SlotArgs...)>(slotMethod));
308 auto senderListHandle = sender.m_connectList.lock_write();
310 if (uniqueConnection) {
313 for (
auto &item : *senderListHandle) {
315 if (item.receiver != &receiver) {
319 if (*(item.signalMethod) != *(signalMethod_Bento)) {
323 if (*(item.slotMethod) != *(slotMethod_Bento)) {
332 sender.addConnection(std::move(signalMethod_Bento), &receiver, std::move(slotMethod_Bento), type, senderListHandle);
338 template<
class Sender,
class SignalClass,
class ...SignalArgs,
class Receiver,
class T>
339 bool connect(
const Sender &sender,
void (SignalClass::*signalMethod)(SignalArgs...),
const Receiver &receiver,
340 T slotLambda, ConnectionKind type,
bool uniqueConnection)
343 Internal::cs_testConnect_SenderSignal<Sender, SignalClass>();
346 Internal::cs_testConnect_SignalSlotArgs_1<T, SignalArgs...>();
348 if (signalMethod ==
nullptr) {
349 throw std::invalid_argument(
"connect(): Can not connect, signal is null");
352 std::unique_ptr<Internal::Bento<
void (SignalClass::*)(SignalArgs...)>>
353 signalMethod_Bento(
new Internal::Bento<
void (SignalClass::*)(SignalArgs...)>(signalMethod));
355 std::unique_ptr<Internal::Bento<T>> slotLambda_Bento(
new Internal::Bento<T>(slotLambda));
357 auto senderListHandle = sender.m_connectList.lock_write();
359 if (uniqueConnection) {
362 for (
auto &item : *senderListHandle) {
364 if (item.receiver != &receiver) {
368 if (*(item.signalMethod) != *(signalMethod_Bento)) {
379 sender.addConnection(std::move(signalMethod_Bento), &receiver, std::move(slotLambda_Bento), type, senderListHandle);
386 template<
class Sender,
class Receiver>
387 bool connect(
const Sender &sender, std::unique_ptr<Internal::BentoAbstract> signalMethod_Bento,
const Receiver &receiver,
388 std::unique_ptr<Internal::BentoAbstract> slotMethod_Bento, ConnectionKind type,
bool uniqueConnection)
390 auto senderListHandle = sender.m_connectList.lock_write();
392 if (uniqueConnection) {
395 for (
const auto &item : *senderListHandle) {
397 if (item.receiver != &receiver) {
401 if (*(item.signalMethod) != *(signalMethod_Bento)) {
405 if (*(item.slotMethod) != *(slotMethod_Bento)) {
414 sender.addConnection(std::move(signalMethod_Bento), &receiver, std::move(slotMethod_Bento), type, senderListHandle);
420 template<
class Sender,
class SignalClass,
class ...SignalArgs,
class Receiver,
class SlotClass,
class ...SlotArgs,
class SlotReturn>
421 bool disconnect(
const Sender &sender,
void (SignalClass::*signalMethod)(SignalArgs...),
const Receiver &receiver,
422 SlotReturn (SlotClass::*slotMethod)(SlotArgs...))
425 Internal::cs_testConnect_SenderSignal<Sender, SignalClass>();
428 Internal::cs_testConnect_ReceiverSlot<SlotClass, Receiver>();
431 Internal::cs_testConnect_SignalSlotArgs_2<
void (*)(SignalArgs...),
void (*)(SlotArgs...) >();
433 Internal::Bento<
void (SignalClass::*)(SignalArgs...)> signalMethod_Bento(signalMethod);
434 Internal::Bento<SlotReturn (SlotClass::*)(SlotArgs...)> slotMethod_Bento(slotMethod);
436 if (! internal_disconnect(sender, &signalMethod_Bento, &receiver, &slotMethod_Bento)) {
444 template<
class Sender,
class SignalClass,
class ...SignalArgs,
class Receiver,
class T>
445 bool disconnect(
const Sender &sender,
void (SignalClass::*signalMethod)(SignalArgs...),
const Receiver &receiver, T slotMethod)
448 static_assert(std::is_convertible<
decltype(slotMethod == slotMethod),
bool>::value,
449 "disconnect(): Slot argument invalid or calling disconnect using a lambda" );
452 Internal::Bento<
void (SignalClass::*)(SignalArgs...)> signalMethod_Bento(signalMethod);
453 Internal::Bento<T> slotMethod_Bento(slotMethod);
455 if (! internal_disconnect(sender, &signalMethod_Bento, &receiver, &slotMethod_Bento)) {
463 template<
class Sender,
class Receiver>
464 bool internal_disconnect(
const Sender &sender,
const Internal::BentoAbstract *signalBento,
465 const Receiver *receiver,
const Internal::BentoAbstract *slotBento)
468 auto senderListHandle = sender.m_connectList.lock_write();
470 for (
auto iter = senderListHandle->begin(); iter != senderListHandle->end(); ++iter) {
471 const SignalBase::ConnectStruct &temp = *iter;
473 bool isMatch =
false;
475 if (signalBento ==
nullptr && receiver ==
nullptr) {
479 }
else if (receiver !=
nullptr) {
481 if (receiver == temp.receiver) {
483 if (signalBento ==
nullptr && (slotBento ==
nullptr || *slotBento == *temp.slotMethod)) {
486 }
else if (signalBento !=
nullptr && *signalBento == *temp.signalMethod && (slotBento ==
nullptr ||
487 *slotBento == *temp.slotMethod)) {
492 }
else if (signalBento !=
nullptr) {
495 if (*signalBento == *temp.signalMethod) {
505 auto receiverListHandle = temp.receiver->m_possibleSenders.lock_write();
506 receiverListHandle->erase(find(receiverListHandle->begin(), receiverListHandle->end(), &sender));
509 senderListHandle->erase(iter);
521 template<
class... Args>
522 class cs_mp_cast_internal
525 template<
class className>
526 constexpr auto operator()(
void (className::*methodPtr)(Args ...))
const {
531 template<
class... Args>
532 constexpr cs_mp_cast_internal<Args...> cs_mp_cast;
536 template<
class... Args>
537 class cs_cmp_cast_internal
540 template<
class className>
541 constexpr auto operator()(
void (className::*methodPtr)(Args ...)
const)
const {
546 template<
class... Args>
547 constexpr cs_cmp_cast_internal<Args...> cs_cmp_cast;
#define LIB_SIG_EXPORT
Definition: cs_macro.h:28