CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_5_3_0/src/CommonTools/Utils/src/AnyMethodArgument.h

Go to the documentation of this file.
00001 #ifndef CommonTools_Utils_AnyMethodArgument_h
00002 #define CommonTools_Utils_AnyMethodArgument_h
00003 
00004 #include "Reflex/Object.h"
00005 #include "Reflex/Member.h"
00006 #include "CommonTools/Utils/interface/Exception.h"
00007 
00008 #include <algorithm>
00009 #include <string>
00010 #include <stdint.h>
00011 
00012 #include <boost/variant.hpp>
00013 #include <boost/type_traits/is_same.hpp>
00014 #include <boost/type_traits/is_integral.hpp>
00015 #include <boost/type_traits/is_floating_point.hpp>
00016 #include <boost/utility/enable_if.hpp>
00017 #include <boost/mpl/if.hpp>
00018 
00019 namespace reco {
00020   namespace parser {
00021 
00022     // true if T matches one of the integral types in the default
00023     // AnyMethodArgument variant
00024     template <typename T>
00025     struct matches_another_integral_type {
00026         static bool const value = 
00027             boost::is_same<T, int8_t>::value  || boost::is_same<T, uint8_t>::value  ||
00028             boost::is_same<T, int16_t>::value || boost::is_same<T, uint16_t>::value ||
00029             boost::is_same<T, int32_t>::value || boost::is_same<T, uint32_t>::value ||
00030             boost::is_same<T, int64_t>::value || boost::is_same<T, uint64_t>::value;
00031     };
00032 
00033     // size_t on 32-bit Os X is type unsigned long, which doesn't match uint32_t,
00034     // so add unsigned long if it doesn't match any of the other integral types.
00035     // Use "unsigned long" rather than size_t as PtrVector has unsigned long as
00036     // size_type
00037     typedef boost::mpl::if_<matches_another_integral_type<unsigned long>,
00038         boost::variant<int8_t, uint8_t,
00039                        int16_t, uint16_t,
00040                        int32_t, uint32_t,
00041                        int64_t, uint64_t,
00042                        double,float,
00043                        std::string>,
00044         boost::variant<int8_t, uint8_t,
00045                        int16_t, uint16_t,
00046                        int32_t, uint32_t,
00047                        int64_t, uint64_t,
00048                        unsigned long,
00049                        double,float,
00050                        std::string> >::type AnyMethodArgument;
00051 
00052     class AnyMethodArgumentFixup : public boost::static_visitor<std::pair<AnyMethodArgument, int> > {
00053         private:
00054             Reflex::Type rflxType_;
00055             const std::type_info & type_;
00056             template<typename From, typename To>
00057             std::pair<AnyMethodArgument, int> retOk_(const From &f, int cast) const {
00058                 return std::pair<AnyMethodArgument,int>(AnyMethodArgument(static_cast<To>(f)), cast);
00059             }
00060 
00061             // correct return for each int output type
00062             std::pair<AnyMethodArgument,int> doInt(int t) const {
00063                 if (type_ == typeid(int8_t))   { return retOk_<int,int8_t>  (t,0); }
00064                 if (type_ == typeid(uint8_t))  { return retOk_<int,uint8_t> (t,0); }
00065                 if (type_ == typeid(int16_t))  { return retOk_<int,int16_t> (t,0); }
00066                 if (type_ == typeid(uint16_t)) { return retOk_<int,uint16_t>(t,0); }
00067                 if (type_ == typeid(int32_t))  { return retOk_<int,int32_t> (t,0); }
00068                 if (type_ == typeid(uint32_t)) { return retOk_<int,uint32_t>(t,0); }
00069                 if (type_ == typeid(int64_t))  { return retOk_<int,int64_t> (t,0); }
00070                 if (type_ == typeid(uint64_t)) { return retOk_<int,uint64_t>(t,0); }
00071                 if (type_ == typeid(unsigned long)) { return retOk_<int,unsigned long>  (t,0); } // harmless if unsigned long matches another type
00072                 if (type_ == typeid(double))   { return retOk_<int,double>  (t,1); }
00073                 if (type_ == typeid(float))    { return retOk_<int,float>   (t,1); }
00074                 return std::pair<AnyMethodArgument,int>(t,-1);
00075             }
00076         public:
00077             AnyMethodArgumentFixup(Reflex::Type type) : 
00078                 rflxType_(type),
00079                 type_(type.Name() == "string" ? typeid(std::string) : type.TypeInfo()) // Otherwise Reflex does this wrong :-(
00080             {
00081                 while (rflxType_.IsTypedef()) rflxType_ = rflxType_.ToType();
00082                 /* // Code to print out enum table 
00083                 if (rflxType_.IsEnum()) {
00084                     std::cerr << "Enum conversion: [" << rflxType_.Name() <<  "] => [" << type_.name() << "]" << std::endl;
00085                     std::cerr << "Enum has " << rflxType_.MemberSize() << ", members." << std::endl;
00086                     for (size_t i = 0; i < rflxType_.MemberSize(); ++i) {
00087                         Reflex::Member mem = rflxType_.MemberAt(i);
00088                         std::cerr << " member #"<<i<<", name = " << mem.Name() << ", rflxType_ = " << mem.TypeOf().Name() << std::endl; 
00089                     }
00090                 } // */
00091             }
00092 
00093             // we handle all integer types through 'int', as that's the way they are parsed by boost::spirit
00094             template<typename I>
00095             typename boost::enable_if<boost::is_integral<I>, std::pair<AnyMethodArgument,int> >::type
00096             operator()(const I &t) const { return doInt(t); }
00097 
00098             template<typename F>
00099             typename boost::enable_if<boost::is_floating_point<F>, std::pair<AnyMethodArgument,int> >::type
00100             operator()(const F &t) const { 
00101                 if (type_ == typeid(double)) { return retOk_<F,double>(t,0); }
00102                 if (type_ == typeid(float))  { return retOk_<F,float> (t,0); }
00103                 return std::pair<AnyMethodArgument,int>(t,-1);
00104             }
00105 
00106             std::pair<AnyMethodArgument,int> operator()(const std::string &t) const { 
00107                 if (type_ == typeid(std::string)) { return std::pair<AnyMethodArgument,int>(t,0); }
00108                 if (rflxType_.IsEnum()) {
00109                     if (rflxType_.MemberSize() == 0) {
00110                         throw parser::Exception(t.c_str()) << "Enumerator '" << rflxType_.Name() << "' has no keys.\nPerhaps the reflex dictionary is missing?\n";
00111                     }
00112                     Reflex::Member value = rflxType_.MemberByName(t);
00113                     //std::cerr << "Trying to convert '" << t << "'  to a value for enumerator '" << rflxType_.Name() << "'" << std::endl;
00114                     if (!value) // check for existing value
00115                         return std::pair<AnyMethodArgument,int>(t,-1);
00116                         // throw parser::Exception(t.c_str()) << "Can't convert '" << t << "' to a value for enumerator '" << rflxType_.Name() << "'\n";
00117                     //std::cerr << "  found member of type '" << value.TypeOf().Name() << "'" << std::endl;
00118                     if (value.TypeOf().TypeInfo() != typeid(int)) // check is backed by an Int
00119                         throw parser::Exception(t.c_str()) << "Enumerator '" << rflxType_.Name() << "' is not implemented by type 'int' !!??\n";
00120                     //std::cerr << "  value is @ " <<   reinterpret_cast<const int *>(value.Get().Address()) << std::endl;
00121                     int ival = * reinterpret_cast<const int *>(value.Get().Address());
00122                     //std::cerr << "  value is = " << ival << std::endl;
00123                     return std::pair<AnyMethodArgument,int>(ival,1);
00124                 }
00125                 return std::pair<AnyMethodArgument,int>(t,-1);
00126             }
00127 
00128     };
00129     
00130     class AnyMethodArgument2VoidPtr : public boost::static_visitor<void *> {
00131         public:
00132             template<typename T>
00133             void * operator()(const T &t) const { return const_cast<void*>(static_cast<const void *>(&t)); }
00134     };
00135   }
00136 }
00137 
00138 #endif