Ring Daemon
Loading...
Searching...
No Matches
observer.h
Go to the documentation of this file.
1/*
2 * Copyright (C) 2004-2026 Savoir-faire Linux Inc.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17#pragma once
18
19#include "noncopyable.h"
20
21#include <cstdlib>
22#include <memory>
23#include <set>
24#include <list>
25#include <mutex>
26#include <functional>
27
28#ifndef __DEBUG__ // this is only defined on plugins build for debugging
29#include "logger.h"
30#endif
31
32namespace jami {
33
34template<typename T>
35class Observer;
36template<typename T>
37class Observable;
38
39/*=== Observable =============================================================*/
40
41template<typename T>
43{
44public:
46 : mutex_()
47 , observers_()
48 {}
49
55 virtual ~Observable()
56 {
57 std::lock_guard lk(mutex_);
58
59 for (auto& pobs : priority_observers_) {
60 if (auto so = pobs.lock()) {
61 so->detached(this);
62 }
63 }
64
65 for (auto& o : observers_)
66 o->detached(this);
67 }
68
70 {
71 std::lock_guard lk(mutex_);
72 if (o and observers_.insert(o).second) {
73 o->attached(this);
74 return true;
75 }
76 return false;
77 }
78
79 void attachPriorityObserver(std::shared_ptr<Observer<T>> o)
80 {
81 std::lock_guard lk(mutex_);
82 priority_observers_.push_back(o);
83 o->attached(this);
84 }
85
87 {
88 std::lock_guard lk(mutex_);
89 for (auto it = priority_observers_.begin(); it != priority_observers_.end(); it++) {
90 if (auto so = it->lock()) {
91 if (so.get() == o) {
92 so->detached(this);
94 return;
95 }
96 }
97 }
98 }
99
101 {
102 std::lock_guard lk(mutex_);
103 if (o and observers_.erase(o)) {
104 o->detached(this);
105 return true;
106 }
107 return false;
108 }
109
111 {
112 std::lock_guard lk(mutex_);
113 return observers_.size() + priority_observers_.size();
114 }
115
116protected:
117 void notify(T data)
118 {
119 std::lock_guard lk(mutex_);
120 for (auto it = priority_observers_.begin(); it != priority_observers_.end();) {
121 if (auto so = it->lock()) {
122 it++;
123 try {
124 so->update(this, data);
125 } catch (std::exception& e) {
126#ifndef __DEBUG__
127 JAMI_ERR() << e.what();
128#endif
129 }
130 } else {
131 it = priority_observers_.erase(it);
132 }
133 }
134
135 for (auto observer : observers_) {
136 observer->update(this, data);
137 }
138 }
139
140private:
142
143protected:
144 std::mutex mutex_; // lock observers_
145 std::list<std::weak_ptr<Observer<T>>> priority_observers_;
146 std::set<Observer<T>*> observers_;
147};
148
149template<typename T>
151{
152public:
153 void publish(T data) { this->notify(data); }
154};
155
156/*=== Observer =============================================================*/
157
158template<typename T>
160{
161public:
162 virtual ~Observer() {}
163 virtual void update(Observable<T>*, const T&) = 0;
164 virtual void attached(Observable<T>*) {}
165 virtual void detached(Observable<T>*) {}
166};
167
168template<typename T>
169class FuncObserver : public Observer<T>
170{
171public:
172 using F = std::function<void(const T&)>;
174 : f_(f)
175 {}
176 virtual ~FuncObserver() {}
177 void update(Observable<T>*, const T& t) override { f_(t); }
178
179private:
180 F f_;
181};
182
183/*=== PublishMapSubject ====================================================*/
184
185template<typename T1, typename T2>
186class PublishMapSubject : public Observer<T1>, public Observable<T2>
187{
188public:
189 using F = std::function<T2(const T1&)>;
190
192 : map_ {f}
193 {}
194
195 void update(Observable<T1>*, const T1& t) override { this->notify(map_(t)); }
196
203 virtual void attached(Observable<T1>* srcObs) override
204 {
205 if (obs_ != nullptr && obs_ != srcObs) {
206 obs_->detach(this);
207 obs_ = srcObs;
208 }
209 }
210
216 virtual void detached(Observable<T1>*) override
217 {
218 std::lock_guard lk(this->mutex_);
219 for (auto& pobs : this->priority_observers_) {
220 if (auto so = pobs.lock()) {
221 so->detached(this);
222 }
223 }
224 for (auto& o : this->observers_)
225 o->detached(this);
226 }
227
234
235private:
236 F map_;
237 Observable<T1>* obs_ = nullptr;
238};
239
240}; // namespace jami
std::function< void(const T &)> F
Definition observer.h:172
void update(Observable< T > *, const T &t) override
Definition observer.h:177
virtual ~FuncObserver()
Definition observer.h:176
std::mutex mutex_
Definition observer.h:144
std::list< std::weak_ptr< Observer< T > > > priority_observers_
Definition observer.h:145
bool attach(Observer< T > *o)
Definition observer.h:69
void detachPriorityObserver(Observer< T > *o)
Definition observer.h:86
bool detach(Observer< T > *o)
Definition observer.h:100
virtual ~Observable()
~Observable Detach all observers to avoid making them call this observable when destroyed
Definition observer.h:55
std::set< Observer< T > * > observers_
Definition observer.h:146
size_t getObserversCount()
Definition observer.h:110
void notify(T data)
Definition observer.h:117
void attachPriorityObserver(std::shared_ptr< Observer< T > > o)
Definition observer.h:79
virtual void attached(Observable< T > *)
Definition observer.h:164
virtual void update(Observable< T > *, const T &)=0
virtual ~Observer()
Definition observer.h:162
virtual void detached(Observable< T > *)
Definition observer.h:165
virtual void detached(Observable< T1 > *) override
detached Since a MapSubject is only attached to one Observable, when detached We should detach all of...
Definition observer.h:216
~PublishMapSubject()
~PublishMapSubject() Detach all observers to avoid making them call this observable when destroyed
Definition observer.h:233
void update(Observable< T1 > *, const T1 &t) override
Definition observer.h:195
std::function< T2(const T1 &)> F
Definition observer.h:189
virtual void attached(Observable< T1 > *srcObs) override
attached Here we just make sure that the PublishMapSubject is only attached to one Observable at a ti...
Definition observer.h:203
void publish(T data)
Definition observer.h:153
#define JAMI_ERR(...)
Definition logger.h:230
void emitSignal(Args... args)
Definition jami_signal.h:64
Simple macro to hide class' copy constructor and assignment operator.
#define NON_COPYABLE(ClassName)
Definition noncopyable.h:30