OpenWalnut  1.3.1
WFlag.h
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #ifndef WFLAG_H
26 #define WFLAG_H
27 
28 #include <boost/shared_ptr.hpp>
29 
30 #include "WCondition.h"
31 
32 /**
33  * Class to have a simple notification/condition system for simple flags. This is somewhat similar to the observer design pattern.
34  * The type of the flag is specified by the template parameter. Per default, it is of type bool.
35  */
36 template < typename T >
37 class WFlag
38 {
39 public:
40  /**
41  * The type for later access.
42  */
43  typedef T ValueType;
44 
45  /**
46  * Convenience typedef for a boost::shared_ptr.
47  */
48  typedef boost::shared_ptr< WFlag< T > > SPtr;
49 
50  /**
51  * Convenience typedef for a boost::shared_ptr. Const.
52  */
53  typedef boost::shared_ptr< const WFlag< T > > ConstSPtr;
54 
55  /**
56  * Constructor. Uses a given condition to realize the wait/notify functionality. By using this constructor, the specified
57  * condition gets deleted whenever this WFlag is deleted.
58  *
59  * \param condition the condition to use.
60  * \note condition can also be a WConditionOneShot.
61  * \param initial the initial value of this flag.
62  */
63  WFlag( WCondition* condition, const T& initial );
64 
65  /**
66  * Constructor. Uses a given condition to realize the wait/notify functionality. By using this constructor, the specified
67  * condition gets NOT explicitely deleted when this WFlag gets deleted.
68  *
69  * \param condition the condition to use.
70  * \note condition can also be a WConditionOneShot.
71  * \param initial the initial value of this flag.
72  */
73  WFlag( boost::shared_ptr< WCondition > condition, const T& initial );
74 
75  /**
76  * Copy constructor. Creates a deep copy of this property. As boost::signals2 and condition variables are non-copyable, new instances get
77  * created. The subscriptions to a signal are LOST as well as all listeners to a condition.
78  * The conditions you can grab using getValueChangeConditon and getCondition are not the same as in the original! This is because
79  * the class corresponds to the observer/observable pattern. You won't expect a clone to fire a condition if a original flag is changed
80  * (which after cloning is completely decoupled from the clone).
81  *
82  * \param from the instance to copy.
83  */
84  explicit WFlag( const WFlag& from );
85 
86  /**
87  * Destructor. It deletes the instance of WCondition specified on construction.
88  */
89  virtual ~WFlag();
90 
91  /**
92  * Operator returns value of the flag.
93  *
94  * \param resetChangeState when true, the changed() flag gets reset to false.
95  *
96  * \return the value.
97  */
98  virtual const T& get( bool resetChangeState = false );
99 
100  /**
101  * Operator returns value of the flag.
102  *
103  * \return the value.
104  */
105  virtual const T& get() const;
106 
107  /**
108  * Operator returns value of the flag.
109  *
110  * \return the value.
111  */
112  virtual const T& operator()() const;
113 
114  /**
115  * Operator returns value of the flag. It does not reset the change flag.
116  *
117  * \return the value.
118  */
119  virtual operator T() const;
120 
121  /**
122  * Wait for the flag to change its value. For WConditionOneShot is also recognizes if the flag has changed before.
123  */
124  virtual void wait() const;
125 
126  /**
127  * Sets the new value for this flag. Also notifies waiting threads. After setting a value, changed() will be true.
128  *
129  * \param value the new value
130  * \param suppressNotification true to avoid a firing condition. This is useful for resetting values.
131  *
132  * \return true if the value has been set successfully.
133  *
134  * \note set( get() ) == true
135  */
136  virtual bool set( const T& value, bool suppressNotification = false );
137 
138  /**
139  * Sets the new value for this flag. Also notifies waiting threads.
140  *
141  * \param value the new value
142  */
143  virtual void operator()( const T& value );
144 
145  /**
146  * Returns the condition that is used by this flag.
147  *
148  * \return the condition
149  */
150  boost::shared_ptr< WCondition > getCondition();
151 
152  /**
153  * Returns the condition denoting a value change. In contrast to getCondition, this condition fires regardless of notification is suppressed
154  * during set() or not.
155  *
156  * \return the condition denoting a value change.
157  */
158  boost::shared_ptr< WCondition > getValueChangeCondition();
159 
160  /**
161  * Determines whether the specified value is acceptable. In WFlags, this always returns true. To modify the behaviour,
162  * implement this function in an appropriate way.
163  *
164  * \param newValue the new value.
165  *
166  * \return true if it is a valid/acceptable value.
167  */
168  virtual bool accept( const T& newValue );
169 
170  /**
171  * Tests whether a flag is currently valid. It is equal to accept( get() );
172  *
173  * \return true if current value is valid.
174  */
175  virtual bool isValid();
176 
177  /**
178  * True whenever the value inside this flag has changed since the last reset. It stays true until get( true ) is called or the reset value is
179  * true.
180  *
181  * \param reset if true, the change flag gets reset.
182  *
183  * \return true when the value has changed and not yet been reseted.
184  */
185  virtual bool changed( bool reset = false );
186 
187 protected:
188  /**
189  * The condition to be used for waiting/notifying. Please note, that it gets deleted during destruction.
190  */
191  boost::shared_ptr< WCondition > m_condition;
192 
193  /**
194  * This condition is fired whenever the value changes. In contrast to m_condition, this also fires if set() is called with
195  * suppressNotification=true.
196  */
197  boost::shared_ptr< WCondition > m_valueChangeCondition;
198 
199  /**
200  * The flag value.
201  */
203 
204  /**
205  * Denotes whether the value has changed since the last reset.
206  */
207  bool m_changed;
208 
209 private:
210 };
211 
212 /**
213  * Alias for easy usage of WFLag< bool >.
214  */
215 typedef WFlag< bool > WBoolFlag;
216 
217 template < typename T >
218 WFlag< T >::WFlag( WCondition* condition, const T& initial ):
219  m_condition( boost::shared_ptr< WCondition >( condition ) ),
220  m_valueChangeCondition( boost::shared_ptr< WCondition >( new WCondition() ) ),
221  m_flag( initial ),
222  m_changed( true )
223 {
224 }
225 
226 template < typename T >
227 WFlag< T >::WFlag( boost::shared_ptr< WCondition > condition, const T& initial ):
228  m_condition( condition ),
229  m_valueChangeCondition( boost::shared_ptr< WCondition >( new WCondition() ) ),
230  m_flag( initial ),
231  m_changed( true )
232 {
233 }
234 
235 template < typename T >
236 WFlag< T >::WFlag( const WFlag& from ):
237  m_condition( boost::shared_ptr< WCondition >( new WCondition() ) ),
238  m_valueChangeCondition( boost::shared_ptr< WCondition >( new WCondition() ) ),
239  m_flag( from.m_flag ),
240  m_changed( from.m_changed )
241 {
242 }
243 
244 template < typename T >
246 {
247 }
248 
249 template < typename T >
250 const T& WFlag< T >::operator()() const
251 {
252  return get();
253 }
254 
255 template < typename T >
256 const T& WFlag< T >::get( bool resetChangeState )
257 {
258  if( resetChangeState )
259  {
260  m_changed = false;
261  }
262  return m_flag;
263 }
264 
265 template < typename T >
266 const T& WFlag< T >::get() const
267 {
268  return m_flag;
269 }
270 
271 template < typename T >
273 {
274  return get();
275 }
276 
277 template < typename T >
278 void WFlag< T >::wait() const
279 {
280  m_condition->wait();
281 }
282 
283 template < typename T >
284 void WFlag< T >::operator()( const T& value )
285 {
286  set( value );
287 }
288 
289 template < typename T >
290 bool WFlag< T >::set( const T& value, bool suppressNotification )
291 {
292  // if the value is the same as the current one -> do not notify but let the caller know "all ok"
293  if( m_flag == value )
294  {
295  return true;
296  }
297 
298  // let the caller know whether the value was acceptable.
299  if( !accept( value ) )
300  {
301  return false;
302  }
303 
304  m_flag = value;
305  m_changed = true;
306 
307  // is the notification suppressed ?
308  if( !suppressNotification )
309  {
310  m_condition->notify();
311  }
312  m_valueChangeCondition->notify();
313 
314  return true;
315 }
316 
317 template < typename T >
318 boost::shared_ptr< WCondition > WFlag< T >::getCondition()
319 {
320  return m_condition;
321 }
322 
323 template < typename T >
324 boost::shared_ptr< WCondition > WFlag< T >::getValueChangeCondition()
325 {
326  return m_valueChangeCondition;
327 }
328 
329 template < typename T >
330 bool WFlag< T >::accept( const T& /* newValue */ )
331 {
332  // please implement this method in your class to modify the behaviour.
333  return true;
334 }
335 
336 template < typename T >
338 {
339  return accept( get() );
340 }
341 
342 template < typename T >
343 bool WFlag< T >::changed( bool reset )
344 {
345  bool tmp = m_changed;
346  if( reset )
347  {
348  m_changed = false;
349  }
350  return tmp;
351 }
352 
353 #endif // WFLAG_H
354