qxLib
observer.h
Go to the documentation of this file.
1 /**
2 
3  @file observer.h
4  @author Khrapov
5  @date 6.03.2021
6  @copyright © Nick Khrapov, 2021. All right reserved.
7 
8 **/
9 #pragma once
10 
12 
13 #include <algorithm>
14 #include <functional>
15 #include <memory>
16 #include <vector>
17 
18 namespace qx
19 {
20 
21 class base_subject;
22 
23 template<class observer_t>
24 class subject;
25 
26 /**
27 
28  @class observer_token_data
29  @brief Tokens are used to automatically detach observer when the observer
30  object is destroyed
31  @details ~
32  @author Khrapov
33  @date 10.03.2021
34 
35 **/
37 {
38  QX_NONCOPYABLE(observer_token_data);
39 
40  template<class>
41  friend class subject;
42 
43 public:
44  observer_token_data() noexcept = default;
45 
46  /**
47  @brief observer_token object constructor
48  @param pSubject - corresponding subject pointer
49  @param pObserver - corresponding observer pointer
50  **/
51  observer_token_data(base_subject* pSubject, void* pObserver) noexcept;
52 
53  /**
54  @brief observer_token object constructor
55  @param other - other observer_token object rvalue ref
56  **/
57  observer_token_data(observer_token_data&& other) noexcept;
58 
59  ~observer_token_data() noexcept;
60 
61  /**
62  @brief Reset observer_token
63  @details Token won't unsubscribe observer from subject in destructor
64  **/
65  void reset() noexcept;
66 
67  observer_token_data& operator=(observer_token_data&& other) noexcept;
68  bool operator==(const observer_token_data& other) const noexcept;
69 
70  /**
71  @brief operator bool
72  @retval - true if observer_token is valid
73  **/
74  operator bool() const noexcept;
75 
76 private:
77  base_subject* m_pSubject = nullptr;
78  void* m_pObserver = nullptr;
79 };
80 
81 using observer_token = std::unique_ptr<observer_token_data>;
82 
83 /**
84 
85  @class base_subject
86  @brief Base subject class
87  @details Allows to avoid template parameter for base logic
88  @details ~
89  @author Khrapov
90  @date 17.11.2021
91 
92 **/
94 {
95  friend observer_token_data;
96 
97 protected:
98  virtual ~base_subject() noexcept = default;
99 
100  /**
101  @brief Detach observer from subject
102  @param pObserver - observer pointer
103  **/
104  virtual void detach(void* pObserver) noexcept = 0;
105 };
106 
107 /**
108 
109  @class subject
110  @brief Class maintains a list of its dependents, called observers,
111  and notifies them automatically of any state changes
112  @details ~
113  @tparam observer_t - observer type
114  @author Khrapov
115  @date 6.03.2021
116 
117 **/
118 template<class observer_t>
119 class subject : public base_subject
120 {
121  template<class base_iterator_t>
122  class base_iterator : public base_iterator_t
123  {
124  public:
125  base_iterator() noexcept = default;
126 
127  /**
128  @brief base_iterator object constructor
129  @param other - base class iterator object
130  @param pSubject - subject class pointer
131  **/
132  base_iterator(const base_iterator_t& other, subject* pSubject) noexcept;
133 
134  base_iterator(const base_iterator& other) noexcept;
135  base_iterator(base_iterator&&) noexcept = default;
136  ~base_iterator() noexcept;
137 
138  base_iterator& operator=(const base_iterator& other) noexcept;
139  observer_t* operator->() noexcept;
140  observer_t& operator*() noexcept;
141 
142  private:
143  /**
144  @brief Init iterator by calling subject callback
145  **/
146  void init() noexcept;
147 
148  private:
149  subject* m_pSubject = nullptr;
150  };
151 
152  template<class base_iterator_t>
153  class const_base_iterator : public base_iterator_t
154  {
155  public:
156  const_base_iterator() noexcept = default;
157  const_base_iterator(const const_base_iterator&) noexcept = default;
158  const_base_iterator(const_base_iterator&&) noexcept = default;
159  const_base_iterator(const base_iterator_t& other) noexcept;
160 
161  const observer_t* operator->() const noexcept;
162  const observer_t& operator*() const noexcept;
163  };
164 
165 public:
166  using observers_container = std::vector<observer_t*>;
167  using iterator = base_iterator<typename observers_container::iterator>;
168  using const_iterator = const_base_iterator<typename observers_container::const_iterator>;
169  using reverse_iterator = base_iterator<typename observers_container::reverse_iterator>;
170  using const_reverse_iterator = const_base_iterator<typename observers_container::const_reverse_iterator>;
171  using notify_func = std::function<void(observer_t*)>;
172 
173 public:
174  QX_NONCOPYABLE(subject);
175  QX_MOVABLE(subject);
176 
177  subject() = default;
178  virtual ~subject() override;
179 
180  /**
181  @brief Attach observer to this subject
182  @param pObserver - observer pointer
183  @retval - observer_token for auto detaching observer from this subject
184  **/
185  [[nodiscard]] observer_token attach(observer_t* pObserver) noexcept;
186 
187  /**
188  @brief Notify all observers
189  @param notifyFunc - callback
190  **/
191  void notify(const notify_func& notifyFunc) const noexcept;
192 
193  /**
194  @brief Return iterator to beginning
195  @retval - iterator to beginning
196  **/
197  iterator begin();
198 
199  /**
200  @brief Return iterator to beginning
201  @retval - iterator to beginning
202  **/
203  const_iterator begin() const;
204 
205  /**
206  @brief Return const iterator to beginning
207  @retval - const iterator to beginning
208  **/
209  const_iterator cbegin() const;
210 
211  /**
212  @brief Return iterator to end
213  @retval - iterator to end
214  **/
215  iterator end();
216 
217  /**
218  @brief Return iterator to end
219  @retval - iterator to end
220  **/
221  const_iterator end() const;
222 
223  /**
224  @brief Return const iterator to end
225  @retval - const iterator to end
226  **/
227  const_iterator cend() const;
228 
229  /**
230  @brief Return reverse iterator to reverse beginning
231  @retval - reverse iterator to reverse beginning
232  **/
233  reverse_iterator rbegin();
234 
235  /**
236  @brief Return reverse iterator to reverse beginning
237  @retval - reverse iterator to reverse beginning
238  **/
239  const_reverse_iterator rbegin() const;
240 
241  /**
242  @brief Return const reverse iterator to reverse beginning
243  @retval - const reverse iterator to reverse beginning
244  **/
245  const_reverse_iterator crbegin() const;
246 
247  /**
248  @brief Return reverse iterator to reverse end
249  @retval - reverse iterator to reverse end
250  **/
251  reverse_iterator rend();
252 
253  /**
254  @brief Return reverse iterator to reverse end
255  @retval - reverse iterator to reverse end
256  **/
257  const_reverse_iterator rend() const;
258 
259  /**
260  @brief Return const reverse iterator to reverse end
261  @retval - const reverse iterator to reverse end
262  **/
263  const_reverse_iterator crend() const;
264 
265  /**
266  @brief Get number of observers attached to this subject
267  @retval - number of observers attached to this subject
268  **/
269  size_t get_num_observers() const noexcept;
270 
271 private:
272  /**
273  @brief Detach observer from this subject
274  @param pObserver - observer pointer
275  **/
276  virtual void detach(void* pObserver) noexcept override;
277 
278  /**
279  @brief Iterator destructing event handler
280  **/
281  void on_iterator_destructed() noexcept;
282 
283  /**
284  @brief Iterator constructing event handler
285  **/
286  void on_iterator_constructed() noexcept;
287 
288 private:
289  observers_container m_Observers;
290  std::vector<observer_token_data*> m_Tokens;
291  size_t m_nIterators = 0;
292 };
293 
294 } // namespace qx
295 
296 #include <qx/patterns/observer.inl>
Base subject class.
Definition: observer.h:94
virtual void detach(void *pObserver) noexcept=0
Detach observer from subject.
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
const_reverse_iterator rend() const
Return reverse iterator to reverse end.
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
const_iterator end() const
Return iterator to end.
size_t get_num_observers() const noexcept
Get number of observers attached to this subject.
Definition: observer.inl:254
const_reverse_iterator rbegin() const
Return reverse iterator to reverse beginning.
void notify(const notify_func &notifyFunc) const noexcept
Notify all observers.
Definition: observer.inl:175
const_iterator begin() const
Return iterator to beginning.
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