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