ISIS Core Library 0.7.2 (api 3.0.0)

/scr/tee1/isis/lib/Core/CoreUtils/value_converter.cpp

Go to the documentation of this file.
00001 /*
00002     <one line to give the program's name and a brief idea of what it does.>
00003     Copyright (C) <year>  <name of author>
00004 
00005     This program is free software: you can redistribute it and/or modify
00006     it under the terms of the GNU General Public License as published by
00007     the Free Software Foundation, either version 3 of the License, or
00008     (at your option) any later version.
00009 
00010     This program is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013     GNU General Public License for more details.
00014 
00015     You should have received a copy of the GNU General Public License
00016     along with this program.  If not, see <http://www.gnu.org/licenses/>.
00017 
00018 */
00019 
00020 #ifdef _MSC_VER
00021 #pragma warning(disable:4800 4996)
00022 #endif
00023 
00024 #include "value_converter.hpp"
00025 #include "value_base.hpp"
00026 #include "value.hpp"
00027 #include <boost/mpl/for_each.hpp>
00028 #include <boost/type_traits/is_arithmetic.hpp>
00029 #include <boost/mpl/and.hpp>
00030 
00031 // @todo we need to know this for lexical_cast (toString)
00032 #include <boost/date_time/gregorian/gregorian.hpp>
00033 #include <boost/date_time/posix_time/posix_time.hpp>
00034 
00035 #include <complex>
00036 
00037 
00039 namespace isis
00040 {
00041 namespace util
00042 {
00043 API_EXCLUDE_BEGIN
00044 namespace _internal
00045 {
00046 
00047 //Define generator - this can be global because its using convert internally
00048 template<typename SRC, typename DST> class ValueGenerator: public ValueConverterBase
00049 {
00050 public:
00051     void create( boost::scoped_ptr<ValueBase>& dst )const {
00052         LOG_IF( dst.get(), Debug, error ) << "Generating into existing value " << dst->toString( true ) << " (dropping this).";
00053         Value<DST> *ref = new Value<DST>;
00054         dst.reset( ref );
00055     }
00056     boost::numeric::range_check_result generate( const ValueBase &src, boost::scoped_ptr<ValueBase>& dst )const {
00057         create( dst );
00058         assert( dst );
00059         const boost::numeric::range_check_result result = convert( src.castToType<SRC>(), *dst );
00060         return result;
00061     }
00062 };
00063 
00065 // general converter version -- does nothing
00067 template<bool NUMERIC, bool SAME, typename SRC, typename DST> class ValueConverter : public ValueGenerator<SRC, DST>
00068 {
00069 public:
00070     //uncomment this to see which conversions are not generated - be carefull, thats f***king much
00071     /*  static boost::shared_ptr<const ValueConverterBase> get() {
00072             std::cout <<
00073                 "There will be no " << (SAME?"copy":NUMERIC?"numeric":"non-numeric") <<  " conversion for " <<
00074                 util::Value<SRC>::staticName() << " to " << util::Value<DST>::staticName() << std::endl;
00075             return boost::shared_ptr<const ValueConverterBase>();
00076         }*/
00077     virtual ~ValueConverter() {}
00078 };
00080 // trivial version -- for conversion of the same type
00082 template<bool NUMERIC, typename SRC, typename DST> class ValueConverter<NUMERIC, true, SRC, DST> : public ValueGenerator<SRC, DST>
00083 {
00084     ValueConverter() {
00085         LOG( Debug, verbose_info )
00086                 << "Creating trivial copy converter for " << Value<SRC>::staticName();
00087     };
00088 public:
00089     static boost::shared_ptr<const ValueConverterBase> get() {
00090         ValueConverter<NUMERIC, true, SRC, DST> *ret = new ValueConverter<NUMERIC, true, SRC, DST>;
00091         return boost::shared_ptr<const ValueConverterBase>( ret );
00092     }
00093     boost::numeric::range_check_result convert( const ValueBase &src, ValueBase &dst )const {
00094         SRC &dstVal = dst.castTo<SRC>();
00095         const SRC &srcVal = src.castTo<SRC>();
00096         dstVal = srcVal;
00097         return boost::numeric::cInRange;
00098     }
00099     virtual ~ValueConverter() {}
00100 };
00101 
00103 // some helper
00105 
00106 // global numeric overflow handler @todo this is NOT thread-safe
00107 struct NumericOverflowHandler {
00108     static boost::numeric::range_check_result result;
00109     void operator() ( boost::numeric::range_check_result r ) { // throw bad_numeric_conversion derived
00110         result = r;
00111     }
00112 };
00113 boost::numeric::range_check_result NumericOverflowHandler::result = boost::numeric::cInRange;
00114 
00115 // basic numeric to numeric conversion (does runding and handles overlow)
00116 template<typename SRC, typename DST> boost::numeric::range_check_result num2num( const SRC &src, DST &dst )
00117 {
00118     typedef boost::numeric::converter <
00119     DST, SRC,
00120        boost::numeric::conversion_traits<DST, SRC>,
00121        NumericOverflowHandler,
00122        boost::numeric::RoundEven<SRC>
00123        > converter;
00124     NumericOverflowHandler::result = boost::numeric::cInRange;
00125     dst = converter::convert( src );
00126     return NumericOverflowHandler::result;
00127 }
00128 
00129 template<typename DST> boost::numeric::range_check_result str2scalar( const std::string &src, DST &dst )
00130 {
00131     try {
00132         if( boost::is_arithmetic<DST>::value ) { // if a converter from double is available first map to double and then convert that into DST
00133             return num2num<double, DST>( Value<double>( src ), dst );
00134         } else { // otherwise try direct mapping (rounding will fail)
00135             LOG( Debug, warning ) << "using lexical_cast to convert from string to "
00136                                   << Value<DST>::staticName() << " no rounding can be done.";
00137             dst = boost::lexical_cast<DST>( src );
00138         }
00139     } catch( const boost::bad_lexical_cast & ) {
00140         dst = DST();
00141         LOG( Runtime, error ) << "Miserably failed to interpret " << MSubject( src ) << " as " << Value<DST>::staticName() << " returning " << MSubject( DST() );
00142     }
00143 
00144     return boost::numeric::cInRange;
00145 }
00146 //this is trivial
00147 template<> boost::numeric::range_check_result str2scalar<std::string>( const std::string &src, std::string &dst )
00148 {
00149     dst = src;
00150     return boost::numeric::cInRange;
00151 }
00152 // needs special handling
00153 template<> boost::numeric::range_check_result str2scalar<boost::posix_time::ptime>( const std::string &src, boost::posix_time::ptime &dst )
00154 {
00155     dst = boost::posix_time::time_from_string( src.c_str() ); //first try "2002-01-20 23:59:59.000"
00156 
00157     if( dst.is_not_a_date_time() ) // try iso formatting
00158         dst = boost::posix_time::from_iso_string( src.c_str() );
00159 
00160     LOG_IF( dst.is_not_a_date_time(), Runtime, error ) // if its still broken at least tell the user
00161             << "Miserably failed to interpret " << MSubject( src ) << " as " << Value<boost::posix_time::ptime>::staticName() << " returning " << MSubject( dst );
00162     return boost::numeric::cInRange;
00163 }
00164 template<> boost::numeric::range_check_result str2scalar<boost::gregorian::date>( const std::string &str, boost::gregorian::date &dst )
00165 {
00166     dst=boost::gregorian::date(boost::gregorian::not_a_date_time);
00167 
00168     // first try ISO format
00169     try{dst=boost::gregorian::date_from_iso_string(str);} catch(boost::bad_lexical_cast &e){
00170         LOG(Debug,verbose_info) << "Failed to parse " << util::MSubject(str) << " as iso date: " << e.what();
00171     }
00172     if(!dst.is_not_a_date())return boost::numeric::cInRange;
00173 
00174     // second try some default formats
00175     typedef boost::gregorian::date(*date_parser)(const std::string);
00176     const date_parser parsers[] = {boost::gregorian::from_simple_string,boost::gregorian::from_uk_string,boost::gregorian::from_us_string};
00177     
00178     BOOST_FOREACH(date_parser parser,parsers){
00179         try{dst=parser(str);} catch(std::out_of_range &e){
00180             LOG(Debug,verbose_info) << "Failed to parse " << util::MSubject(str) << " as date: " << e.what();
00181         }
00182         if(!dst.is_not_a_date())return boost::numeric::cInRange;
00183     }
00184 
00185     // last try try - stream io
00186     std::stringstream ss(str);ss >> dst;
00187     if(dst.is_not_a_date())
00188     {
00189         LOG(Debug,verbose_info) << "Failed to parse " << util::MSubject(str) << " using stream io";
00190     } else 
00191         return boost::numeric::cInRange;
00192     
00193     return boost::numeric::cPosOverflow;
00194 }
00195 // this as well (interpret everything like true/false yes/no y/n)
00196 template<> boost::numeric::range_check_result str2scalar<bool>( const std::string &src, bool &dst )
00197 {
00198     const std::string srcVal = boost::algorithm::to_lower_copy<std::string>( src );
00199 
00200     if (  srcVal == "true" || srcVal == "y" || srcVal == "yes" ) {
00201         dst = true;
00202     } else if ( srcVal == "false" || srcVal == "n" || srcVal == "no" ) {
00203         dst = false;
00204     } else {
00205         LOG( Runtime, warning ) << util::MSubject( src ) << " is ambiguous while converting to " << Value<bool>::staticName();
00206         return boost::numeric::cPosOverflow;
00207     }
00208 
00209     return boost::numeric::cInRange;
00210 }
00211 //and this (lexical_cast doesnt work here, because it creates a temporary buffer which will screw our dst)
00212 template<> boost::numeric::range_check_result str2scalar<Selection>( const std::string &src, Selection &dst )
00213 {
00214     if ( dst.set( src.c_str() ) )
00215         return boost::numeric::cInRange;
00216     else
00217         return boost::numeric::cPosOverflow; //if the string is not "part" of the selection we count this as positive overflow
00218 }
00219 
00220 template<bool IS_NUM> struct Tokenizer { //jump from number to number in the string ignoring anything else
00221     static std::list<std::string> run( const std::string &src ) {
00222         std::list<std::string> ret;
00223         const char *mask = "0123456789-eE.";
00224         const char *start_mask = "0123456789-";
00225 
00226         for( size_t i = src.find_first_of( start_mask ), end; i < std::string::npos; i = src.find_first_of( start_mask, end ) ) {
00227             end = src.find_first_not_of( mask, i );
00228             const std::string numstr = src.substr( i, end - i );
00229             ret.push_back( numstr );
00230         }
00231 
00232         return ret;
00233     }
00234 };
00235 template<> struct Tokenizer<false> { // not for numbers / tokenize string at spaces,"," and ";"
00236     static std::list<std::string> run( const std::string &src ) {
00237         return util::stringToList<std::string>( src, boost::regex( "[\\s,;]+" ) );
00238     }
00239 };
00240 
00241 template<typename DST> struct StrTransformer {
00242     boost::numeric::range_check_result range_ok;
00243     StrTransformer(): range_ok( boost::numeric::cInRange ) {}
00244     DST operator()( const std::string &src ) {
00245         DST ret;
00246         const boost::numeric::range_check_result result = str2scalar( src, ret );
00247 
00248         if( result != boost::numeric::cInRange )
00249             range_ok = result; // keep the first error
00250 
00251         return ret;
00252     }
00253 };
00254 
00255 //helper to convert strings to FixedVectors
00256 template<typename DST, int NUM> boost::numeric::range_check_result convertStr2Vector( const ValueBase &src, FixedVector<DST, NUM> &dstList )
00257 {
00258     const std::list<std::string> srcList = Tokenizer<boost::is_arithmetic<DST>::value>::run( src.castTo<std::string>() ); // tokenize the string based on the target type
00259     std::list< std::string >::const_iterator end = srcList.begin();
00260     std::advance( end, std::min<size_t>( srcList.size(), NUM ) ); // use a max of NUM tokens
00261     StrTransformer<DST> transformer; // create a transformer from string to DST
00262     std::transform( srcList.begin(), end, dstList.begin(), transformer ); // transform the found strings to the destination
00263     return transformer.range_ok;
00264 }
00265 
00266 // additional base for converters which use another converter
00267 template<typename SRC, typename DST> struct SubValueConv {
00268     boost::shared_ptr<const ValueConverterBase> sub_conv;
00269 };
00270 template<typename SRC, typename DST> struct IterableSubValueConv: SubValueConv<SRC, DST> {
00271     template<typename SRC_LST, typename DST_LST> boost::numeric::range_check_result
00272     convertIter2Iter( const SRC_LST &srcLst, DST_LST &dstLst )const {
00273         boost::numeric::range_check_result ret = boost::numeric::cInRange;
00274 
00275         typename SRC_LST::const_iterator srcAt = srcLst.begin(), srcEnd = srcLst.end();
00276         typename DST_LST::iterator dstBegin = dstLst.begin(), dstEnd = dstLst.end();
00277 
00278         while( srcAt != srcEnd ) { //slow and ugly, but flexible
00279 
00280             if( dstBegin != dstEnd ) {
00281                 Value<DST> elem_dst;
00282                 const boost::numeric::range_check_result result = SubValueConv<SRC, DST>::sub_conv->convert( Value<SRC>( *srcAt ), elem_dst );
00283 
00284                 if ( ret == boost::numeric::cInRange && result != boost::numeric::cInRange )
00285                     ret = result;
00286 
00287                 *( dstBegin++ ) = ( DST )elem_dst;
00288             } else if( *srcAt != SRC() )
00289                 return boost::numeric::cPosOverflow; // abort and send positive overflow if source wont fit into destination
00290 
00291             srcAt++;
00292         }
00293 
00294         return ret;
00295     }
00296 
00297 };
00298 template<typename CLASS, typename SRC, typename DST> static boost::shared_ptr<const ValueConverterBase> getFor()
00299 {
00300     typedef boost::mpl::and_<boost::is_arithmetic<SRC>, boost::is_arithmetic<DST> > is_num;
00301     typedef boost::is_same<SRC, DST> is_same;
00302     boost::shared_ptr<const ValueConverterBase> sub_conv = ValueConverter<is_num::value, is_same::value, SRC, DST>::get();
00303 
00304     if ( sub_conv ) {
00305         boost::shared_ptr<CLASS > ret( new CLASS );
00306         ret->sub_conv = sub_conv;
00307         return ret;
00308     } else {
00309         return boost::shared_ptr<const ValueConverterBase>();
00310     }
00311 }
00312 
00313 // special to string conversions
00314 template<typename T> std::string toStringConv( const T &src )
00315 {
00316     std::stringstream s;
00317     s << std::boolalpha << src; // bool will be converted to true/false
00318     return s.str();
00319 }
00320 template<> std::string toStringConv<uint8_t>( const uint8_t &src ) {return toStringConv( static_cast<uint16_t>( src ) );}
00321 template<> std::string toStringConv<int8_t> ( const  int8_t &src ) {return toStringConv( static_cast< int16_t>( src ) );}
00322 
00323 
00325 // Numeric version -- uses num2num
00327 template<typename SRC, typename DST> class ValueConverter<true, false, SRC, DST> : public ValueGenerator<SRC, DST>
00328 {
00329     ValueConverter() {
00330         LOG( Debug, verbose_info )
00331                 << "Creating numeric converter from "
00332                 << Value<SRC>::staticName() << " to " << Value<DST>::staticName();
00333     };
00334 public:
00335     static boost::shared_ptr<const ValueConverterBase> get() {
00336         ValueConverter<true, false, SRC, DST> *ret = new ValueConverter<true, false, SRC, DST>;
00337         return boost::shared_ptr<const ValueConverterBase>( ret );
00338     }
00339     boost::numeric::range_check_result convert( const ValueBase &src, ValueBase &dst )const {
00340         return num2num( src.castTo<SRC>(), dst.castTo<DST>() );
00341     }
00342     virtual ~ValueConverter() {}
00343 };
00344 
00346 // Conversion between complex numbers -- uses num2num
00348 template<typename SRC, typename DST> class ValueConverter<false, false, std::complex<SRC>, std::complex<DST> > : public ValueGenerator<std::complex<SRC>, std::complex<DST> >
00349 {
00350     ValueConverter() {
00351         LOG( Debug, verbose_info ) << "Creating complex-complex converter from " << Value<std::complex<SRC> >::staticName() << " to " << Value<std::complex<DST> >::staticName();
00352     };
00353 public:
00354     static boost::shared_ptr<const ValueConverterBase> get() {
00355         ValueConverter<false, false, std::complex<SRC>, std::complex<DST> > *ret = new ValueConverter<false, false, std::complex<SRC>, std::complex<DST> >;
00356         return boost::shared_ptr<const ValueConverterBase>( ret );
00357     }
00358     boost::numeric::range_check_result convert( const ValueBase &src, ValueBase &dst )const {
00359         return num2num( src.castTo<std::complex<SRC> >(), dst.castTo<std::complex<DST> >() );
00360     }
00361     virtual ~ValueConverter() {}
00362 };
00363 
00365 // Conversion between color -- uses num2num
00367 template<typename SRC, typename DST> class ValueConverter<false, false, color<SRC>, color<DST> > : public ValueGenerator<color<SRC>, color<DST> >
00368 {
00369     ValueConverter() {
00370         LOG( Debug, verbose_info ) << "Creating color converter from " << Value<color<SRC> >::staticName() << " to " << Value<color<DST> >::staticName();
00371     };
00372 public:
00373     static boost::shared_ptr<const ValueConverterBase> get() {
00374         ValueConverter<false, false, color<SRC>, color<DST>  > *ret = new ValueConverter<false, false, color<SRC>, color<DST>  >;
00375         return boost::shared_ptr<const ValueConverterBase>( ret );
00376     }
00377     boost::numeric::range_check_result convert( const ValueBase &src, ValueBase &dst )const {
00378         boost::numeric::range_check_result res = boost::numeric::cInRange;
00379         const SRC *srcVal = &src.castTo<color<SRC> >().r;
00380         DST *dstVal = &dst.castTo<color<DST> >().r;
00381 
00382         for( uint_fast8_t i = 0; i < 3; i++ ) {
00383             const boost::numeric::range_check_result result = num2num( srcVal[i], dstVal[i] );
00384 
00385             if( result != boost::numeric::cInRange )res = result;
00386         }
00387 
00388         return res;
00389     }
00390     virtual ~ValueConverter() {}
00391 };
00392 
00394 // Conversion for "all" to complex numbers -- uses ValueConverter on the real part
00396 template<typename SRC, typename DST> class ValueConverter<false, false, SRC, std::complex<DST> > :
00397     public ValueGenerator<SRC, std::complex<DST> >, private SubValueConv<SRC, DST >
00398 {
00399     ValueConverter( ) {
00400         LOG( Debug, verbose_info )
00401                 << "Creating number-complex converter from "
00402                 << Value<SRC>::staticName() << " to " << Value<std::complex<DST> >::staticName();
00403     };
00404     friend boost::shared_ptr<const ValueConverterBase> getFor<ValueConverter<false, false, SRC, std::complex<DST> >, SRC, DST >();
00405 public:
00406     static boost::shared_ptr<const ValueConverterBase> get() {
00407         return getFor<ValueConverter<false, false, SRC, std::complex<DST> >, SRC, DST >();
00408     }
00409     boost::numeric::range_check_result convert( const ValueBase &src, ValueBase &dst )const {
00410         std::complex<DST> &dstVal = dst.castTo<std::complex<DST> >();
00411         Value<DST> real;
00412         boost::numeric::range_check_result ret = this->sub_conv->convert( src, real );
00413 
00414         if( ret == boost::numeric::cInRange )
00415             dstVal = std::complex<DST>( ( DST )real, DST() );
00416 
00417         return ret;
00418     }
00419     virtual ~ValueConverter() {}
00420 };
00421 
00422 
00424 // vectorX to vectorX version -- uses IterableSubValueConv::convertIter2Iter
00426 // vector4 => vector4
00427 template<typename SRC, typename DST > class ValueConverter<false, false, vector4<SRC>, vector4<DST> >:
00428     public ValueGenerator<vector4<SRC>, vector4<DST> >, private IterableSubValueConv<SRC, DST >
00429 {
00430     ValueConverter( ) {
00431         LOG( Debug, verbose_info ) << "Creating vector converter from " << Value<vector4<SRC> >::staticName() << " to " << Value<vector4<DST> >::staticName();
00432     };
00433     friend boost::shared_ptr<const ValueConverterBase> getFor<ValueConverter<false, false, vector4<SRC>, vector4<DST> >, SRC, DST>();
00434 public:
00435     static boost::shared_ptr<const ValueConverterBase> get() {
00436         return getFor<ValueConverter<false, false, vector4<SRC>, vector4<DST> >, SRC, DST>();
00437     }
00438     boost::numeric::range_check_result convert( const ValueBase &src, ValueBase &dst )const {
00439         return IterableSubValueConv<SRC, DST >::convertIter2Iter( src.castTo<vector4<SRC> >(), dst.castTo<vector4<DST> >() );
00440     }
00441     virtual ~ValueConverter() {}
00442 };
00443 // vector3 => vector4
00444 template<typename SRC, typename DST > class ValueConverter<false, false, vector3<SRC>, vector4<DST> >:
00445     public ValueGenerator<vector3<SRC>, vector4<DST> >, private IterableSubValueConv<SRC, DST >
00446 {
00447     ValueConverter( ) {
00448         LOG( Debug, verbose_info ) << "Creating vector converter from " << Value<vector3<SRC> >::staticName() << " to " << Value<vector4<DST> >::staticName();
00449     };
00450     friend boost::shared_ptr<const ValueConverterBase> getFor<ValueConverter<false, false, vector3<SRC>, vector4<DST> >, SRC, DST>();
00451 public:
00452     static boost::shared_ptr<const ValueConverterBase> get() {
00453         return getFor<ValueConverter<false, false, vector3<SRC>, vector4<DST> >, SRC, DST>();
00454     }
00455     boost::numeric::range_check_result convert( const ValueBase &src, ValueBase &dst )const {
00456         return IterableSubValueConv<SRC, DST >::convertIter2Iter( src.castTo<vector3<SRC> >(), dst.castTo<vector4<DST> >() );
00457     }
00458     virtual ~ValueConverter() {}
00459 };
00460 // vector4 => vector3
00461 template<typename SRC, typename DST > class ValueConverter<false, false, vector4<SRC>, vector3<DST> >:
00462     public ValueGenerator<vector4<SRC>, vector3<DST> >, private IterableSubValueConv<SRC, DST >
00463 {
00464     ValueConverter( ) {
00465         LOG( Debug, verbose_info ) << "Creating vector converter from " << Value<vector4<SRC> >::staticName() << " to " << Value<vector3<DST> >::staticName();
00466     };
00467     friend boost::shared_ptr<const ValueConverterBase> getFor<ValueConverter<false, false, vector4<SRC>, vector3<DST> >, SRC, DST>();
00468 public:
00469     static boost::shared_ptr<const ValueConverterBase> get() {
00470         return getFor<ValueConverter<false, false, vector4<SRC>, vector3<DST> >, SRC, DST>();
00471     }
00472     boost::numeric::range_check_result convert( const ValueBase &src, ValueBase &dst )const {
00473         return IterableSubValueConv<SRC, DST >::convertIter2Iter( src.castTo<vector4<SRC> >(), dst.castTo<vector3<DST> >() );
00474     }
00475     virtual ~ValueConverter() {}
00476 };
00477 // vector3 => vector3
00478 template<typename SRC, typename DST > class ValueConverter<false, false, vector3<SRC>, vector3<DST> >:
00479     public ValueGenerator<vector3<SRC>, vector3<DST> >, private IterableSubValueConv<SRC, DST >
00480 {
00481     ValueConverter( ) {
00482         LOG( Debug, verbose_info ) << "Creating vector converter from " << Value<vector3<SRC> >::staticName() << " to " << Value<vector3<DST> >::staticName();
00483     };
00484     friend boost::shared_ptr<const ValueConverterBase> getFor<ValueConverter<false, false, vector3<SRC>, vector3<DST> >, SRC, DST>();
00485 public:
00486     static boost::shared_ptr<const ValueConverterBase> get() {
00487         return getFor<ValueConverter<false, false, vector3<SRC>, vector3<DST> >, SRC, DST>();
00488     }
00489     boost::numeric::range_check_result convert( const ValueBase &src, ValueBase &dst )const {
00490         return IterableSubValueConv<SRC, DST >::convertIter2Iter( src.castTo<vector3<SRC> >(), dst.castTo<vector3<DST> >() );
00491     }
00492     virtual ~ValueConverter() {}
00493 };
00494 
00496 // list to list version -- uses IterableSubValueConv::convertIter2Iter
00498 template<typename SRC, typename DST > class ValueConverter<false, false, std::list<SRC>, std::list<DST> >:
00499     public ValueGenerator<std::list<SRC>, std::list<DST> >, private IterableSubValueConv<SRC, DST >
00500 {
00501     ValueConverter() {
00502         LOG( Debug, verbose_info ) << "Creating list converter from " << Value<std::list<SRC> >::staticName() << " to " << Value<std::list<DST> >::staticName();
00503     };
00504     friend boost::shared_ptr<const ValueConverterBase> getFor<ValueConverter<false, false, std::list<SRC>, std::list<DST> >, SRC, DST>();
00505 public:
00506     static boost::shared_ptr<const ValueConverterBase> get() {
00507         return getFor<ValueConverter<false, false, std::list<SRC>, std::list<DST> >, SRC, DST>();
00508     }
00509     boost::numeric::range_check_result convert( const ValueBase &src, ValueBase &dst )const {
00510         std::list<DST> &dstVal = dst.castTo<std::list<DST> >();
00511         LOG_IF( ! dstVal.empty(), CoreLog, warning )
00512                 << "Storing into non empty list while conversion from "
00513                 << Value<std::list<SRC> >::staticName() << " to " << Value<std::list<DST> >::staticName();
00514         const std::list<SRC> &srcVal = src.castTo<std::list<SRC> >();
00515         dstVal.resize( srcVal.size() );
00516 
00517         return IterableSubValueConv<SRC, DST >::convertIter2Iter( srcVal, dstVal );
00518     }
00519     virtual ~ValueConverter() {}
00520 };
00522 // vectorX to list version -- uses IterableSubValueConv::convertIter2Iter
00524 template<typename SRC, typename DST > class ValueConverter<false, false, util::vector3<SRC>, std::list<DST> >:
00525     public ValueGenerator<util::vector3<SRC>, std::list<DST> >, private IterableSubValueConv<SRC, DST >
00526 {
00527     ValueConverter() {
00528         LOG( Debug, verbose_info ) << "Creating list converter from " << Value<util::vector3<SRC> >::staticName() << " to " << Value<std::list<DST> >::staticName();
00529     };
00530     friend boost::shared_ptr<const ValueConverterBase> getFor<ValueConverter<false, false, util::vector3<SRC>, std::list<DST> >, SRC, DST>();
00531 public:
00532     static boost::shared_ptr<const ValueConverterBase> get() {
00533         return getFor<ValueConverter<false, false, util::vector3<SRC>, std::list<DST> >, SRC, DST>();
00534     }
00535     boost::numeric::range_check_result convert( const ValueBase &src, ValueBase &dst )const {
00536         std::list<DST> &dstVal = dst.castTo<std::list<DST> >();
00537         LOG_IF( ! dstVal.empty(), CoreLog, warning ) << "Storing into non empty list while conversion from " << Value<util::vector3<SRC> >::staticName() << " to " << Value<std::list<DST> >::staticName();
00538         dstVal.resize( 3 );
00539 
00540         return IterableSubValueConv<SRC, DST >::convertIter2Iter( src.castTo<util::vector3<SRC> >(), dstVal );
00541     }
00542     virtual ~ValueConverter() {}
00543 };
00544 template<typename SRC, typename DST > class ValueConverter<false, false, util::vector4<SRC>, std::list<DST> >:
00545     public ValueGenerator<util::vector4<SRC>, std::list<DST> >, private IterableSubValueConv<SRC, DST >
00546 {
00547     ValueConverter() {
00548         LOG( Debug, verbose_info ) << "Creating list converter from " << Value<util::vector4<SRC> >::staticName() << " to " << Value<std::list<DST> >::staticName();
00549     };
00550     friend boost::shared_ptr<const ValueConverterBase> getFor<ValueConverter<false, false, util::vector4<SRC>, std::list<DST> >, SRC, DST>();
00551 public:
00552     static boost::shared_ptr<const ValueConverterBase> get() {
00553         return getFor<ValueConverter<false, false, util::vector4<SRC>, std::list<DST> >, SRC, DST>();
00554     }
00555     boost::numeric::range_check_result convert( const ValueBase &src, ValueBase &dst )const {
00556         std::list<DST> &dstVal = dst.castTo<std::list<DST> >();
00557         LOG_IF( ! dstVal.empty(), CoreLog, warning ) << "Storing into non empty list while conversion from " << Value<util::vector4<SRC> >::staticName() << " to " << Value<std::list<DST> >::staticName();
00558         dstVal.resize( 4 );
00559         return IterableSubValueConv<SRC, DST >::convertIter2Iter( src.castTo<util::vector4<SRC> >(), dstVal );
00560     }
00561     virtual ~ValueConverter() {}
00562 };
00564 // list to vectorX version -- uses IterableSubValueConv::convertIter2Iter
00566 template<typename SRC, typename DST > class ValueConverter<false, false, std::list<SRC>, vector3<DST> >:
00567     public ValueGenerator<std::list<SRC>, vector3<DST> >, private IterableSubValueConv<SRC, DST >
00568 {
00569     ValueConverter() {
00570         LOG( Debug, verbose_info ) << "Creating list converter from " << Value<std::list<SRC> >::staticName() << " to " << Value<vector3<DST> >::staticName();
00571     };
00572     friend boost::shared_ptr<const ValueConverterBase> getFor<ValueConverter<false, false, std::list<SRC>, vector3<DST> >, SRC, DST>();
00573 public:
00574     static boost::shared_ptr<const ValueConverterBase> get() {
00575         return getFor<ValueConverter<false, false, std::list<SRC>, vector3<DST> >, SRC, DST>();
00576     }
00577     boost::numeric::range_check_result convert( const ValueBase &src, ValueBase &dst )const {
00578         return IterableSubValueConv<SRC, DST >::convertIter2Iter( src.castTo<std::list<SRC> >(), dst.castTo<vector3<DST> >() );
00579     }
00580     virtual ~ValueConverter() {}
00581 };
00582 template<typename SRC, typename DST > class ValueConverter<false, false, std::list<SRC>, vector4<DST> >:
00583     public ValueGenerator<std::list<SRC>, vector4<DST> >, private IterableSubValueConv<SRC, DST >
00584 {
00585     ValueConverter() {
00586         LOG( Debug, verbose_info ) << "Creating list converter from " << Value<std::list<SRC> >::staticName() << " to " << Value<vector4<DST> >::staticName();
00587     };
00588     friend boost::shared_ptr<const ValueConverterBase> getFor<ValueConverter<false, false, std::list<SRC>, vector4<DST> >, SRC, DST>();
00589 public:
00590     static boost::shared_ptr<const ValueConverterBase> get() {
00591         return getFor<ValueConverter<false, false, std::list<SRC>, vector4<DST> >, SRC, DST>();
00592     }
00593     boost::numeric::range_check_result convert( const ValueBase &src, ValueBase &dst )const {
00594         return IterableSubValueConv<SRC, DST >::convertIter2Iter( src.castTo<std::list<SRC> >(), dst.castTo<vector4<DST> >() );
00595     }
00596     virtual ~ValueConverter() {}
00597 };
00598 
00599 
00601 // string to scalar -- uses lexical_cast (and in some cases mumeric conversion) to convert from string
00603 template<typename DST> class ValueConverter<false, false, std::string, DST> : public ValueGenerator<std::string, DST>
00604 {
00605     ValueConverter() {
00606         LOG( Debug, verbose_info ) << "Creating from-string converter for " << Value<DST>::staticName();
00607     };
00608 public:
00609     static boost::shared_ptr<const ValueConverterBase> get() {
00610         ValueConverter<false, false, std::string, DST> *ret = new ValueConverter<false, false, std::string, DST>;
00611         return boost::shared_ptr<const ValueConverterBase>( ret );
00612     }
00613     boost::numeric::range_check_result convert( const ValueBase &src, ValueBase &dst )const {
00614         return str2scalar( src.castTo<std::string>(), dst.castTo<DST>() );
00615     }
00616     virtual ~ValueConverter() {}
00617 };
00618 // cannot use the general str to all because that would be ambiguous with "all to complex"
00619 template<typename DST> class ValueConverter<false, false, std::string, std::complex<DST> > :
00620     public ValueGenerator<std::string, std::complex<DST> >, private SubValueConv<std::complex<double>, std::complex<DST> >
00621 {
00622     ValueConverter() {
00623         LOG( Debug, verbose_info )
00624                 << "Creating from-string converter for " << Value<std::complex<DST> >::staticName();
00625     };
00626     friend boost::shared_ptr<const ValueConverterBase> getFor<ValueConverter<false, false, std::string, std::complex<DST> >, std::complex<double>, std::complex<DST> >();
00627 public:
00628     static boost::shared_ptr<const ValueConverterBase> get() {
00629         return getFor<ValueConverter<false, false, std::string, std::complex<DST> >, std::complex<double>, std::complex<DST> >();
00630     }
00631     boost::numeric::range_check_result convert( const ValueBase &src, ValueBase &dst )const {
00632         try {
00633             const util::Value<std::complex<double> > srcDbl( src.castTo<std::string>() ); // make a double from the string
00634             return num2num( srcDbl.castTo<std::complex<double> >(), dst.castTo<std::complex<DST> >() );
00635         } catch( const boost::bad_lexical_cast & ) {
00636             dst.castTo<DST>() = DST();
00637             LOG( Runtime, error ) << "Miserably failed to interpret " << MSubject( src ) << " as " << Value<DST>::staticName() << " returning " << MSubject( DST() );
00638         }
00639 
00640         return boost::numeric::cInRange;
00641     }
00642     virtual ~ValueConverter() {}
00643 };
00644 
00646 // all to string -- just use formatted print into a string buffer
00648 template<typename SRC> class ValueConverter<false, false, SRC, std::string> : public ValueGenerator<SRC, std::string>
00649 {
00650     ValueConverter() {
00651         LOG( Debug, verbose_info )
00652                 << "Creating to-string converter for " << Value<SRC>::staticName();
00653     };
00654 public:
00655     static boost::shared_ptr<const ValueConverterBase> get() {
00656         ValueConverter<false, false, SRC, std::string> *ret = new ValueConverter<false, false, SRC, std::string>;
00657         return boost::shared_ptr<const ValueConverterBase>( ret );
00658     }
00659     boost::numeric::range_check_result convert( const ValueBase &src, ValueBase &dst )const {
00660         dst.castTo<std::string>() = toStringConv( src.castTo<SRC>() );
00661         return boost::numeric::cInRange; // this should allways be ok
00662     }
00663     virtual ~ValueConverter() {}
00664 };
00665 
00667 // string => list/vector/color version -- uses util::stringToList
00669 template<typename DST> class ValueConverter<false, false, std::string, std::list<DST> >:
00670     public ValueGenerator<std::string, std::list<DST> >
00671 {
00672     ValueConverter() {
00673         LOG( Debug, verbose_info )
00674                 << "Creating from-string converter for " << Value<std::list<DST> >::staticName();
00675     };
00676 public:
00677     static boost::shared_ptr<const ValueConverterBase> get() {
00678         ValueConverter<false, false, std::string, std::list<DST> > *ret = new ValueConverter<false, false, std::string, std::list<DST> >;
00679         return boost::shared_ptr<const ValueConverterBase>( ret );
00680     }
00681     boost::numeric::range_check_result convert( const ValueBase &src, ValueBase &dst )const {
00682         std::list<DST> &dstList = dst.castTo<std::list<DST> >();
00683         const std::list<std::string> srcList = Tokenizer<boost::is_arithmetic<DST>::value>::run( src.castTo<std::string>() ); // tokenize the strin based on the target type
00684         dstList.resize( srcList.size() ); // resize target to the ammount of found tokens
00685         StrTransformer<DST> transformer; // create a transformer from string to DST
00686         std::transform( srcList.begin(), srcList.end(), dstList.begin(), transformer ); // transform the found strings to the destination
00687         return transformer.range_ok;
00688     }
00689     virtual ~ValueConverter() {}
00690 };
00691 template<typename DST> class ValueConverter<false, false, std::string, vector4<DST> >: public ValueGenerator<std::string, vector4<DST> >  //string => vector4
00692 {
00693     ValueConverter() {
00694         LOG( Debug, verbose_info ) << "Creating from-string converter for " << Value<vector4<DST> >::staticName();
00695     };
00696 public:
00697     static boost::shared_ptr<const ValueConverterBase> get() {
00698         ValueConverter<false, false, std::string, vector4<DST> > *ret = new ValueConverter<false, false, std::string, vector4<DST> >;
00699         return boost::shared_ptr<const ValueConverterBase>( ret );
00700     }
00701     boost::numeric::range_check_result convert( const ValueBase &src, ValueBase &dst )const {
00702         return _internal::convertStr2Vector<DST, 4>( src, dst.castTo<vector4<DST> >() );
00703     }
00704     virtual ~ValueConverter() {}
00705 };
00706 
00707 template<typename DST> class ValueConverter<false, false, std::string, vector3<DST> >: public ValueGenerator<std::string, vector3<DST> >  //string => vector3
00708 {
00709     ValueConverter() {
00710         LOG( Debug, verbose_info ) << "Creating from-string converter for " << Value<vector3<DST> >::staticName();
00711     };
00712 public:
00713     static boost::shared_ptr<const ValueConverterBase> get() {
00714         ValueConverter<false, false, std::string, vector3<DST> > *ret = new ValueConverter<false, false, std::string, vector3<DST> >;
00715         return boost::shared_ptr<const ValueConverterBase>( ret );
00716     }
00717     boost::numeric::range_check_result convert( const ValueBase &src, ValueBase &dst )const {
00718         return _internal::convertStr2Vector<DST, 3>( src, dst.castTo<vector3<DST> >() );
00719     }
00720     virtual ~ValueConverter() {}
00721 };
00722 
00723 template<typename T> class ValueConverter<false, false, std::string, color<T> >: public ValueGenerator<std::string, color<T> >  //string => color
00724 {
00725     ValueConverter() {
00726         LOG( Debug, verbose_info )
00727                 << "Creating from-string converter for " << Value<color<T> >::staticName();
00728     };
00729 public:
00730     static boost::shared_ptr<const ValueConverterBase> get() {
00731         ValueConverter<false, false, std::string, color<T> > *ret = new ValueConverter<false, false, std::string, color<T> >;
00732         return boost::shared_ptr<const ValueConverterBase>( ret );
00733     }
00734     boost::numeric::range_check_result convert( const ValueBase &src, ValueBase &dst )const {
00735         color<T> &dstVal = dst.castTo<color<T> >();
00736         const std::list<std::string> srcList = Tokenizer<boost::is_arithmetic<T>::value>::run( src.castTo<std::string>() ); // tokenize the string based on the target type
00737         std::list< std::string >::const_iterator end = srcList.begin();
00738         std::advance( end, std::min<size_t>( srcList.size(), 3 ) ); // use a max of 3 tokens
00739         StrTransformer<T> transformer; // create a transformer from string to DST
00740         std::transform( srcList.begin(), end, &dstVal.r, transformer ); // transform the found strings to the destination
00741         return transformer.range_ok;
00742     }
00743     virtual ~ValueConverter() {}
00744 };
00745 
00747 //OK, thats about the foreplay. Now we get to the dirty stuff.
00749 
00751 template<typename SRC> struct inner_TypeConverter {
00752     std::map<int, boost::shared_ptr<const ValueConverterBase> > &m_subMap;
00753     inner_TypeConverter( std::map<int, boost::shared_ptr<const ValueConverterBase> > &subMap ): m_subMap( subMap ) {}
00754     template<typename DST> void operator()( DST ) { //will be called by the mpl::for_each in outer_TypeConverter for any DST out of "types"
00755         //create a converter based on the type traits and the types of SRC and DST
00756         typedef boost::mpl::and_<boost::is_arithmetic<SRC>, boost::is_arithmetic<DST> > is_num;
00757         typedef boost::is_same<SRC, DST> is_same;
00758         boost::shared_ptr<const ValueConverterBase> conv =
00759             ValueConverter<is_num::value, is_same::value, SRC, DST>::get();
00760         //and insert it into the to-conversion-map of SRC
00761         m_subMap.insert( m_subMap.end(), std::make_pair( Value<DST>::staticID, conv ) );
00762     }
00763 };
00764 
00766 struct outer_TypeConverter {
00767     std::map< int , std::map<int, boost::shared_ptr<const ValueConverterBase> > > &m_map;
00768     outer_TypeConverter( std::map< int , std::map<int, boost::shared_ptr<const ValueConverterBase> > > &map ): m_map( map ) {}
00769     template<typename SRC> void operator()( SRC ) {//will be called by the mpl::for_each in ValueConverterMap() for any SRC out of "types"
00770         boost::mpl::for_each<types>( // create a functor for from-SRC-conversion and call its ()-operator for any DST out of "types"
00771             inner_TypeConverter<SRC>( m_map[Value<SRC>().getTypeID()] )
00772         );
00773     }
00774 };
00775 
00776 ValueConverterMap::ValueConverterMap()
00777 {
00778     boost::mpl::for_each<types>( outer_TypeConverter( *this ) );
00779     LOG( Debug, info ) << "conversion map for " << size() << " types created";
00780 }
00781 
00782 }
00783 API_EXCLUDE_END
00784 }
00785 }