forked from NoAvailableAlias/nano-signal-slot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnano_observer.hpp
133 lines (107 loc) · 3.17 KB
/
nano_observer.hpp
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
#ifndef NANO_OBSERVER_HPP
#define NANO_OBSERVER_HPP
#include "nano_function.hpp"
namespace Nano
{
class Observer
{
template <typename T> friend class Signal;
struct DelegateKeyObserver { DelegateKey delegate; Observer* observer; };
struct Node {
DelegateKeyObserver data;
struct Node* next;
};
Node* head = nullptr;
Node* last = nullptr;
//-----------------------------------------------------------PRIVATE METHODS
void insert(DelegateKey const& key, Observer* obs)
{
Node* newNode = new Node{{key, obs}, nullptr};
if(last) {
last->next = newNode;
}
else {
head = newNode;
}
last = newNode;
}
void remove(DelegateKey const& key, Observer* obs)
{
Node* node = head;
Node* prev = nullptr;
// Only delete the first occurrence
for ( ; node; prev = node, node = node->next)
{
if (node->data.delegate == key && node->data.observer == obs)
{
if (prev)
{
prev->next = node->next;
}
else
{
head = head->next;
}
if(node == last) {
last = prev;
}
delete node;
break;
}
}
}
void removeAll()
{
for (auto node = head; node;)
{
auto temp = node;
// If this is us we only need to delete
if (this != node->data.observer)
{
// Remove this slot from this listening Observer
node->data.observer->remove(node->data.delegate, this);
}
node = node->next;
delete temp;
}
head = nullptr;
last = nullptr;
}
bool isEmpty() const
{
return head == nullptr;
}
template <typename Delegate, typename... Uref>
void onEach(Uref&&... args)
{
for (auto node = head, next = head; node; node = next)
{
next = node->next;
// Perfect forward and emit
Delegate(node->data.delegate)(std::forward<Uref>(args)...);
}
}
template <typename Delegate, typename Accumulate, typename... Uref>
void onEach_Accumulate(Accumulate&& accumulate, Uref&&... args)
{
for (auto node = head, next = head; node; node = next)
{
next = node->next;
// Perfect forward, emit, and accumulate the return value
accumulate(Delegate(node->data.delegate)(std::forward<Uref>(args)...));
}
}
//-----------------------------------------------------------------PROTECTED
protected:
~Observer()
{
removeAll();
}
//--------------------------------------------------------------------PUBLIC
public:
Observer() = default;
Observer(const Observer& other) = delete; // non construction-copyable
Observer& operator=(const Observer&) = delete; // non copyable
};
} // namespace Nano ------------------------------------------------------------
#endif // NANO_OBSERVER_HPP