OpenWalnut  1.3.1
WPropertyStruct.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 WPROPERTYSTRUCT_H
26 #define WPROPERTYSTRUCT_H
27 
28 #include <vector>
29 #include <string>
30 
31 #include <boost/shared_ptr.hpp>
32 
33 #include <boost/tuple/tuple.hpp>
34 #include <boost/mpl/vector.hpp>
35 #include <boost/mpl/copy.hpp>
36 #include <boost/mpl/size.hpp>
37 #include <boost/mpl/at.hpp>
38 #include <boost/preprocessor/repetition/enum_params.hpp>
39 
40 #include "WStringUtils.h"
41 #include "WCondition.h"
42 #include "WPropertyGroupBase.h"
43 #include "WPropertyBase.h"
44 #include "WPropertyTypes.h"
45 #include "exceptions/WPropertyUnknown.h"
46 
47 /**
48  * This contains some helping classes for compile time type conversion and similar.
49  */
50 namespace WPropertyStructHelper
51 {
52  /**
53  * Class to push a type from a sequence to the front of a tuple type
54  *
55  * \tparam T the sequence to convert.
56  * \tparam Tuple the tuple type, getting extended with the sequence types.
57  */
58  template< typename T, typename Tuple>
60 
61  /**
62  * Class to push a type from a sequence to the front of a tuple type. This is a specialization allowing to create a tuple from a list of
63  * types.
64  *
65  * \tparam T the sequence to convert.
66  * \tparam list of types to add to the tuple.
67  */
68  template< typename T, BOOST_PP_ENUM_PARAMS( 10, typename T )>
69  struct PushTypeToTupleFront< T, boost::tuple< BOOST_PP_ENUM_PARAMS( 10, T ) > >
70  {
71  /**
72  * The resulting tuple type
73  */
74  typedef boost::tuple< T, BOOST_PP_ENUM_PARAMS( 9, T ) > type;
75  };
76 
77  /**
78  * Converts a boost mpl sequence to a boost tuple
79  *
80  * \tparam Sequence the sequence to convert
81  */
82  template< typename Sequence >
84  {
85  /**
86  * This is the tuple type for the sequence
87  */
88  typedef typename boost::mpl::reverse_copy<
89  Sequence,
90  boost::mpl::inserter<
91  boost::tuple<>,
93  >
95  };
96 
97  /**
98  * Alias for default type to emulate variadic templates
99  */
100  typedef boost::mpl::na NOTYPE;
101 
102  /**
103  * Convert a list of template parameters to a boost::mpl::vector. This is currently done using the boost::mpl no-type type. This might get a
104  * problem some day?!
105  *
106  * \tparam T0 first type. Mandatory.
107  * \tparam T1 additional type. Optional.
108  * \tparam T2 additional type. Optional.
109  * \tparam T3 additional type. Optional.
110  * \tparam T4 additional type. Optional.
111  * \tparam T5 additional type. Optional.
112  * \tparam T6 additional type. Optional.
113  * \tparam T7 additional type. Optional.
114  * \tparam T8 additional type. Optional.
115  * \tparam T9 additional type. Optional.
116  */
117  template<
118  typename T0,
119  typename T1 = NOTYPE,
120  typename T2 = NOTYPE,
121  typename T3 = NOTYPE,
122  typename T4 = NOTYPE,
123  typename T5 = NOTYPE,
124  typename T6 = NOTYPE,
125  typename T7 = NOTYPE,
126  typename T8 = NOTYPE,
127  typename T9 = NOTYPE
128  >
129  struct AsVector
130  {
131  /**
132  * The template types as mpl vector
133  */
134  typedef boost::mpl::vector< BOOST_PP_ENUM_PARAMS( 10, T ) > type;
135  };
136 }
137 
138 /**
139  * Specialization which does nothing for the NOTYPE default template parameters of \ref WPropertyStruct.
140  */
141 template<>
142 struct WPropertyGroupBase::PropertyCreatorAndGroupAdder< WPropertyStructHelper::NOTYPE >
143 {
144  /**
145  * The type of the initial value.
146  */
148 
149  /**
150  * Dummy method which does nothing for NOTYPE types.
151  */
152  static void createAndAdd( WPropertyGroupBase*, std::string, std::string, const ValueType& )
153  {
154  // NOTYPE will not cause any property creation.
155  }
156 
157  /**
158  * Dummy method which does nothing for NOTYPE types.
159  */
160  static void createAndAdd( WPropertyGroupBase*, std::string, std::string )
161  {
162  // NOTYPE will not cause any property creation.
163  }
164 };
165 
166 
167 /**
168  * This is a property which encapsulates a given, fixed number of other properties. You can specify up to 10 properties. This can be seen
169  * similar to the "struct" in the C++ language. A WPropertyStruct can basically seen as \ref WPropertyGroup, but is different in a certain way:
170  * it is fixed size (defined on compile time), it allows getting each property with their correct type and provides the appearance as if this
171  * property is only ONE object and not a group of multiple objects.
172  *
173  * \note the limitation to 10 types is due to the boost::tuple. If you need more, you need to replace the tuple type as storage-backend.
174  * \note if we use C++11 some day, we could use variadic templates here.
175  *
176  * \tparam T0 first type. Mandatory.
177  * \tparam T1 additional type. Optional.
178  * \tparam T2 additional type. Optional.
179  * \tparam T3 additional type. Optional.
180  * \tparam T4 additional type. Optional.
181  * \tparam T5 additional type. Optional.
182  * \tparam T6 additional type. Optional.
183  * \tparam T7 additional type. Optional.
184  * \tparam T8 additional type. Optional.
185  * \tparam T9 additional type. Optional.
186  */
187 template<
188  typename T0,
189  typename T1 = WPropertyStructHelper::NOTYPE,
190  typename T2 = WPropertyStructHelper::NOTYPE,
191  typename T3 = WPropertyStructHelper::NOTYPE,
192  typename T4 = WPropertyStructHelper::NOTYPE,
193  typename T5 = WPropertyStructHelper::NOTYPE,
194  typename T6 = WPropertyStructHelper::NOTYPE,
195  typename T7 = WPropertyStructHelper::NOTYPE,
196  typename T8 = WPropertyStructHelper::NOTYPE,
197  typename T9 = WPropertyStructHelper::NOTYPE
198 >
200 {
201 friend class WPropertyStructTest;
202 public:
203  /**
204  * The type of this template instantiation.
205  */
207 
208  /**
209  * Convenience typedef for a boost::shared_ptr< WPropertyStructType >
210  */
211  typedef typename boost::shared_ptr< WPropertyStructType > SPtr;
212 
213  /**
214  * Convenience typedef for a boost::shared_ptr< const WPropertyStructType >
215  */
216  typedef typename boost::shared_ptr< const WPropertyStructType > ConstSPtr;
217 
218  /**
219  * The boost mpl vector for all the types specified.
220  */
222 
223  /**
224  * The type vector as a boost tuple.
225  */
227 
228  /**
229  * Create an empty named property.
230  *
231  * \param name the name of the property
232  * \param description the description of the property
233  */
234  WPropertyStruct( std::string name, std::string description ):
235  WPropertyGroupBase( name, description )
236  {
237  // now create the property instances
238  PropertyCreatorAndGroupAdder< T0 >::createAndAdd( this, name + "_Prop0", "No description for Property 0 in struct \"" + name + "\"." );
239  PropertyCreatorAndGroupAdder< T1 >::createAndAdd( this, name + "_Prop1", "No description for Property 1 in struct \"" + name + "\"." );
240  PropertyCreatorAndGroupAdder< T2 >::createAndAdd( this, name + "_Prop2", "No description for Property 2 in struct \"" + name + "\"." );
241  PropertyCreatorAndGroupAdder< T3 >::createAndAdd( this, name + "_Prop3", "No description for Property 3 in struct \"" + name + "\"." );
242  PropertyCreatorAndGroupAdder< T4 >::createAndAdd( this, name + "_Prop4", "No description for Property 4 in struct \"" + name + "\"." );
243  PropertyCreatorAndGroupAdder< T5 >::createAndAdd( this, name + "_Prop5", "No description for Property 5 in struct \"" + name + "\"." );
244  PropertyCreatorAndGroupAdder< T6 >::createAndAdd( this, name + "_Prop6", "No description for Property 6 in struct \"" + name + "\"." );
245  PropertyCreatorAndGroupAdder< T7 >::createAndAdd( this, name + "_Prop7", "No description for Property 7 in struct \"" + name + "\"." );
246  PropertyCreatorAndGroupAdder< T8 >::createAndAdd( this, name + "_Prop8", "No description for Property 8 in struct \"" + name + "\"." );
247  PropertyCreatorAndGroupAdder< T9 >::createAndAdd( this, name + "_Prop9", "No description for Property 9 in struct \"" + name + "\"." );
248  }
249 
250  /**
251  * Copy constructor. Creates a deep copy of this property. As boost::signals2 and condition variables are non-copyable, new instances get
252  * created. The subscriptions to a signal are LOST as well as all listeners to a condition.
253  *
254  * \param from the instance to copy.
255  */
256  explicit WPropertyStruct( const WPropertyStructType& from ):
257  WPropertyGroupBase( from )
258  {
259  // this created a NEW update condition and NEW property instances (clones)
260  }
261 
262  /**
263  * Destructor.
264  */
266  {
267  // the storing tuple is destroyed automatically and the properties if not used anymore
268  }
269 
270  /**
271  * Get the N'th property in the struct.
272  *
273  * \tparam N the number of the property to get.
274  *
275  * \return the property.
276  */
277  template< int N >
278  typename boost::mpl::at< TypeVector, boost::mpl::size_t< N > >::type getProperty()
279  {
280  typedef typename boost::mpl::at< TypeVector, boost::mpl::size_t< N > >::type::element_type TargetType;
281  return boost::dynamic_pointer_cast< TargetType >( getProperty( N ) );
282  }
283 
284  /**
285  * Get the N'th property in the struct.
286  *
287  * \tparam N the number of the property to get.
288  *
289  * \return the property.
290  */
291  template< int N >
292  typename boost::mpl::at< TypeVector, boost::mpl::size_t< N > >::type::element_type::ConstSPtr getProperty() const
293  {
294  typedef typename boost::mpl::at< TypeVector, boost::mpl::size_t< N > >::type::element_type TargetType;
295  return boost::dynamic_pointer_cast< const TargetType >( getProperty( N ) );
296  }
297 
298  /**
299  * Returns the property with the given number, but only as base type. The advantage is that the property number can be specified during
300  * runtime.
301  *
302  * \param n the number of the property
303  *
304  * \return the property
305  */
306  const WPropertyBase::SPtr& getProperty( size_t n ) const
307  {
308  // lock, unlocked if l looses focus
310  return l->get()[ n ];
311  }
312 
313  /**
314  * Returns the property with the given number, but only as base type. The advantage is that the property number can be specified during
315  * runtime.
316  *
317  * \param n the number of the property
318  *
319  * \return the property
320  */
322  {
323  // lock, unlocked if l looses focus
325  return l->get()[ n ];
326  }
327 
328  /**
329  * The size of the WPropertyStruct. This returns the number of properties encapsulated.
330  *
331  * \return number of properties in struct
332  */
333  size_t size() const
334  {
335  return m_size;
336  }
337 
338  /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
339  // The WPropertyBase specific stuff
340  /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
341 
342  /**
343  * This method clones a property and returns the clone. It does a deep copy and, in contrast to a copy constructor, creates property with the
344  * correct type without explicitly requiring the user to specify it. It creates a NEW change condition and change signal. This means, alls
345  * subscribed signal handlers are NOT copied.
346  *
347  * \note this simply ensures the copy constructor of the runtime type is issued.
348  *
349  * \return the deep clone of this property.
350  */
352  {
353  // just use the copy constructor
354  return typename WPropertyStructType::SPtr( new WPropertyStructType( *this ) );
355  }
356 
357  /**
358  * Gets the real WPropertyVariable type of this instance.
359  *
360  * \return the real type.
361  */
362  virtual PROPERTY_TYPE getType() const
363  {
364  return PV_STRUCT;
365  }
366 
367  /**
368  * This methods allows properties to be set by a string value. This is especially useful when a property is only available as string and the
369  * real type of the property is unknown. This is a shortcut for casting the property and then setting the lexically casted value.
370  *
371  * \param value the new value to set.
372  *
373  * \return true if value could be set.
374  */
375  virtual bool setAsString( std::string value )
376  {
377  // this method splits the given string and simply forwards the call to the other properties
378  std::vector< std::string > propsAsString = string_utils::tokenize( value, "|", false );
379  if( size() != propsAsString.size() )
380  {
381  return false;
382  }
383 
384  // lock, unlocked if l looses focus
386  // give the string to each property
387  size_t curPropNb = 0;
388  bool success = true;
389  for( std::vector< std::string >::const_iterator iter = propsAsString.begin(); iter != propsAsString.end(); ++iter )
390  {
391  success = success && l->get()[ curPropNb ]->setAsString( *iter );
392  curPropNb++;
393  }
394  return success;
395  }
396 
397  /**
398  * Returns the current value as a string. This is useful for debugging or project files. It is not implemented as << operator, since the <<
399  * should also print min/max constraints and so on. This simply is the value.
400  *
401  * \return the value as a string.
402  */
403  virtual std::string getAsString()
404  {
405  // lock, unlocked if l looses focus
407 
408  // go through and append each prop
409  std::string result = "";
410  for( size_t i = 0; i < size(); ++i )
411  {
412  result += l->get()[ i ]->getAsString() + "|";
413  }
414  // strip last "|"
415  result.erase( result.length() - 1, 1 );
416  return result;
417  }
418 
419  /**
420  * Sets the value from the specified property to this one. This is especially useful to copy a value without explicitly casting/knowing the
421  * dynamic type of the property.
422  *
423  * \param value the new value.
424  * \param recommendedOnly if true, property types which support recommended values apply the given value as recommendation.
425  *
426  * \return true if the value has been accepted.
427  */
428  virtual bool set( boost::shared_ptr< WPropertyBase > value, bool recommendedOnly = false )
429  {
430  // is this the same type as we are?
431  typename WPropertyStructType::SPtr v = boost::dynamic_pointer_cast< WPropertyStructType >( value );
432  if( !v )
433  {
434  // it is not a WPropertyStruct with the same type
435  return false;
436  }
437 
438  // lock, unlocked if l looses focus
440  PropertySharedContainerType::ReadTicket lother = v->m_properties.getReadTicket();
441  bool success = true;
442  // set each property
443  for( size_t curPropNb = 0; curPropNb < size(); ++curPropNb )
444  {
445  success = success && l->get()[ curPropNb ]->set( lother->get()[ curPropNb ], recommendedOnly );
446  }
447 
448  return success;
449  }
450 
451 protected:
452 private:
453  /**
454  * How many elements are in this WPropertyStruct?
455  */
456  static const size_t m_size = boost::mpl::size< TypeVector >::value;
457 };
458 
459 #endif // WPROPERTYSTRUCT_H
460