qxLib
observer.inl
Go to the documentation of this file.
1 /**
2 
3  @file observer.inl
4  @author Khrapov
5  @date 6.03.2021
6  @copyright © Nick Khrapov, 2021. All right reserved.
7 
8 **/
9 
10 namespace qx
11 {
12 
13 // -------------------------- qx::observer_token_data --------------------------
14 
15 inline observer_token_data::observer_token_data(base_subject* pSubject, void* pObserver) noexcept
16  : m_pSubject(pSubject)
17  , m_pObserver(pObserver)
18 {
19 }
20 
21 inline void observer_token_data::reset() noexcept
22 {
23  if (m_pSubject && m_pObserver)
24  m_pSubject->detach(m_pObserver);
25 
26  m_pSubject = nullptr;
27  m_pObserver = nullptr;
28 }
29 
30 inline observer_token_data::observer_token_data(observer_token_data&& other) noexcept
31 {
32  std::swap(m_pSubject, other.m_pSubject);
33  std::swap(m_pObserver, other.m_pObserver);
34 }
35 
36 inline observer_token_data& observer_token_data::operator=(observer_token_data&& other) noexcept
37 {
38  std::swap(m_pSubject, other.m_pSubject);
39  std::swap(m_pObserver, other.m_pObserver);
40  return *this;
41 }
42 
43 inline observer_token_data::~observer_token_data() noexcept
44 {
45  reset();
46 }
47 
48 inline bool observer_token_data::operator==(const observer_token_data& other) const noexcept
49 {
50  return m_pSubject == other.m_pSubject && m_pObserver == other.m_pObserver;
51 }
52 
53 inline observer_token_data::operator bool() const noexcept
54 {
55  return m_pSubject && m_pObserver;
56 }
57 
58 
59 
60 // --------------------------- subject::base_iterator --------------------------
61 
62 template<class observer_t>
63 template<class base_iterator_t>
65  const base_iterator_t& other,
66  subject* pSubject) noexcept
67  : base_iterator_t(other)
68  , m_pSubject(pSubject)
69 {
70  init();
71 }
72 
73 template<class observer_t>
74 template<class base_iterator_t>
75 inline subject<observer_t>::base_iterator<base_iterator_t>::base_iterator(const base_iterator& other) noexcept
76  : base_iterator_t(other)
77  , m_pSubject(other.m_pSubject)
78 {
79  init();
80 }
81 
82 template<class observer_t>
83 template<class base_iterator_t>
84 inline subject<observer_t>::base_iterator<base_iterator_t>::~base_iterator() noexcept
85 {
86  m_pSubject->on_iterator_destructed();
87 }
88 
89 template<class observer_t>
90 template<class base_iterator_t>
91 inline typename subject<observer_t>::template base_iterator<base_iterator_t>& subject<observer_t>::base_iterator<
92  base_iterator_t>::operator=(const base_iterator& other) noexcept
93 {
94  *this = std::move(base_iterator(other));
95  return *this;
96 }
97 
98 template<class observer_t>
99 template<class base_iterator_t>
100 inline observer_t* subject<observer_t>::base_iterator<base_iterator_t>::operator->(void) noexcept
101 {
102  return static_cast<observer_t*>(*base_iterator_t::operator->());
103 }
104 
105 template<class observer_t>
106 template<class base_iterator_t>
107 inline observer_t& subject<observer_t>::base_iterator<base_iterator_t>::operator*(void) noexcept
108 {
109  return static_cast<observer_t&>(*base_iterator_t::operator*());
110 }
111 
112 template<class observer_t>
113 template<class base_iterator_t>
114 inline void subject<observer_t>::base_iterator<base_iterator_t>::init() noexcept
115 {
116  m_pSubject->on_iterator_constructed();
117 }
118 
119 
120 
121 // ------------------------ subject::const_base_iterator -----------------------
122 
123 template<class observer_t>
124 template<class base_iterator_t>
125 inline subject<observer_t>::const_base_iterator<base_iterator_t>::const_base_iterator(
126  const base_iterator_t& other) noexcept
127  : base_iterator_t(other)
128 {
129 }
130 
131 template<class observer_t>
132 template<class base_iterator_t>
133 const observer_t* subject<observer_t>::const_base_iterator<base_iterator_t>::operator->() const noexcept
134 {
135  return static_cast<const observer_t*>(*base_iterator_t::operator->());
136 }
137 
138 template<class observer_t>
139 template<class base_iterator_t>
140 const observer_t& subject<observer_t>::const_base_iterator<base_iterator_t>::operator*() const noexcept
141 {
142  return static_cast<const observer_t&>(*base_iterator_t::operator*());
143 }
144 
145 
146 
147 // ---------------------------------- subject ----------------------------------
148 
149 template<class observer_t>
150 inline subject<observer_t>::~subject()
151 {
152  // temp vector because reset will erase elements from m_Tokens
153  const auto tokens = m_Tokens;
154  for (const auto pToken : tokens)
155  pToken->reset();
156 }
157 
158 template<class observer_t>
159 inline observer_token subject<observer_t>::attach(observer_t* pObserver) noexcept
160 {
161  if (std::find(m_Observers.begin(), m_Observers.end(), pObserver) == m_Observers.end())
162  {
163  m_Observers.push_back(pObserver);
164  auto token = std::make_unique<observer_token_data>(this, pObserver);
165  m_Tokens.push_back(token.get());
166  return token;
167  }
168  else
169  {
170  return observer_token();
171  }
172 }
173 
174 template<class observer_t>
175 inline void subject<observer_t>::notify(const notify_func& notifyFunc) const noexcept
176 {
177  for (auto pObserver : m_Observers)
178  notifyFunc(pObserver);
179 }
180 
181 template<class observer_t>
182 inline typename subject<observer_t>::iterator subject<observer_t>::begin()
183 {
184  return iterator(m_Observers.begin(), this);
185 }
186 
187 template<class observer_t>
188 inline typename subject<observer_t>::const_iterator subject<observer_t>::begin(void) const
189 {
190  return const_iterator(m_Observers.cbegin());
191 }
192 
193 template<class observer_t>
194 inline typename subject<observer_t>::const_iterator subject<observer_t>::cbegin(void) const
195 {
196  return const_iterator(m_Observers.cbegin());
197 }
198 
199 template<class observer_t>
200 inline typename subject<observer_t>::iterator subject<observer_t>::end()
201 {
202  return iterator(m_Observers.end(), this);
203 }
204 
205 template<class observer_t>
206 inline typename subject<observer_t>::const_iterator subject<observer_t>::end(void) const
207 {
208  return const_iterator(m_Observers.cend());
209 }
210 
211 template<class observer_t>
212 inline typename subject<observer_t>::const_iterator subject<observer_t>::cend(void) const
213 {
214  return const_iterator(m_Observers.cend());
215 }
216 
217 template<class observer_t>
218 inline typename subject<observer_t>::reverse_iterator subject<observer_t>::rbegin(void)
219 {
220  return reverse_iterator(m_Observers.rbegin(), this);
221 }
222 
223 template<class observer_t>
224 inline typename subject<observer_t>::const_reverse_iterator subject<observer_t>::rbegin() const
225 {
226  return const_reverse_iterator(m_Observers.crbegin());
227 }
228 
229 template<class observer_t>
230 inline typename subject<observer_t>::const_reverse_iterator subject<observer_t>::crbegin() const
231 {
232  return const_reverse_iterator(m_Observers.crbegin());
233 }
234 
235 template<class observer_t>
236 inline typename subject<observer_t>::reverse_iterator subject<observer_t>::rend(void)
237 {
238  return reverse_iterator(m_Observers.rend(), this);
239 }
240 
241 template<class observer_t>
242 inline typename subject<observer_t>::const_reverse_iterator subject<observer_t>::rend() const
243 {
244  return const_reverse_iterator(m_Observers.crend());
245 }
246 
247 template<class observer_t>
248 inline typename subject<observer_t>::const_reverse_iterator subject<observer_t>::crend() const
249 {
250  return const_reverse_iterator(m_Observers.crend());
251 }
252 
253 template<class observer_t>
254 inline size_t subject<observer_t>::get_num_observers() const noexcept
255 {
256  return m_Observers.size();
257 }
258 
259 template<class observer_t>
260 inline void subject<observer_t>::detach(void* pObserver) noexcept
261 {
262  if (m_nIterators == 0)
263  {
264  std::erase_if(
265  m_Tokens,
266  [pObserver](const observer_token_data* pToken)
267  {
268  return pToken->m_pObserver == pObserver;
269  });
270 
271  m_Observers.erase(std::remove(m_Observers.begin(), m_Observers.end(), pObserver), m_Observers.end());
272  }
273  else
274  {
275  std::replace_if(
276  m_Tokens.begin(),
277  m_Tokens.end(),
278  [pObserver](const observer_token_data* pToken)
279  {
280  return pToken && pToken->m_pObserver == pObserver;
281  },
282  static_cast<observer_token_data*>(nullptr));
283 
284  std::replace(
285  m_Observers.begin(),
286  m_Observers.end(),
287  static_cast<observer_t*>(pObserver),
288  static_cast<observer_t*>(nullptr));
289  }
290 }
291 
292 template<class observer_t>
293 inline void subject<observer_t>::on_iterator_destructed() noexcept
294 {
295  m_nIterators--;
296  if (m_nIterators == 0)
297  {
298  m_Tokens.erase(std::remove(m_Tokens.begin(), m_Tokens.end(), nullptr), m_Tokens.end());
299 
300  m_Observers.erase(std::remove(m_Observers.begin(), m_Observers.end(), nullptr), m_Observers.end());
301  }
302 }
303 
304 template<class observer_t>
305 inline void subject<observer_t>::on_iterator_constructed() noexcept
306 {
307  m_nIterators++;
308 }
309 
310 } // namespace qx
Base subject class.
Definition: observer.h:94
virtual void detach(void *pObserver) noexcept=0
Detach observer from subject.
Const random access iterator type.
Definition: iterator.h:74
Const reverse random access iterator type.
Definition: iterator.h:159
Tokens are used to automatically detach observer when the observer object is destroyed.
Definition: observer.h:37
void reset() noexcept
Reset observer_token.
Definition: observer.inl:21
Class maintains a list of its dependents, called observers, and notifies them automatically of any st...
Definition: observer.h:120
const_iterator cbegin() const
Return const iterator to beginning.
Definition: observer.inl:194
iterator begin()
Return iterator to beginning.
Definition: observer.inl:182
const_iterator cend() const
Return const iterator to end.
Definition: observer.inl:212
observer_token attach(observer_t *pObserver) noexcept
Attach observer to this subject.
Definition: observer.inl:159
iterator end()
Return iterator to end.
Definition: observer.inl:200
reverse_iterator rbegin()
Return reverse iterator to reverse beginning.
Definition: observer.inl:218
size_t get_num_observers() const noexcept
Get number of observers attached to this subject.
Definition: observer.inl:254
void notify(const notify_func &notifyFunc) const noexcept
Notify all observers.
Definition: observer.inl:175
const_reverse_iterator crend() const
Return const reverse iterator to reverse end.
Definition: observer.inl:248
reverse_iterator rend()
Return reverse iterator to reverse end.
Definition: observer.inl:236
const_reverse_iterator crbegin() const
Return const reverse iterator to reverse beginning.
Definition: observer.inl:230