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-20 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 
37 namespace UTIL
38 {
39 class LINK;
40 
41 namespace DETAIL
42 {
44  {
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 } // namespace DETAIL
97 
98 
102 class LINK
103 {
104 public:
105  LINK();
106  LINK( std::shared_ptr<DETAIL::OBSERVABLE_BASE::IMPL> token, void* observer );
107  LINK( LINK&& other );
108  LINK( const LINK& ) = delete;
109 
110  void operator=( const LINK& ) = delete;
111  LINK& operator=( LINK&& other );
112 
113  void reset();
114 
115  explicit operator bool() const;
116 
117  ~LINK();
118 
119 private:
120  std::shared_ptr<DETAIL::OBSERVABLE_BASE::IMPL> token_;
121  void* observer_;
122 };
123 
124 
125 template <typename ObserverInterface>
127 {
128 public:
133 
139  OBSERVABLE( OBSERVABLE& aInherit ) : OBSERVABLE_BASE( aInherit ) {}
140 
146  void SubscribeUnmanaged( ObserverInterface* aObserver )
147  {
148  OBSERVABLE_BASE::add_observer( static_cast<void*>( aObserver ) );
149  }
150 
157  LINK Subscribe( ObserverInterface* aObserver )
158  {
159  OBSERVABLE_BASE::add_observer( static_cast<void*>( aObserver ) );
160  return LINK( impl_, static_cast<void*>( aObserver ) );
161  }
162 
170  void Unsubscribe( ObserverInterface* aObserver )
171  {
172  OBSERVABLE_BASE::remove_observer( static_cast<void*>( aObserver ) );
173  }
174 
181  template <typename... Args1, typename... Args2>
182  void Notify( void ( ObserverInterface::*Ptr )( Args1... ), Args2&&... aArgs )
183  {
184  static_assert( sizeof...( Args1 ) == sizeof...( Args2 ), "argument counts don't match" );
185 
186  if( impl_ )
187  {
188  enter_iteration();
189  try
190  {
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 } // namespace UTIL
250 
251 #endif
OBSERVABLE()
Construct an observable with empty non-shared subscription list.
Definition: observable.h:132
std::vector< void * > observers_
Definition: observable.h:72
LINK Subscribe(ObserverInterface *aObserver)
Add a subscription returning an RAII link.
Definition: observable.h:157
std::shared_ptr< IMPL > impl_
Definition: observable.h:93
void SubscribeUnmanaged(ObserverInterface *aObserver)
Add a subscription without RAII link.
Definition: observable.h:146
void add_observer(void *observer)
Definition: observable.cpp:216
void NotifyIgnore(void(ObserverInterface::*Ptr)(Args1...), ObserverInterface *aIgnore, Args2 &&... aArgs)
Notify event to all subscribed observers but one to be ignore.
Definition: observable.h:218
void Notify(void(ObserverInterface::*Ptr)(Args1...), Args2 &&... aArgs)
Notify event to all subscribed observers.
Definition: observable.h:182
OBSERVABLE(OBSERVABLE &aInherit)
Construct an observable with a shared subscription list.
Definition: observable.h:139
std::shared_ptr< IMPL > get_shared_impl()
Definition: observable.cpp:209
void add_observer(void *observer)
Definition: observable.cpp:88
A model subscriber implementation using links to represent connections.
Definition: observable.cpp:27
void remove_observer(void *observer)
Definition: observable.cpp:223
void Unsubscribe(ObserverInterface *aObserver)
Cancel the subscription of a subscriber.
Definition: observable.h:170
IMPL(OBSERVABLE_BASE *owned_by=nullptr)
Definition: observable.cpp:45
void remove_observer(void *observer)
Definition: observable.cpp:95