Scroom  0.14
observable.hh
Go to the documentation of this file.
1 /*
2  * Scroom - Generic viewer for 2D data
3  * Copyright (C) 2009-2022 Kees-Jan Dijkzeul
4  *
5  * SPDX-License-Identifier: LGPL-2.1
6  */
7 
8 #pragma once
9 
10 #include <list>
11 #include <map>
12 #include <utility>
13 
14 #include <boost/shared_ptr.hpp>
15 #include <boost/thread.hpp>
16 #include <boost/weak_ptr.hpp>
17 
18 #include <scroom/bookkeeping.hh>
19 #include <scroom/utilities.hh>
20 
21 namespace Scroom::Utils
22 {
23  template <typename T>
24  class Observable;
25 
26  namespace Detail
27  {
33  template <typename T>
35  {
36  public:
37  boost::weak_ptr<Observable<T>> observable;
38  boost::shared_ptr<T> o;
39  boost::weak_ptr<T> observer;
41  using Ptr = boost::shared_ptr<Registration<T>>;
42 
43  public:
44  Registration() = default;
45  Registration(boost::weak_ptr<Observable<T>> observable, boost::shared_ptr<T> observer);
46  Registration(boost::weak_ptr<Observable<T>> observable, boost::weak_ptr<T> observer);
47  void set(boost::shared_ptr<T> observer);
48  void set(boost::weak_ptr<T> observer);
49 
50  static Ptr create(boost::weak_ptr<Observable<T>> observable, boost::shared_ptr<T> observer);
51  static Ptr create(boost::weak_ptr<Observable<T>> observable, boost::weak_ptr<T> observer);
52  };
53  } // namespace Detail
54 
70  template <typename T>
71  class Observable : public virtual Base
72  {
73  public:
74  using Observer = boost::shared_ptr<T>;
75  using Ptr = boost::shared_ptr<Observable<T>>;
76 
77  private:
78  using ObserverWeak = boost::weak_ptr<T>;
80 
81  private:
84 
85  protected:
93  std::list<Observer> getObservers();
94 
95  public:
96  Observable();
97  ~Observable() override;
98  Observable(const Observable&) = delete;
99  Observable(Observable&&) = delete;
100  Observable operator=(const Observable&) = delete;
101  Observable operator=(Observable&&) = delete;
102 
103  protected:
108  virtual void observerAdded(Observer const& observer, Scroom::Bookkeeping::Token const& token);
109 
110  public:
113 
114  private:
115  void unregisterObserver(ObserverWeak const& observer);
116 
117  friend class Detail::Registration<T>;
118  };
119 
121  // Detail::Registration implementation
122 
123  template <typename T>
124  Detail::Registration<T>::Registration(boost::weak_ptr<Observable<T>> observable_, boost::shared_ptr<T> observer_)
125  : observable(std::move(observable_))
126  , o(observer_)
127  , observer(observer_)
128  {
129  }
130 
131  template <typename T>
132  Detail::Registration<T>::Registration(boost::weak_ptr<Observable<T>> observable_, boost::weak_ptr<T> observer_)
133  : observable(std::move(observable_))
134  , o()
135  , observer(std::move(observer_))
136  {
137  // We don't want to store a "hard" reference, so field o is intentionally empty.
138  }
139 
140  template <typename T>
141  void Detail::Registration<T>::set(boost::shared_ptr<T> observer_)
142  {
143  o = observer_;
144  observer = observer_;
145  }
146 
147  template <typename T>
148  void Detail::Registration<T>::set(boost::weak_ptr<T> observer_)
149  {
150  // We don't want to store a "hard" reference, so field o is intentionally empty.
151  o.reset();
152  observer = observer_;
153  }
154 
155  template <typename T>
157  boost::shared_ptr<T> observer)
158  {
159  return typename Detail::Registration<T>::Ptr(new Detail::Registration<T>(observable, observer));
160  }
161 
162  template <typename T>
164  boost::weak_ptr<T> observer)
165  {
166  return typename Detail::Registration<T>::Ptr(new Detail::Registration<T>(observable, observer));
167  }
168 
170  // Observable implementation
171  template <typename T>
173  {
175  }
176 
177  template <typename T>
179  {
180  // Destroy strong references to any observers
181  //
182  // The one holding the token of the registration is in control
183  // of the lifetime of the registration objects. Hence, as long
184  // as the Token is valid, a reference to the Registration will
185  // exist, which may, in turn, contain a (strong) reference to an
186  // Observer. This is not desirable. As soon as the observable is
187  // deleted (which is now), it should no longer hold any
188  // references to any Observers. Hence, we should manually reset
189  // references to observers here.
190  for(const typename Registration::Ptr& registration: registrationMap->values())
191  {
192  registration->o.reset();
193  }
194  }
195 
196  template <typename T>
197  std::list<typename Observable<T>::Observer> Observable<T>::getObservers()
198  {
199  std::list<typename Observable<T>::Observer> result;
200  for(const typename Registration::Ptr& registration: registrationMap->values())
201  {
202  Observer const o = registration->observer.lock();
203  if(o)
204  {
205  result.push_back(o);
206  }
207  }
208 
209  return result;
210  }
211 
212  template <typename T>
214  {
215  Scroom::Bookkeeping::Token t = registrationMap->reReserve(observer);
216  typename Detail::Registration<T>::Ptr r = registrationMap->get(observer);
217  if(r)
218  {
219  r->set(observer);
220  }
221  else
222  {
223  r = Detail::Registration<T>::create(shared_from_this<Observable<T>>(), observer);
224  registrationMap->set(observer, r);
225  }
226 
227  observerAdded(observer, t);
228 
229  return t;
230  }
231 
232  template <typename T>
234  {
235  Scroom::Bookkeeping::Token t = registrationMap->reReserve(observer);
236  typename Detail::Registration<T>::Ptr r = registrationMap->get(observer);
237  if(r)
238  {
239  r->set(observer);
240  }
241  else
242  {
243  r = Detail::Registration<T>::create(shared_from_this<Observable<T>>(), observer);
244  registrationMap->set(observer, r);
245  }
246 
247  observerAdded(typename Observable<T>::Observer(observer), t);
248 
249  return t;
250  }
251 
252  template <typename T>
254  {
255  registrationMap->remove(observer);
256  }
257 
258  template <typename T>
260  {
261  // Do nothing
262  }
263 } // namespace Scroom::Utils
Scroom::Utils::Detail::Registration::observable
boost::weak_ptr< Observable< T > > observable
Definition: observable.hh:37
Scroom::Utils
Definition: assertions.hh:14
Scroom::Utils::Observable::registerStrongObserver
Scroom::Bookkeeping::Token registerStrongObserver(Observer const &observer)
Definition: observable.hh:213
Scroom::Utils::Detail::Registration::set
void set(boost::shared_ptr< T > observer)
Definition: observable.hh:141
Scroom::Utils::Observable::getObservers
std::list< Observer > getObservers()
Definition: observable.hh:197
Scroom::Utils::Detail::Registration::observer
boost::weak_ptr< T > observer
Definition: observable.hh:39
utilities.hh
Scroom::Utils::Observable::unregisterObserver
void unregisterObserver(ObserverWeak const &observer)
Definition: observable.hh:253
Scroom::Utils::Observable< TileLoadingObserver >::ObserverWeak
boost::weak_ptr< TileLoadingObserver > ObserverWeak
Definition: observable.hh:78
Scroom::Utils::Observable::registerObserver
Scroom::Bookkeeping::Token registerObserver(ObserverWeak const &observer)
Definition: observable.hh:233
Scroom::Utils::Observable::~Observable
~Observable() override
Definition: observable.hh:178
Scroom::Utils::Detail::Registration::Ptr
boost::shared_ptr< Registration< T > > Ptr
Definition: observable.hh:41
Scroom::Utils::Observable< TileLoadingObserver >::Ptr
boost::shared_ptr< Observable< TileLoadingObserver > > Ptr
Definition: observable.hh:75
Scroom::Utils::Detail::Registration
Definition: observable.hh:34
Scroom::Utils::Base
Definition: utilities.hh:30
Scroom::Utils::Observable< TileLoadingObserver >::Observer
boost::shared_ptr< TileLoadingObserver > Observer
Definition: observable.hh:74
Scroom::Utils::Observable::registrationMap
Scroom::Bookkeeping::Map< ObserverWeak, typename Registration::Ptr >::Ptr registrationMap
Definition: observable.hh:83
Scroom::Utils::Observable
Definition: observable.hh:24
Scroom::Utils::Detail::Registration::Registration
Registration()=default
Scroom::Utils::Observable::Observable
Observable()
Definition: observable.hh:172
Detail
Definition: async-deleter.hh:12
Scroom::Bookkeeping::Map::Ptr
boost::shared_ptr< Map< K, V > > Ptr
Definition: bookkeeping.hh:85
Scroom::Utils::Observable::observerAdded
virtual void observerAdded(Observer const &observer, Scroom::Bookkeeping::Token const &token)
Definition: observable.hh:259
Scroom::Bookkeeping::Token
Definition: bookkeeping.hh:37
Scroom::Bookkeeping::Map::create
static Ptr create()
Definition: bookkeepingimpl.hh:424
Scroom::Utils::Observable::operator=
Observable operator=(const Observable &)=delete
bookkeeping.hh
Scroom::Utils::Detail::Registration::o
boost::shared_ptr< T > o
Definition: observable.hh:38
Scroom::Utils::Detail::Registration::create
static Ptr create(boost::weak_ptr< Observable< T >> observable, boost::shared_ptr< T > observer)
Definition: observable.hh:156