Orocos Real-Time Toolkit  2.5.0
PropertyDecomposition.cpp
00001 /***************************************************************************
00002   tag: The SourceWorks  Tue Sep 7 00:55:18 CEST 2010  PropertyDecomposition.cpp
00003 
00004                         PropertyDecomposition.cpp -  description
00005                            -------------------
00006     begin                : Tue September 07 2010
00007     copyright            : (C) 2010 The SourceWorks
00008     email                : peter@thesourceworks.com
00009 
00010  ***************************************************************************
00011  *   This library is free software; you can redistribute it and/or         *
00012  *   modify it under the terms of the GNU General Public                   *
00013  *   License as published by the Free Software Foundation;                 *
00014  *   version 2 of the License.                                             *
00015  *                                                                         *
00016  *   As a special exception, you may use this file as part of a free       *
00017  *   software library without restriction.  Specifically, if other files   *
00018  *   instantiate templates or use macros or inline functions from this     *
00019  *   file, or you compile this file and link it with other files to        *
00020  *   produce an executable, this file does not by itself cause the         *
00021  *   resulting executable to be covered by the GNU General Public          *
00022  *   License.  This exception does not however invalidate any other        *
00023  *   reasons why the executable file might be covered by the GNU General   *
00024  *   Public License.                                                       *
00025  *                                                                         *
00026  *   This library is distributed in the hope that it will be useful,       *
00027  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00028  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00029  *   Lesser General Public License for more details.                       *
00030  *                                                                         *
00031  *   You should have received a copy of the GNU General Public             *
00032  *   License along with this library; if not, write to the Free Software   *
00033  *   Foundation, Inc., 59 Temple Place,                                    *
00034  *   Suite 330, Boston, MA  02111-1307  USA                                *
00035  *                                                                         *
00036  ***************************************************************************/
00037 
00038 
00046 #include "PropertyDecomposition.hpp"
00047 #include "../internal/DataSource.hpp"
00048 #include <vector>
00049 #include <string>
00050 #include <memory>
00051 #include <boost/lexical_cast.hpp>
00052 #include "../Logger.hpp"
00053 #include "TypeInfo.hpp"
00054 #include "../Property.hpp"
00055 
00056 
00057 using namespace std;
00058 using namespace RTT;
00059 using namespace RTT::detail;
00060 
00061 namespace RTT { namespace types {
00062 
00063 bool propertyDecomposition( base::PropertyBase* source, PropertyBag& targetbag, bool recurse )
00064 {
00065     if (!source)
00066         return false;
00067     DataSourceBase::shared_ptr dsb = source->getDataSource();
00068     if (!dsb)
00069         return false;
00070     return typeDecomposition( dsb, targetbag, recurse);
00071 }
00072 
00073 bool typeDecomposition( base::DataSourceBase::shared_ptr dsb, PropertyBag& targetbag, bool recurse)
00074 {
00075     if (!dsb)
00076         return false;
00077 
00078     // try user's custom type decomposition first:
00079     DataSourceBase::shared_ptr decomposed = dsb->getTypeInfo()->decomposeType(dsb);
00080     if (decomposed) {
00081         // decomposed is or another type, or a PropertyBag
00082         internal::AssignableDataSource<PropertyBag>::shared_ptr bag = internal::AssignableDataSource<PropertyBag>::narrow( decomposed.get() );
00083         if ( bag ) {
00084             // get it and copy it.
00085             targetbag = bag->rvalue();
00086             return true;
00087         } else {
00088             // it converted to something else than a bag.
00089             // In cases where decomposeType() returned dsb itself, we stop the decomposition here.
00090             //log(Debug) << "propertyDecomposition: decomposeType() of "<<  dsb->getTypeName() << " did not return a PropertyBag but a " << decomposed->getTypeName() << endlog();
00091             return false;
00092         }
00093     }
00094 
00095     vector<string> parts = dsb->getMemberNames();
00096     if ( parts.empty() ) {
00097         log(Debug) << "propertyDecomposition: "<<  dsb->getTypeName() << " does not have any members." << endlog();
00098         return false;
00099     }
00100 
00101     targetbag.setType( dsb->getTypeName() );
00102 
00103     // needed for recursion.
00104     auto_ptr< Property<PropertyBag> > recurse_bag( new Property<PropertyBag>("recurse_bag","Part") );
00105     // First at the explicitly listed parts:
00106     for(vector<string>::iterator it = parts.begin(); it != parts.end(); ++it ) {
00107         DataSourceBase::shared_ptr part = dsb->getMember( *it );
00108         if (!part) {
00109             log(Error) <<"propertyDecomposition: Inconsistent type info for "<< dsb->getTypeName() << ": reported to have part '"<<*it<<"' but failed to return it."<<endlog();
00110             continue;
00111         }
00112         if ( !part->isAssignable() ) {
00113             // For example: the case for size() and capacity() in SequenceTypeInfo
00114             log(Debug)<<"propertyDecomposition: Part "<< *it << ":"<< part->getTypeName() << " is not changeable."<<endlog();
00115             continue;
00116         }
00117         // finally recurse or add it to the target bag:
00118         PropertyBase* newpb = part->getTypeInfo()->buildProperty(*it,"Part",part);
00119         if ( !newpb ) {
00120             log(Error)<< "Decomposition failed because Part '"<<*it<<"' is not known to type system."<<endlog();
00121             continue;
00122         }
00123         if ( !recurse || !propertyDecomposition( newpb, recurse_bag->value(), true) ) {
00124             assert( recurse_bag->value().empty() );
00125             targetbag.ownProperty( newpb ); // leaf
00126         } else {
00127             recurse_bag->setName(*it);
00128             // setType() is done by recursive of self.
00129             targetbag.ownProperty( recurse_bag.release() ); //recursed.
00130             recurse_bag.reset( new Property<PropertyBag>("recurse_bag","Part") );
00131             delete newpb; // since we recursed, the recurse_bag now 'embodies' newpb.
00132         }
00133     }
00134 
00135     // Prepare recurse_bag for storing composite items:
00136     recurse_bag->setDescription("Item");
00137 
00138     // Next get the numbered parts:
00139     DataSource<int>::shared_ptr size = DataSource<int>::narrow( dsb->getMember("size").get() );
00140     if (size) {
00141         int msize = size->get();
00142         for (int i=0; i < msize; ++i) {
00143             string indx = boost::lexical_cast<string>( i );
00144             DataSourceBase::shared_ptr item = dsb->getMember(indx);
00145             if (item) {
00146                 if ( !item->isAssignable() ) {
00147                     // For example: the case for size() and capacity() in SequenceTypeInfo
00148                     log(Warning)<<"propertyDecomposition: Item '"<< indx << "' of type "<< dsb->getTypeName() << " is not changeable."<<endlog();
00149                     continue;
00150                 }
00151                 // finally recurse or add it to the target bag:
00152                 PropertyBase* newpb = item->getTypeInfo()->buildProperty( "Element" + indx,"Sequence Element",item);
00153                 if ( !recurse || !propertyDecomposition( newpb, recurse_bag->value()) ) {
00154                     targetbag.ownProperty( newpb ); // leaf
00155                 } else {
00156                     delete newpb;
00157                     recurse_bag->setName( "Element" + indx );
00158                     // setType() is done by recursive of self.
00159                     targetbag.ownProperty( recurse_bag.release() ); //recursed.
00160                     recurse_bag.reset( new Property<PropertyBag>("recurse_bag","Item") );
00161                 }
00162             }
00163         }
00164     }
00165     if (targetbag.empty() )
00166         log(Debug) << "propertyDecomposition: "<<  dsb->getTypeName() << " returns an empty property bag." << endlog();
00167     return true;
00168 }
00169 
00170 }}