-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathsignal_call.h
151 lines (129 loc) · 2.99 KB
/
signal_call.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/*********************************************************
File Name:signal_call.cpp
Author: Abby Cin
Mail: [email protected]
Created Time: Wed 11 May 2016 09:56:38 PM CST
**********************************************************/
#ifndef SIGNAL_CLASS_H_
#define SIGNAL_CLASS_H_
#include <list>
#include <utility>
#include <mutex>
namespace nm
{
namespace
{
struct thread_safe { };
struct non_thread_safe { };
struct member_function { };
struct non_member_function { };
template<typename T>
struct Trait;
// specialization
template<typename Obj, typename Res, typename... Args>
struct Trait<Res (Obj::*)(Args...)> {
typedef thread_safe safe_type;
typedef member_function func_type;
typedef Obj Object;
typedef Res (Obj::*Func)(Args...);
static void call(Func f, Obj *o, Args &&...args)
{
(o->*f)(std::forward<Args>(args)...);
}
};
// specialization
template<typename Res, typename... Args>
struct Trait<Res (*)(Args...)> {
typedef thread_safe safe_type;
typedef non_member_function func_type;
typedef Res (*Func)(Args...);
typedef Res Object;
static void call(Func f, Object *, Args &&...args)
{
(*f)(std::forward<Args>(args)...);
}
};
}
template<typename T>
using SafeTrait = Trait<T>;
// template<typename T> using UnSafeTrait = SomeTrait<T>;
template<typename T, template<typename> class Default = SafeTrait>
class Signal {
public:
using Handle = typename std::list<T>::iterator;
Signal()
{
obj = nullptr;
}
Signal(const Signal &) = delete;
Signal &operator=(const Signal &) = delete;
~Signal()
{
callable.clear();
obj = nullptr;
}
template<typename Func>
Handle connect(typename Trait<Func>::Object *recv, Func slot)
{
obj = recv;
callable.push_back(slot);
return --callable.end();
}
template<typename Func>
Handle connect(Func &&f)
{
callable.push_back(f);
return --callable.end();
}
void disconnect(Handle iter)
{
callable.erase(iter);
}
void disconnect(T fp)
{
for (auto iter = callable.begin(); iter != callable.end();) {
if (*iter == fp)
iter = callable.erase(iter);
else
++iter;
}
}
template<typename... Args>
void emit(Args &&...args)
{
this->exec(typename Default<T>::safe_type(),
std::forward<Args>(args)...);
}
private:
typename Default<T>::Object *obj;
std::list<T> callable;
std::mutex l;
template<typename... Args>
void do_exec(member_function, Args &&...args)
{
for (auto &x : callable)
Default<T>::call(x, obj, std::forward<Args>(args)...);
}
template<typename... Args>
void do_exec(non_member_function, Args &&...args)
{
for (auto &x : callable)
Default<T>::call(
x, nullptr, std::forward<Args>(args)...);
}
template<typename... Args>
void exec(thread_safe, Args &&...args)
{
std::lock_guard<std::mutex> lock(l);
do_exec(typename Default<T>::func_type(),
std::forward<Args>(args)...);
}
template<typename... Args>
void exec(non_thread_safe, Args &&...args)
{
do_exec(typename Default<T>::func_type(),
std::forward<Args>(args)...);
}
};
}
#endif