OpenWalnut  1.4.0
WPropertyStruct.h
00001 //---------------------------------------------------------------------------
00002 //
00003 // Project: OpenWalnut ( http://www.openwalnut.org )
00004 //
00005 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
00006 // For more information see http://www.openwalnut.org/copying
00007 //
00008 // This file is part of OpenWalnut.
00009 //
00010 // OpenWalnut is free software: you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as published by
00012 // the Free Software Foundation, either version 3 of the License, or
00013 // (at your option) any later version.
00014 //
00015 // OpenWalnut is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 // GNU Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public License
00021 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
00022 //
00023 //---------------------------------------------------------------------------
00024 
00025 #ifndef WPROPERTYSTRUCT_H
00026 #define WPROPERTYSTRUCT_H
00027 
00028 #include <vector>
00029 #include <string>
00030 
00031 #include <boost/shared_ptr.hpp>
00032 
00033 #include <boost/tuple/tuple.hpp>
00034 #include <boost/mpl/vector.hpp>
00035 #include <boost/mpl/copy.hpp>
00036 #include <boost/mpl/size.hpp>
00037 #include <boost/mpl/at.hpp>
00038 #include <boost/preprocessor/repetition/enum_params.hpp>
00039 
00040 #include "WStringUtils.h"
00041 #include "WCondition.h"
00042 #include "WPropertyGroupBase.h"
00043 #include "WPropertyBase.h"
00044 #include "WPropertyTypes.h"
00045 #include "exceptions/WPropertyUnknown.h"
00046 
00047 /**
00048  * This contains some helping classes for compile time type conversion and similar.
00049  */
00050 namespace WPropertyStructHelper
00051 {
00052     /**
00053      * Class to push a type from a sequence to the front of a tuple type
00054      *
00055      * \tparam T the sequence to convert.
00056      * \tparam Tuple the tuple type, getting extended with the sequence types.
00057      */
00058     template< typename T, typename Tuple>
00059     struct PushTypeToTupleFront;
00060 
00061     /**
00062      * 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
00063      * types.
00064      *
00065      * \tparam T the sequence to convert.
00066      * \tparam list of types to add to the tuple.
00067      */
00068     template< typename T, BOOST_PP_ENUM_PARAMS( 10, typename T )>
00069     struct PushTypeToTupleFront< T, boost::tuple< BOOST_PP_ENUM_PARAMS( 10, T ) > >
00070     {
00071         /**
00072          * The resulting tuple type
00073          */
00074         typedef boost::tuple< T, BOOST_PP_ENUM_PARAMS( 9, T ) > type;
00075     };
00076 
00077     /**
00078      * Converts a boost mpl sequence to a boost tuple
00079      *
00080      * \tparam Sequence the sequence to convert
00081      */
00082     template< typename Sequence >
00083     struct SequenceToTuple
00084     {
00085         /**
00086          * This is the tuple type for the sequence
00087          */
00088         typedef typename boost::mpl::reverse_copy<
00089             Sequence,
00090             boost::mpl::inserter<
00091                 boost::tuple<>,
00092                 PushTypeToTupleFront< boost::mpl::_2, boost::mpl::_1 >
00093             >
00094         >::type type;
00095     };
00096 
00097     /**
00098      * Alias for default type to emulate variadic templates
00099      */
00100     typedef boost::mpl::na NOTYPE;
00101 
00102     /**
00103      * 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
00104      * problem some day?!
00105      *
00106      * \tparam T0 first type. Mandatory.
00107      * \tparam T1 additional type. Optional.
00108      * \tparam T2 additional type. Optional.
00109      * \tparam T3 additional type. Optional.
00110      * \tparam T4 additional type. Optional.
00111      * \tparam T5 additional type. Optional.
00112      * \tparam T6 additional type. Optional.
00113      * \tparam T7 additional type. Optional.
00114      * \tparam T8 additional type. Optional.
00115      * \tparam T9 additional type. Optional.
00116      */
00117     template<
00118         typename T0,
00119         typename T1 = NOTYPE,
00120         typename T2 = NOTYPE,
00121         typename T3 = NOTYPE,
00122         typename T4 = NOTYPE,
00123         typename T5 = NOTYPE,
00124         typename T6 = NOTYPE,
00125         typename T7 = NOTYPE,
00126         typename T8 = NOTYPE,
00127         typename T9 = NOTYPE
00128     >
00129     struct AsVector
00130     {
00131         /**
00132          * The template types as mpl vector
00133          */
00134         typedef boost::mpl::vector< BOOST_PP_ENUM_PARAMS( 10, T ) > type;
00135     };
00136 }
00137 
00138 /**
00139  * Specialization which does nothing for the NOTYPE default template parameters of \ref WPropertyStruct.
00140  */
00141 template<>
00142 struct WPropertyGroupBase::PropertyCreatorAndGroupAdder< WPropertyStructHelper::NOTYPE >
00143 {
00144     /**
00145      * The type of the initial value.
00146      */
00147     typedef WPropertyStructHelper::NOTYPE ValueType;
00148 
00149     /**
00150      * Dummy method which does nothing for NOTYPE types.
00151      */
00152     static void createAndAdd( WPropertyGroupBase*, std::string, std::string, const ValueType& )
00153     {
00154         // NOTYPE will not cause any property creation.
00155     }
00156 
00157     /**
00158      * Dummy method which does nothing for NOTYPE types.
00159      */
00160     static void createAndAdd( WPropertyGroupBase*, std::string, std::string )
00161     {
00162         // NOTYPE will not cause any property creation.
00163     }
00164 };
00165 
00166 
00167 /**
00168  *  This is a property which encapsulates a given, fixed number of other properties. You can specify up to 10 properties. This can be seen
00169  *  similar to the "struct" in the C++ language. A WPropertyStruct can basically seen as \ref WPropertyGroup, but is different in a certain way:
00170  *  it is fixed size (defined on compile time), it allows getting each property with their correct type and provides the appearance as if this
00171  *  property is only ONE object and not a group of multiple objects.
00172  *
00173  *  \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.
00174  *  \note if we use C++11 some day, we could use variadic templates here.
00175  *
00176  * \tparam T0 first type. Mandatory.
00177  * \tparam T1 additional type. Optional.
00178  * \tparam T2 additional type. Optional.
00179  * \tparam T3 additional type. Optional.
00180  * \tparam T4 additional type. Optional.
00181  * \tparam T5 additional type. Optional.
00182  * \tparam T6 additional type. Optional.
00183  * \tparam T7 additional type. Optional.
00184  * \tparam T8 additional type. Optional.
00185  * \tparam T9 additional type. Optional.
00186  */
00187 template<
00188     typename T0,
00189     typename T1 = WPropertyStructHelper::NOTYPE,
00190     typename T2 = WPropertyStructHelper::NOTYPE,
00191     typename T3 = WPropertyStructHelper::NOTYPE,
00192     typename T4 = WPropertyStructHelper::NOTYPE,
00193     typename T5 = WPropertyStructHelper::NOTYPE,
00194     typename T6 = WPropertyStructHelper::NOTYPE,
00195     typename T7 = WPropertyStructHelper::NOTYPE,
00196     typename T8 = WPropertyStructHelper::NOTYPE,
00197     typename T9 = WPropertyStructHelper::NOTYPE
00198 >
00199 class WPropertyStruct: public WPropertyGroupBase
00200 {
00201 friend class WPropertyStructTest;
00202 public:
00203    /**
00204     * The type of this template instantiation.
00205     */
00206     typedef WPropertyStruct< BOOST_PP_ENUM_PARAMS( 10, T ) > WPropertyStructType;
00207 
00208     /**
00209      * Convenience typedef for a boost::shared_ptr< WPropertyStructType >
00210      */
00211     typedef typename boost::shared_ptr< WPropertyStructType > SPtr;
00212 
00213     /**
00214      * Convenience typedef for a  boost::shared_ptr< const WPropertyStructType >
00215      */
00216     typedef typename boost::shared_ptr< const WPropertyStructType > ConstSPtr;
00217 
00218     /**
00219      * The boost mpl vector for all the types specified.
00220      */
00221     typedef typename WPropertyStructHelper::AsVector< BOOST_PP_ENUM_PARAMS( 10, T ) >::type TypeVector;
00222 
00223     /**
00224      * The type vector as a boost tuple.
00225      */
00226     typedef typename WPropertyStructHelper::SequenceToTuple< TypeVector >::type TupleType;
00227 
00228     /**
00229      * Create an empty named property.
00230      *
00231      * \param name  the name of the property
00232      * \param description the description of the property
00233      */
00234     WPropertyStruct( std::string name, std::string description ):
00235         WPropertyGroupBase( name, description )
00236     {
00237         // now create the property instances
00238         PropertyCreatorAndGroupAdder< T0 >::createAndAdd( this, name + "_Prop0", "No description for Property 0 in struct \"" + name + "\"." );
00239         PropertyCreatorAndGroupAdder< T1 >::createAndAdd( this, name + "_Prop1", "No description for Property 1 in struct \"" + name + "\"." );
00240         PropertyCreatorAndGroupAdder< T2 >::createAndAdd( this, name + "_Prop2", "No description for Property 2 in struct \"" + name + "\"." );
00241         PropertyCreatorAndGroupAdder< T3 >::createAndAdd( this, name + "_Prop3", "No description for Property 3 in struct \"" + name + "\"." );
00242         PropertyCreatorAndGroupAdder< T4 >::createAndAdd( this, name + "_Prop4", "No description for Property 4 in struct \"" + name + "\"." );
00243         PropertyCreatorAndGroupAdder< T5 >::createAndAdd( this, name + "_Prop5", "No description for Property 5 in struct \"" + name + "\"." );
00244         PropertyCreatorAndGroupAdder< T6 >::createAndAdd( this, name + "_Prop6", "No description for Property 6 in struct \"" + name + "\"." );
00245         PropertyCreatorAndGroupAdder< T7 >::createAndAdd( this, name + "_Prop7", "No description for Property 7 in struct \"" + name + "\"." );
00246         PropertyCreatorAndGroupAdder< T8 >::createAndAdd( this, name + "_Prop8", "No description for Property 8 in struct \"" + name + "\"." );
00247         PropertyCreatorAndGroupAdder< T9 >::createAndAdd( this, name + "_Prop9", "No description for Property 9 in struct \"" + name + "\"." );
00248     }
00249 
00250     /**
00251      * Copy constructor. Creates a deep copy of this property. As boost::signals2 and condition variables are non-copyable, new instances get
00252      * created. The subscriptions to a signal are LOST as well as all listeners to a condition.
00253      *
00254      * \param from the instance to copy.
00255      */
00256     explicit WPropertyStruct( const WPropertyStructType& from ):
00257         WPropertyGroupBase( from )
00258     {
00259         // this created a NEW update condition and NEW property instances (clones)
00260     }
00261 
00262     /**
00263      * Destructor.
00264      */
00265     virtual ~WPropertyStruct()
00266     {
00267         // the storing tuple is destroyed automatically and the properties if not used anymore
00268     }
00269 
00270     /**
00271      * Get the N'th property in the struct.
00272      *
00273      * \tparam N the number of the property to get.
00274      *
00275      * \return the property.
00276      */
00277     template< int N >
00278     typename boost::mpl::at< TypeVector, boost::mpl::size_t< N > >::type getProperty()
00279     {
00280         typedef typename boost::mpl::at< TypeVector, boost::mpl::size_t< N > >::type::element_type TargetType;
00281         return boost::dynamic_pointer_cast< TargetType >( getProperty( N ) );
00282     }
00283 
00284     /**
00285      * Get the N'th property in the struct.
00286      *
00287      * \tparam N the number of the property to get.
00288      *
00289      * \return the property.
00290      */
00291     template< int N >
00292     typename boost::mpl::at< TypeVector, boost::mpl::size_t< N > >::type::element_type::ConstSPtr getProperty() const
00293     {
00294         typedef typename boost::mpl::at< TypeVector, boost::mpl::size_t< N > >::type::element_type TargetType;
00295         return boost::dynamic_pointer_cast< const TargetType >( getProperty( N ) );
00296     }
00297 
00298     /**
00299      * Returns the property with the given number, but only as base type. The advantage is that the property number can be specified during
00300      * runtime.
00301      *
00302      * \param n the number of the property
00303      *
00304      * \return the property
00305      */
00306     const WPropertyBase::SPtr& getProperty( size_t n ) const
00307     {
00308        // lock, unlocked if l looses focus
00309         PropertySharedContainerType::ReadTicket l = m_properties.getReadTicket();
00310         return l->get()[ n ];
00311     }
00312 
00313     /**
00314      * Returns the property with the given number, but only as base type. The advantage is that the property number can be specified during
00315      * runtime.
00316      *
00317      * \param n the number of the property
00318      *
00319      * \return the property
00320      */
00321     WPropertyBase::SPtr getProperty( size_t n )
00322     {
00323        // lock, unlocked if l looses focus
00324         PropertySharedContainerType::ReadTicket l = m_properties.getReadTicket();
00325         return l->get()[ n ];
00326     }
00327 
00328     /**
00329      * The size of the WPropertyStruct. This returns the number of properties encapsulated.
00330      *
00331      * \return number of properties in struct
00332      */
00333     size_t size() const
00334     {
00335         return m_size;
00336     }
00337 
00338     /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
00339     // The WPropertyBase specific stuff
00340     /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
00341 
00342     /**
00343      * 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
00344      * correct type without explicitly requiring the user to specify it. It creates a NEW change condition and change signal. This means, alls
00345      * subscribed signal handlers are NOT copied.
00346      *
00347      * \note this simply ensures the copy constructor of the runtime type is issued.
00348      *
00349      * \return the deep clone of this property.
00350      */
00351     virtual WPropertyBase::SPtr clone()
00352     {
00353         // just use the copy constructor
00354         return typename WPropertyStructType::SPtr( new WPropertyStructType( *this ) );
00355     }
00356 
00357     /**
00358      * Gets the real WPropertyVariable type of this instance.
00359      *
00360      * \return the real type.
00361      */
00362     virtual PROPERTY_TYPE getType() const
00363     {
00364         return PV_STRUCT;
00365     }
00366 
00367     /**
00368      * 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
00369      * real type of the property is unknown. This is a shortcut for casting the property and then setting the lexically casted value.
00370      *
00371      * \param value the new value to set.
00372      *
00373      * \return true if value could be set.
00374      */
00375     virtual bool setAsString( std::string value )
00376     {
00377         // this method splits the given string and simply forwards the call to the other properties
00378         std::vector< std::string > propsAsString = string_utils::tokenize( value, "|", false );
00379         if( size() != propsAsString.size() )
00380         {
00381             return false;
00382         }
00383 
00384         // lock, unlocked if l looses focus
00385         PropertySharedContainerType::ReadTicket l = m_properties.getReadTicket();
00386         // give the string to each property
00387         size_t curPropNb = 0;
00388         bool success = true;
00389         for( std::vector< std::string >::const_iterator iter = propsAsString.begin(); iter != propsAsString.end(); ++iter )
00390         {
00391             success = success && l->get()[ curPropNb ]->setAsString( *iter );
00392             curPropNb++;
00393         }
00394         return success;
00395     }
00396 
00397     /**
00398      * Returns the current value as a string. This is useful for debugging or project files. It is not implemented as << operator, since the <<
00399      * should also print min/max constraints and so on. This simply is the value.
00400      *
00401      * \return the value as a string.
00402      */
00403     virtual std::string getAsString()
00404     {
00405         // lock, unlocked if l looses focus
00406         PropertySharedContainerType::ReadTicket l = m_properties.getReadTicket();
00407 
00408         // go through and append each prop
00409         std::string result = "";
00410         for( size_t i = 0; i < size(); ++i )
00411         {
00412             result += l->get()[ i ]->getAsString() + "|";
00413         }
00414         // strip last "|"
00415         result.erase( result.length() - 1, 1 );
00416         return result;
00417     }
00418 
00419     /**
00420      * Sets the value from the specified property to this one. This is especially useful to copy a value without explicitly casting/knowing the
00421      * dynamic type of the property.
00422      *
00423      * \param value the new value.
00424      * \param recommendedOnly if true, property types which support recommended values apply the given value as recommendation.
00425      *
00426      * \return true if the value has been accepted.
00427      */
00428     virtual bool set( boost::shared_ptr< WPropertyBase > value, bool recommendedOnly = false )
00429     {
00430         // is this the same type as we are?
00431         typename WPropertyStructType::SPtr v = boost::dynamic_pointer_cast< WPropertyStructType >( value );
00432         if( !v )
00433         {
00434             // it is not a WPropertyStruct with the same type
00435             return false;
00436         }
00437 
00438         // lock, unlocked if l looses focus
00439         PropertySharedContainerType::ReadTicket l = m_properties.getReadTicket();
00440         PropertySharedContainerType::ReadTicket lother = v->m_properties.getReadTicket();
00441         bool success = true;
00442         // set each property
00443         for( size_t curPropNb = 0; curPropNb < size(); ++curPropNb )
00444         {
00445             success = success && l->get()[ curPropNb ]->set( lother->get()[ curPropNb ], recommendedOnly );
00446         }
00447 
00448         return success;
00449     }
00450 
00451 protected:
00452 private:
00453     /**
00454      * How many elements are in this WPropertyStruct?
00455      */
00456     static const size_t m_size = boost::mpl::size< TypeVector >::value;
00457 };
00458 
00459 #endif  // WPROPERTYSTRUCT_H
00460