Ring Daemon 16.0.0
Loading...
Searching...
No Matches
observer.h
Go to the documentation of this file.
1/*
2 * Copyright (C) 2004-2025 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 <cstdint>
23#include <memory>
24#include <set>
25#include <list>
26#include <mutex>
27#include <functional>
28#include <ciso646> // fix windows compiler bug
29#ifndef __DEBUG__ // this is only defined on plugins build for debugging
30#include "logger.h"
31#endif
32
33namespace jami {
34
35template<typename T>
36class Observer;
37template<typename T>
38class Observable;
39
40/*=== Observable =============================================================*/
41
42template<typename T>
44{
45public:
47 : mutex_()
48 , observers_()
49 {}
50
56 virtual ~Observable()
57 {
58 std::lock_guard lk(mutex_);
59
60 for (auto& pobs : priority_observers_) {
61 if (auto so = pobs.lock()) {
62 so->detached(this);
63 }
64 }
65
66 for (auto& o : observers_)
67 o->detached(this);
68 }
69
71 {
72 std::lock_guard lk(mutex_);
73 if (o and observers_.insert(o).second) {
74 o->attached(this);
75 return true;
76 }
77 return false;
78 }
79
80 void attachPriorityObserver(std::shared_ptr<Observer<T>> o)
81 {
82 std::lock_guard lk(mutex_);
83 priority_observers_.push_back(o);
84 o->attached(this);
85 }
86
88 {
89 std::lock_guard lk(mutex_);
90 for (auto it = priority_observers_.begin(); it != priority_observers_.end(); it++) {
91 if (auto so = it->lock()) {
92 if (so.get() == o) {
93 so->detached(this);
95 return;
96 }
97 }
98 }
99 }
100
102 {
103 std::lock_guard lk(mutex_);
104 if (o and observers_.erase(o)) {
105 o->detached(this);
106 return true;
107 }
108 return false;
109 }
110
112 {
113 std::lock_guard lk(mutex_);
114 return observers_.size() + priority_observers_.size();
115 }
116
117protected:
118 void notify(T data)
119 {
120 std::lock_guard lk(mutex_);
121 for (auto it = priority_observers_.begin(); it != priority_observers_.end();) {
122 if (auto so = it->lock()) {
123 it++;
124 try {
125 so->update(this, data);
126 } catch (std::exception& e) {
127#ifndef __DEBUG__
128 JAMI_ERR() << e.what();
129#endif
130 }
131 } else {
132 it = priority_observers_.erase(it);
133 }
134 }
135
136 for (auto observer : observers_) {
137 observer->update(this, data);
138 }
139 }
140
141private:
143
144protected:
145 std::mutex mutex_; // lock observers_
146 std::list<std::weak_ptr<Observer<T>>> priority_observers_;
147 std::set<Observer<T>*> observers_;
148};
149
150template<typename T>
152{
153public:
154 void publish(T data) { this->notify(data); }
155};
156
157/*=== Observer =============================================================*/
158
159template<typename T>
161{
162public:
163 virtual ~Observer() {}
164 virtual void update(Observable<T>*, const T&) = 0;
165 virtual void attached(Observable<T>*) {}
166 virtual void detached(Observable<T>*) {}
167};
168
169template<typename T>
170class FuncObserver : public Observer<T>
171{
172public:
173 using F = std::function<void(const T&)>;
175 : f_(f)
176 {}
177 virtual ~FuncObserver() {}
178 void update(Observable<T>*, const T& t) override { f_(t); }
179
180private:
181 F f_;
182};
183
184/*=== PublishMapSubject ====================================================*/
185
186template<typename T1, typename T2>
187class PublishMapSubject : public Observer<T1>, public Observable<T2>
188{
189public:
190 using F = std::function<T2(const T1&)>;
191
193 : map_ {f}
194 {}
195
196 void update(Observable<T1>*, const T1& t) override { this->notify(map_(t)); }
197
204 virtual void attached(Observable<T1>* srcObs) override
205 {
206 if (obs_ != nullptr && obs_ != srcObs) {
207 obs_->detach(this);
208 obs_ = srcObs;
209 }
210 }
211
217 virtual void detached(Observable<T1>*) override
218 {
219 std::lock_guard lk(this->mutex_);
220 for (auto& pobs : this->priority_observers_) {
221 if (auto so = pobs.lock()) {
222 so->detached(this);
223 }
224 }
225 for (auto& o : this->observers_)
226 o->detached(this);
227 }
228
235
236private:
237 F map_;
238 Observable<T1>* obs_ = nullptr;
239};
240
241}; // namespace jami
std::function< void(const T &)> F
Definition observer.h:173
void update(Observable< T > *, const T &t) override
Definition observer.h:178
virtual ~FuncObserver()
Definition observer.h:177
std::mutex mutex_
Definition observer.h:145
std::list< std::weak_ptr< Observer< T > > > priority_observers_
Definition observer.h:146
bool attach(Observer< T > *o)
Definition observer.h:70
void detachPriorityObserver(Observer< T > *o)
Definition observer.h:87
bool detach(Observer< T > *o)
Definition observer.h:101
virtual ~Observable()
~Observable Detach all observers to avoid making them call this observable when destroyed
Definition observer.h:56
std::set< Observer< T > * > observers_
Definition observer.h:147
size_t getObserversCount()
Definition observer.h:111
void notify(T data)
Definition observer.h:118
void attachPriorityObserver(std::shared_ptr< Observer< T > > o)
Definition observer.h:80
virtual void attached(Observable< T > *)
Definition observer.h:165
virtual void update(Observable< T > *, const T &)=0
virtual ~Observer()
Definition observer.h:163
virtual void detached(Observable< T > *)
Definition observer.h:166
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:217
~PublishMapSubject()
~PublishMapSubject() Detach all observers to avoid making them call this observable when destroyed
Definition observer.h:234
void update(Observable< T1 > *, const T1 &t) override
Definition observer.h:196
std::function< T2(const T1 &)> F
Definition observer.h:190
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:204
void publish(T data)
Definition observer.h:154
#define JAMI_ERR(...)
Definition logger.h:218
void emitSignal(Args... args)
Definition ring_signal.h:64
Simple macro to hide class' copy constructor and assignment operator.
#define NON_COPYABLE(ClassName)
Definition noncopyable.h:30