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