KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 The KiCad Developers, see AUTHORS.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, see <https://www.gnu.org/licenses/>.
18*/
19
20#ifndef COMMON_OBSERVABLE_H__
21#define COMMON_OBSERVABLE_H__
22
23#include <cassert>
24#include <memory>
25#include <vector>
26#include <utility>
27
33namespace UTIL
34{
35class LINK;
36
37namespace DETAIL
38{
40 {
41 public:
44
46
47 size_t size() const;
48
49 private:
50 friend class UTIL::LINK;
51
52 struct IMPL
53 {
54 IMPL( OBSERVABLE_BASE* owned_by = nullptr );
55 bool is_shared() const;
56 void set_shared();
57 ~IMPL();
58
59 void add_observer( void* observer );
60 void remove_observer( void* observer );
61 void collect();
62
63 bool is_iterating() const;
64
65 void enter_iteration();
66 void leave_iteration();
67
68 std::vector<void*> observers_;
69 unsigned int iteration_count_;
71 };
72
73 void allocate_impl();
75
76 void deallocate_impl();
77
78 std::shared_ptr<IMPL> get_shared_impl();
79
80 protected:
81 void on_observers_empty();
82
83 void enter_iteration();
84 void leave_iteration();
85
86 void add_observer( void* observer );
87 void remove_observer( void* observer );
88
89 std::shared_ptr<IMPL> impl_;
90 };
91
92} // namespace DETAIL
93
94
98class LINK
99{
100public:
101 LINK();
102 LINK( std::shared_ptr<DETAIL::OBSERVABLE_BASE::IMPL> token, void* observer );
103 LINK( LINK&& other );
104 LINK( const LINK& ) = delete;
105
106 void operator=( const LINK& ) = delete;
107 LINK& operator=( LINK&& other );
108
109 void reset();
110
111 explicit operator bool() const;
112
113 ~LINK();
114
115private:
116 std::shared_ptr<DETAIL::OBSERVABLE_BASE::IMPL> token_;
118};
119
120
121template <typename ObserverInterface>
123{
124public:
129
135 OBSERVABLE( OBSERVABLE& aInherit ) : OBSERVABLE_BASE( aInherit ) {}
136
142 void SubscribeUnmanaged( ObserverInterface* aObserver )
143 {
144 OBSERVABLE_BASE::add_observer( static_cast<void*>( aObserver ) );
145 }
146
153 LINK Subscribe( ObserverInterface* aObserver )
154 {
155 OBSERVABLE_BASE::add_observer( static_cast<void*>( aObserver ) );
156 return LINK( impl_, static_cast<void*>( aObserver ) );
157 }
158
166 void Unsubscribe( ObserverInterface* aObserver )
167 {
168 OBSERVABLE_BASE::remove_observer( static_cast<void*>( aObserver ) );
169 }
170
177 template <typename... Args1, typename... Args2>
178 void Notify( void ( ObserverInterface::*Ptr )( Args1... ), Args2&&... aArgs )
179 {
180 static_assert( sizeof...( Args1 ) == sizeof...( Args2 ), "argument counts don't match" );
181
182 if( impl_ )
183 {
185 try
186 {
187 for( auto* void_ptr : impl_->observers_ )
188 {
189 if( void_ptr )
190 {
191 auto* typed_ptr = static_cast<ObserverInterface*>( void_ptr );
192 ( typed_ptr->*Ptr )( std::forward<Args2>( aArgs )... );
193 }
194 }
195 }
196 catch( ... )
197 {
199 throw;
200 }
201
203 }
204 }
205
213 template <typename... Args1, typename... Args2>
214 void NotifyIgnore( void ( ObserverInterface::*Ptr )( Args1... ), ObserverInterface* aIgnore,
215 Args2&&... aArgs )
216 {
217 static_assert( sizeof...( Args1 ) == sizeof...( Args2 ), "argument counts don't match" );
218
219 if( impl_ )
220 {
222
223 try
224 {
225 for( auto* void_ptr : impl_->observers_ )
226 {
227 if( void_ptr && void_ptr != aIgnore )
228 {
229 auto* typed_ptr = static_cast<ObserverInterface*>( void_ptr );
230 ( typed_ptr->*Ptr )( std::forward<Args2>( aArgs )... );
231 }
232 }
233 }
234 catch( ... )
235 {
237 throw;
238 }
239
240 }
241 }
242};
243
244} // namespace UTIL
245
246#endif
LINK Subscribe(ObserverInterface *aObserver)
Add a subscription returning an RAII link.
Definition observable.h:153
OBSERVABLE(OBSERVABLE &aInherit)
Construct an observable with a shared subscription list.
Definition observable.h:135
void SubscribeUnmanaged(ObserverInterface *aObserver)
Add a subscription without RAII link.
Definition observable.h:142
void NotifyIgnore(void(ObserverInterface::*Ptr)(Args1...), ObserverInterface *aIgnore, Args2 &&... aArgs)
Notify event to all subscribed observers but one to be ignore.
Definition observable.h:214
void Notify(void(ObserverInterface::*Ptr)(Args1...), Args2 &&... aArgs)
Notify event to all subscribed observers.
Definition observable.h:178
OBSERVABLE()
Construct an observable with empty non-shared subscription list.
Definition observable.h:128
void Unsubscribe(ObserverInterface *aObserver)
Cancel the subscription of a subscriber.
Definition observable.h:166
A model subscriber implementation using links to represent connections.
void remove_observer(void *observer)
void add_observer(void *observer)
std::vector< void * > observers_
Definition observable.h:68
IMPL(OBSERVABLE_BASE *owned_by=nullptr)
void remove_observer(void *observer)
std::shared_ptr< IMPL > get_shared_impl()
friend class UTIL::LINK
Definition observable.h:50
void add_observer(void *observer)
std::shared_ptr< IMPL > impl_
Definition observable.h:89