KiCad PCB EDA Suite
observable.h
Go to the documentation of this file.
1 
2 /*
3 * This program source code file is part of KICAD, a free EDA CAD application.
4 *
5 * Copyright (C) 2016 Kicad Developers, see change_log.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24 
25 #ifndef COMMON_OBSERVABLE_H__
26 #define COMMON_OBSERVABLE_H__
27 
28 #include <cassert>
29 #include <memory>
30 #include <vector>
31 #include <utility>
32 
33 /*
34 model subscriber implementation using links to represent connections.
35 subscribers can be removed during notification.
36 if no observers are registered, size is the size of a shared_ptr.
37 */
38 
39 namespace UTIL {
40 
41  class LINK;
42 
43  namespace DETAIL {
44 
45  struct OBSERVABLE_BASE {
46  public:
49 
51 
52  size_t size() const;
53 
54  private:
55  friend class UTIL::LINK;
56 
57  struct IMPL
58  {
59  IMPL( OBSERVABLE_BASE* owned_by = nullptr );
60  bool is_shared() const;
61  void set_shared();
62  ~IMPL();
63 
64  void add_observer( void* observer );
65  void remove_observer( void* observer );
66  void collect();
67 
68  bool is_iterating() const;
69 
70  void enter_iteration();
71  void leave_iteration();
72 
73  std::vector<void*> observers_;
74  unsigned int iteration_count_;
76  };
77 
78  void allocate_impl();
79  void allocate_shared_impl();
80 
81  void deallocate_impl();
82 
83  std::shared_ptr<IMPL> get_shared_impl();
84 
85  protected:
86  void on_observers_empty();
87 
88  void enter_iteration();
89  void leave_iteration();
90 
91  void add_observer( void* observer );
92  void remove_observer( void* observer );
93 
94  std::shared_ptr<IMPL> impl_;
95  };
96 
97  }
98 
99  //
100  // Simple RAII-handle to a subscription.
101  //
102  class LINK {
103  public:
104  LINK();
105  LINK( std::shared_ptr<DETAIL::OBSERVABLE_BASE::IMPL> token, void* observer );
106  LINK( LINK&& other );
107  LINK( const LINK& ) = delete;
108 
109  void operator=( const LINK& ) = delete;
110  LINK& operator=( LINK&& other );
111 
112  void reset();
113 
114  explicit operator bool() const;
115 
116  ~LINK();
117 
118  private:
119  std::shared_ptr<DETAIL::OBSERVABLE_BASE::IMPL> token_;
120  void* observer_;
121  };
122 
123  //
124  //
125  //
126  template<typename ObserverInterface>
127  class OBSERVABLE :
129  {
130  public:
136 
142  OBSERVABLE( OBSERVABLE& aInherit )
143  : OBSERVABLE_BASE( aInherit )
144  {}
145 
151  void SubscribeUnmanaged( ObserverInterface* aObserver )
152  {
153  OBSERVABLE_BASE::add_observer( static_cast<void*>(aObserver) );
154  }
155 
162  LINK Subscribe( ObserverInterface* aObserver ) {
163  OBSERVABLE_BASE::add_observer( static_cast<void*>(aObserver) );
164  return LINK( impl_, static_cast<void*>(aObserver) );
165  }
166 
172  void Unsubscribe( ObserverInterface* obs )
173  {
174  OBSERVABLE_BASE::remove_observer( static_cast<void*>(obs) );
175  }
176 
183  template< typename... Args1, typename... Args2 >
184  void Notify( void(ObserverInterface::*Ptr)(Args1...), Args2&&... aArgs )
185  {
186  static_assert(sizeof...(Args1) == sizeof...(Args2), "argument counts don't match");
187 
188  if( impl_ )
189  {
190  enter_iteration();
191  try {
192  for( auto* void_ptr : impl_->observers_ )
193  {
194  if( void_ptr )
195  {
196  auto* typed_ptr = static_cast<ObserverInterface*>(void_ptr);
197  (typed_ptr->*Ptr)(std::forward<Args2>( aArgs )...);
198  }
199  }
200  }
201  catch(...)
202  {
203  leave_iteration();
204  throw;
205  }
206 
207  leave_iteration();
208  }
209  }
210 
218  template< typename... Args1, typename... Args2 >
219  void NotifyIgnore( void(ObserverInterface::*Ptr)(Args1...), ObserverInterface* aIgnore,
220  Args2&&... aArgs )
221  {
222  static_assert(sizeof...(Args1) == sizeof...(Args2), "argument counts don't match");
223 
224  if( impl_ )
225  {
226  enter_iteration();
227 
228  try
229  {
230  for(auto* void_ptr : impl_->observers_)
231  {
232  if( void_ptr && void_ptr != aIgnore )
233  {
234  auto* typed_ptr = static_cast<ObserverInterface*>(void_ptr);
235  (typed_ptr->*Ptr)(std::forward<Args2>( aArgs )...);
236  }
237  }
238  }
239  catch(...)
240  {
241  leave_iteration();
242  throw;
243  }
244 
245  leave_iteration();
246  }
247  }
248 
249  };
250 
251 }
252 
253 #endif
OBSERVABLE()
Function Observable() Constructor.
Definition: observable.h:135
std::vector< void * > observers_
Definition: observable.h:73
LINK Subscribe(ObserverInterface *aObserver)
Function Subscribe adds a subscription returning an RAII link.
Definition: observable.h:162
std::shared_ptr< IMPL > impl_
Definition: observable.h:94
void SubscribeUnmanaged(ObserverInterface *aObserver)
Function SubscribeUnmanaged adds a subscription without RAII link.
Definition: observable.h:151
void add_observer(void *observer)
Definition: observable.cpp:216
OBSERVABLE(OBSERVABLE &aInherit)
Function Observable(OBSERVABLE&) Constructor.
Definition: observable.h:142
void Unsubscribe(ObserverInterface *obs)
Function Unsubscribe cancels the subscription of a subscriber.
Definition: observable.h:172
std::shared_ptr< IMPL > get_shared_impl()
Definition: observable.cpp:209
void Notify(void(ObserverInterface::*Ptr)(Args1...), Args2 &&...aArgs)
Function Notify Notifies event to all subscribed observers.
Definition: observable.h:184
void add_observer(void *observer)
Definition: observable.cpp:88
void remove_observer(void *observer)
Definition: observable.cpp:223
void NotifyIgnore(void(ObserverInterface::*Ptr)(Args1...), ObserverInterface *aIgnore, Args2 &&...aArgs)
Function Notify Notifies event to all subscribed observers but one to be ignore.
Definition: observable.h:219
IMPL(OBSERVABLE_BASE *owned_by=nullptr)
Definition: observable.cpp:45
void remove_observer(void *observer)
Definition: observable.cpp:95