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
37namespace UTIL
38{
39class LINK;
40
41namespace 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();
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
102class LINK
103{
104public:
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
119private:
120 std::shared_ptr<DETAIL::OBSERVABLE_BASE::IMPL> token_;
122};
123
124
125template <typename ObserverInterface>
127{
128public:
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 {
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 {
203 throw;
204 }
205
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 {
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 {
241 throw;
242 }
243
245 }
246 }
247};
248
249} // namespace UTIL
250
251#endif
LINK Subscribe(ObserverInterface *aObserver)
Add a subscription returning an RAII link.
Definition: observable.h:157
OBSERVABLE(OBSERVABLE &aInherit)
Construct an observable with a shared subscription list.
Definition: observable.h:139
void SubscribeUnmanaged(ObserverInterface *aObserver)
Add a subscription without RAII link.
Definition: observable.h:146
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()
Construct an observable with empty non-shared subscription list.
Definition: observable.h:132
void Unsubscribe(ObserverInterface *aObserver)
Cancel the subscription of a subscriber.
Definition: observable.h:170
A model subscriber implementation using links to represent connections.
Definition: observable.cpp:27
void remove_observer(void *observer)
Definition: observable.cpp:95
void add_observer(void *observer)
Definition: observable.cpp:88
std::vector< void * > observers_
Definition: observable.h:72
IMPL(OBSERVABLE_BASE *owned_by=nullptr)
Definition: observable.cpp:45
void remove_observer(void *observer)
Definition: observable.cpp:223
std::shared_ptr< IMPL > get_shared_impl()
Definition: observable.cpp:209
void add_observer(void *observer)
Definition: observable.cpp:216
std::shared_ptr< IMPL > impl_
Definition: observable.h:93