14 #ifndef TRANSACTION_SIGNAL_H
15 #define TRANSACTION_SIGNAL_H
17 #include "transaction.h"
22 namespace Transactional {
26 template <
class Func,
class R,
typename TPL,
typename... Args>
28 CallByTuple<N - 1>(f, r, t, std::get<N - 1>(t), args...);
33 template <
class Func,
class R,
typename TPL,
typename... Args>
35 (r.*f)(std::forward<Args>(args)...);
39 template <
typename...Args>
41 explicit Event(std::tuple<Args...>&& tpl) noexcept : tuple(std::move(tpl)) {}
46 std::tuple<Args...> tuple;
48 template <
class Func,
class T>
49 void operator()(Func f, T &t)
const {
54 template <
class Event>
59 virtual void operator() (
const Event&)
const = 0;
61 template <
class SS,
typename...Args>
66 template<
class Event,
class R,
class Func>
68 ListenerRef(R &obj, Func f, XListener::FLAGS flags) noexcept :
70 virtual void operator() (
const Event& e)
const override {
77 template<
class Event,
class R,
class Func>
79 ListenerWeak(
const shared_ptr<R> &obj, Func f, XListener::FLAGS flags) noexcept :
81 virtual void operator() (
const Event& e)
const override {
82 if(
auto p = m_obj.lock() ) {
88 const weak_ptr<R> m_obj;
94 virtual void talk(
const SS &shot) = 0;
95 virtual int unmark(
const shared_ptr<XListener> &x) = 0;
101 template <
class SS,
typename...Args>
104 virtual ~
Talker() =
default;
106 template <
class R,
class T,
typename...ArgRefs>
107 shared_ptr<XListener> connect(R& obj,
void(T::*func)(ArgRefs...),
int flags = 0);
108 template <
class R,
class T,
typename...ArgRefs>
109 shared_ptr<XListener> connectWeakly(
const shared_ptr<R> &obj,
110 void (T::*func)(ArgRefs...),
int flags = 0);
112 void connect(
const shared_ptr<XListener> &x);
113 void disconnect(
const shared_ptr<XListener> &);
120 template <
typename...ArgRefs>
121 shared_ptr<Message> createMessage(int64_t tr_serial, ArgRefs&&... arg)
const;
122 template <
typename...ArgRefs>
123 void talk(
const SS &shot, ArgRefs&&...args)
const {
124 Message m(m_listeners, std::forward<ArgRefs>(args)...);
128 bool empty()
const noexcept {
return !m_listeners;}
132 typedef std::vector<weak_ptr<Listener_> > ListenerList;
134 shared_ptr<ListenerList> m_listeners;
136 void connect(
const shared_ptr<Listener_> &);
142 const shared_ptr<Listener_> listener;
143 virtual bool talkBuffered() = 0;
149 virtual bool talkBuffered()
override {
150 ( *this->listener)(std::move(event));
156 virtual bool talkBuffered()
override {
158 if(this->listener->delay_ms()) {
159 long elapsed_ms = XTime::now().diff_msec(this->registered_time);
160 skip = ((long)this->listener->delay_ms() > elapsed_ms);
164 e.
swap(this->listener->event);
166 ( *this->listener)( std::move(*e));
173 template <
class...ArgRefs>
174 Message(
const shared_ptr<ListenerList> &l, ArgRefs&&...as) noexcept :
175 Message_<SS>(), listeners(l), args(std::forward<Args>(as)...) {}
176 shared_ptr<ListenerList> listeners;
177 std::tuple<Args...> args;
178 shared_ptr<UnmarkedListenerList> listeners_unmarked;
179 virtual void talk(
const SS &shot)
override;
180 virtual int unmark(
const shared_ptr<XListener> &x)
override {
184 for(
auto &&y: *listeners) {
185 if(
auto listener = y.lock()) {
187 if( !listeners_unmarked)
189 listeners_unmarked->push_back(x);
199 template <
class SS,
typename...Args>
204 template <
typename...ArgRefs>
205 shared_ptr<typename TalkerSingleton::Message> createMessage(int64_t tr_serial, ArgRefs&&...args)
const {
206 if(m_transaction_serial == tr_serial) {
207 if(
auto m = m_marked.lock()) {
208 m->args = std::make_tuple(std::forward<ArgRefs>(args)...);
213 m_transaction_serial = tr_serial;
218 mutable weak_ptr<
typename Talker<SS, Args...>::Message> m_marked;
219 mutable int64_t m_transaction_serial;
222 template <
class SS,
typename...Args>
223 template <
typename...ArgRefs>
227 return std::make_shared<Message>(m_listeners, std::forward<ArgRefs>(args)...);
230 template <
class SS,
typename...Args>
231 template <
class R,
class T,
typename...ArgRefs>
232 shared_ptr<XListener>
234 shared_ptr<Listener_> listener =
235 std::make_shared<ListenerRef<
Talker<SS, Args...>::Event_, T, decltype(func)>>(
236 static_cast<T&
>(obj), func, (XListener::FLAGS)flags);
241 template <
class SS,
typename...Args>
242 template <
class R,
class T,
typename...ArgRefs>
243 shared_ptr<XListener>
245 void(T::*func)(ArgRefs...),
int flags) {
246 shared_ptr<Listener_> listener =
247 std::make_shared<ListenerWeak<
Talker<SS, Args...>::Event_, T, decltype(func)>>(
248 static_pointer_cast<T>(obj), func, (XListener::FLAGS)flags);
252 template <class SS, typename...Args>
255 auto listener = dynamic_pointer_cast<Listener_>(lx);
258 template <
class SS,
typename...Args>
261 auto new_list = m_listeners ? std::make_shared<ListenerList>( *m_listeners) : std::make_shared<ListenerList>();
263 for(
auto it = new_list->begin(); it != new_list->end();) {
265 it = new_list->erase(it);
269 new_list->push_back(lx);
270 new_list->shrink_to_fit();
271 m_listeners = new_list;
273 template <
class SS,
typename...Args>
276 auto new_list = m_listeners ? std::make_shared<ListenerList>( *m_listeners) : std::make_shared<ListenerList>();
277 for(
auto it = new_list->begin(); it != new_list->end();) {
278 if(
auto listener = it->lock()) {
280 if( !listener || (lx == listener)) {
281 it = new_list->erase(it);
287 if(new_list->empty())
290 new_list->shrink_to_fit();
291 m_listeners = new_list;
294 template <
class SS,
typename...Args>
297 if( !listeners)
return;
298 Event_ event(std::tuple_cat(std::tie(shot), std::move(args)));
300 for(
auto &&x: *listeners) {
301 if(
auto listener = x.lock()) {
302 if(listeners_unmarked &&
303 (std::find(listeners_unmarked->begin(), listeners_unmarked->end(), listener) != listeners_unmarked->end()))
305 if(listener->flags() & XListener::FLAG_MAIN_THREAD_CALL) {
306 if(listener->flags() & XListener::FLAG_AVOID_DUP) {
308 newevent.swap(listener->event);
310 registerTransactionList(
new EventWrapperAvoidDup(listener));
322 registerTransactionList(
new EventWrapperAllowDup(listener, event));
329 for(
auto &&x: *listeners) {
330 if(
auto listener = x.lock()) {
331 if(listeners_unmarked &&
332 (std::find(listeners_unmarked->begin(), listeners_unmarked->end(), listener) != listeners_unmarked->end()))
334 if( !(listener->flags() & XListener::FLAG_MAIN_THREAD_CALL)) {