ISIS Core Library 0.7.2 (api 3.0.0)
|
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 }