KiCad PCB EDA Suite
observable.cpp
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 #include "observable.h"
25 #include <algorithm>
26 
27 namespace UTIL {
28 
29  namespace DETAIL {
30 
31  template<typename T>
32  struct equals {
33  equals( const T& val ) : val_( val ) {}
34 
35  bool operator()( const T& val )
36  {
37  return val == val_;
38  }
39 
40  private:
41  const T& val_;
42  };
43 
44 
46  : iteration_count_( 0 ), owned_by_( owned_by )
47  {}
48 
49 
51  {
52  return owned_by_ == nullptr;
53  }
54 
55 
57  {
58  owned_by_ = nullptr;
59  }
60 
61 
63  {
64  }
65 
66 
68  {
69  ++iteration_count_;
70  }
71 
72 
74  {
75  --iteration_count_;
76 
77  if( iteration_count_ == 0 )
78  collect();
79  }
80 
81 
83  {
84  return iteration_count_ != 0;
85  }
86 
87 
88  void OBSERVABLE_BASE::IMPL::add_observer( void* observer )
89  {
90  assert( !is_iterating() );
91  observers_.push_back( observer );
92  }
93 
94 
96  {
97  auto it = std::find( observers_.begin(), observers_.end(), observer );
98 
99  if( it == observers_.end() )
100  {
101  assert( false );
102  return;
103  }
104 
105  if( is_iterating() )
106  *it = nullptr;
107  else
108  observers_.erase( it );
109  }
110 
111 
113  {
114  auto it = std::remove_if( observers_.begin(), observers_.end(), DETAIL::equals<void*>( nullptr ) );
115  observers_.erase( it, observers_.end() );
116  }
117  }
118 
119 
121  : observer_( nullptr )
122  {
123  }
124 
125 
126  LINK::LINK( std::shared_ptr<DETAIL::OBSERVABLE_BASE::IMPL> token, void* observer )
127  : token_( std::move( token ) ), observer_( observer )
128  {
129  }
130 
131 
132  LINK::LINK( LINK&& other )
133  : token_( std::move( other.token_ ) ), observer_( other.observer_ )
134  {
135  other.token_.reset();
136  }
137 
138 
140  {
141  token_ = std::move( other.token_ );
142  other.token_.reset();
143  observer_ = other.observer_;
144  return *this;
145  }
146 
147 
148  LINK::operator bool() const
149  {
150  return token_ ? true : false;
151  }
152 
153 
155  {
156  reset();
157  }
158 
159 
160  void LINK::reset()
161  {
162  if(token_)
163  {
164  token_->remove_observer( observer_ );
165  token_.reset();
166  }
167  }
168 
169 
170  namespace DETAIL {
171 
173  {
174  }
175 
176 
178  : impl_( other.get_shared_impl() )
179  {
180  }
181 
182 
184  {
185  }
186 
187 
189  {
190  if(!impl_)
191  impl_ = std::make_shared<IMPL>( this );
192  }
193 
194 
196  {
197  if(!impl_)
198  impl_ = std::make_shared<IMPL>();
199  else
200  impl_->set_shared();
201  }
202 
203 
205  impl_.reset();
206  }
207 
208 
209  std::shared_ptr<OBSERVABLE_BASE::IMPL> OBSERVABLE_BASE::get_shared_impl()
210  {
212  return impl_;
213  }
214 
215 
216  void OBSERVABLE_BASE::add_observer( void* observer )
217  {
218  allocate_impl();
219  impl_->add_observer( observer );
220  }
221 
222 
223  void OBSERVABLE_BASE::remove_observer( void* observer )
224  {
225  assert( impl_ );
226  impl_->remove_observer( observer );
227  }
228 
229 
231  {
232  if( impl_ )
233  impl_->enter_iteration();
234  }
235 
236 
238  {
239  if( impl_)
240  {
241  impl_->leave_iteration();
242 
243  if( !impl_->is_iterating() && !impl_->is_shared() && impl_.use_count() == 1 )
244  impl_.reset();
245  }
246  }
247 
248 
249  size_t OBSERVABLE_BASE::size() const
250  {
251  if( impl_ )
252  return impl_->observers_.size();
253  else
254  return 0;
255  }
256 
257 
259  {
260  // called by an impl that is owned by this, ie. it is a non-shared impl
261  // also it is not iterating
262  deallocate_impl();
263  }
264 
265  }
266 
267 }
T
enum T contains all this lexer's tokens.
std::shared_ptr< IMPL > impl_
Definition: observable.h:93
void add_observer(void *observer)
Definition: observable.cpp:216
std::shared_ptr< IMPL > get_shared_impl()
Definition: observable.cpp:209
equals(const T &val)
Definition: observable.cpp:33
void add_observer(void *observer)
Definition: observable.cpp:88
void remove_observer(void *observer)
Definition: observable.cpp:223
bool operator()(const T &val)
Definition: observable.cpp:35
IMPL(OBSERVABLE_BASE *owned_by=nullptr)
Definition: observable.cpp:45
void remove_observer(void *observer)
Definition: observable.cpp:95