CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_5_3_14/src/FWCore/Utilities/src/ReflexTools.cc

Go to the documentation of this file.
00001 #include "FWCore/Utilities/interface/ReflexTools.h"
00002 #include "FWCore/Utilities/interface/Algorithms.h"
00003 #include "FWCore/Utilities/interface/EDMException.h"
00004 
00005 #include "Api.h" // for G__ClassInfo
00006 #include "Reflex/Base.h"
00007 #include "Reflex/Member.h"
00008 #include "Reflex/TypeTemplate.h"
00009 
00010 #include "TROOT.h"
00011 
00012 #include "boost/algorithm/string.hpp"
00013 #include "boost/thread/tss.hpp"
00014 
00015 #include <algorithm>
00016 #include <sstream>
00017 
00018 using Reflex::Base;
00019 using Reflex::FINAL;
00020 using Reflex::Member;
00021 using Reflex::Object;
00022 using Reflex::SCOPED;
00023 using Reflex::Type;
00024 using Reflex::TypeTemplate;
00025 using Reflex::Type_Iterator;
00026 
00027 namespace edm {
00028 
00029   static StringSet foundTypes_;
00030   static StringSet missingTypes_;
00031 
00032   Type get_final_type(Type t) {
00033     while(t.IsTypedef()) t = t.ToType();
00034     return t;
00035   }
00036 
00037   bool
00038   find_nested_type_named(std::string const& nested_type,
00039                          Type const& type_to_search,
00040                          Type& found_type) {
00041     // Look for a sub-type named 'nested_type'
00042     for(Type_Iterator
00043            i = type_to_search.SubType_Begin(),
00044            e = type_to_search.SubType_End();
00045            i != e;
00046            ++i) {
00047       if(i->Name() == nested_type) {
00048         found_type = get_final_type(*i);
00049         return true;
00050       }
00051     }
00052     return false;
00053   }
00054 
00055   bool
00056   is_RefVector(Reflex::Type const& possible_ref_vector,
00057                Reflex::Type& value_type) {
00058 
00059     static TypeTemplate ref_vector_template_id(TypeTemplate::ByName("edm::RefVector", 3));
00060     static std::string member_type("member_type");
00061     TypeTemplate primary_template_id(possible_ref_vector.TemplateFamily());
00062     if(primary_template_id == ref_vector_template_id) {
00063       return find_nested_type_named(member_type, possible_ref_vector, value_type);
00064     }
00065     return false;
00066   }
00067 
00068   bool
00069   is_PtrVector(Reflex::Type const& possible_ref_vector,
00070                Reflex::Type& value_type) {
00071 
00072     static TypeTemplate ref_vector_template_id(TypeTemplate::ByName("edm::PtrVector", 1));
00073     static std::string member_type("member_type");
00074     static std::string val_type("value_type");
00075     TypeTemplate primary_template_id(possible_ref_vector.TemplateFamily());
00076     if(primary_template_id == ref_vector_template_id) {
00077       Reflex::Type ptrType;
00078       if(find_nested_type_named(val_type, possible_ref_vector, ptrType)) {
00079         return find_nested_type_named(val_type, ptrType, value_type);
00080       }
00081     }
00082     return false;
00083   }
00084 
00085   bool
00086   is_RefToBaseVector(Reflex::Type const& possible_ref_vector,
00087                      Reflex::Type& value_type) {
00088 
00089     static TypeTemplate ref_vector_template_id(TypeTemplate::ByName("edm::RefToBaseVector", 1));
00090     static std::string member_type("member_type");
00091     TypeTemplate primary_template_id(possible_ref_vector.TemplateFamily());
00092     if(primary_template_id == ref_vector_template_id) {
00093       return find_nested_type_named(member_type, possible_ref_vector, value_type);
00094     }
00095     return false;
00096   }
00097 
00098   namespace {
00099 
00100     int const oneParamArraySize = 6;
00101     std::string const oneParam[oneParamArraySize] = {
00102       "vector",
00103       "basic_string",
00104       "set",
00105       "list",
00106       "deque",
00107       "multiset"
00108     };
00109     int const twoParamArraySize = 3;
00110     std::string const twoParam[twoParamArraySize] = {
00111       "map",
00112       "pair",
00113       "multimap"
00114     };
00115 
00116 
00117     bool
00118     hasCintDictionary(std::string const& name) {
00119       std::auto_ptr<G__ClassInfo> ci(new G__ClassInfo(name.c_str()));
00120         return(ci.get() && ci->IsLoaded());
00121     }
00122 
00123     // Checks if there is a Reflex dictionary for the Type t.
00124     // If noComponents is false, checks members and base classes recursively.
00125     // If noComponents is true, checks Type t only.
00126     void
00127     checkType(Type t, bool noComponents = false) {
00128 
00129       // ToType strips const, volatile, array, pointer, reference, etc.,
00130       // and also translates typedefs.
00131       // To be safe, we do this recursively until we either get a null type
00132       // or the same type.
00133       Type null;
00134       for(Type x = t.ToType(); x != null && x != t; t = x, x = t.ToType()) {}
00135 
00136       std::string name = t.Name(SCOPED);
00137       boost::trim(name);
00138 
00139       if(foundTypes().end() != foundTypes().find(name) || missingTypes().end() != missingTypes().find(name)) {
00140         // Already been processed. Prevents infinite loop.
00141         return;
00142       }
00143 
00144       if(name.empty() || t.IsFundamental() || t.IsEnum()) {
00145         foundTypes().insert(name);
00146         return;
00147       }
00148 
00149       if(!bool(t)) {
00150         if(hasCintDictionary(name)) {
00151           foundTypes().insert(name);
00152         } else {
00153           missingTypes().insert(name);
00154         }
00155         return;
00156       }
00157 
00158       foundTypes().insert(name);
00159       if(noComponents) return;
00160 
00161       if(name.find("std::") == 0) {
00162         if(t.IsTemplateInstance()) {
00163           std::string::size_type n = name.find('<');
00164           int cnt = 0;
00165           if(std::find(oneParam, oneParam + oneParamArraySize, name.substr(5, n - 5)) != oneParam + oneParamArraySize) {
00166             cnt = 1;
00167           } else if(std::find(twoParam, twoParam + twoParamArraySize, name.substr(5, n - 5)) != twoParam + twoParamArraySize) {
00168             cnt = 2;
00169           }
00170           for(int i = 0; i < cnt; ++i) {
00171             checkType(t.TemplateArgumentAt(i));
00172           }
00173         }
00174       } else {
00175         int mcnt = t.DataMemberSize();
00176         for(int i = 0; i < mcnt; ++i) {
00177           Member m = t.DataMemberAt(i);
00178           if(m.IsTransient() || m.IsStatic()) continue;
00179           checkType(m.TypeOf());
00180         }
00181         int cnt = t.BaseSize();
00182         for(int i = 0; i < cnt; ++i) {
00183           checkType(t.BaseAt(i).ToType());
00184         }
00185       }
00186     }
00187   } // end unnamed namespace
00188 
00189   StringSet& missingTypes() {
00190     return missingTypes_;
00191   }
00192 
00193   StringSet& foundTypes() {
00194     // The only purpose of this cache is to stop infinite recursion.
00195     // Reflex maintains its own internal cache.
00196     return foundTypes_;
00197   }
00198 
00199   void checkDictionaries(std::string const& name, bool noComponents) {
00200     Type null;
00201     Type t = Type::ByName(name);
00202     if(t == null) {
00203       missingTypes().insert(name);
00204       return;
00205     }
00206     checkType(Type::ByName(name), noComponents);
00207   }
00208 
00209   void throwMissingDictionariesException() {
00210     if(!missingTypes().empty()) {
00211       std::ostringstream ostr;
00212       for (StringSet::const_iterator it = missingTypes().begin(), itEnd = missingTypes().end();
00213            it != itEnd; ++it) {
00214         ostr << *it << "\n\n";
00215       }
00216       throw Exception(errors::DictionaryNotFound)
00217         << "No REFLEX data dictionary found for the following classes:\n\n"
00218         << ostr.str()
00219         << "Most likely each dictionary was never generated,\n"
00220         << "but it may be that it was generated in the wrong package.\n"
00221         << "Please add (or move) the specification\n"
00222         << "<class name=\"whatever\"/>\n"
00223         << "to the appropriate classes_def.xml file.\n"
00224         << "If the class is a template instance, you may need\n"
00225         << "to define a dummy variable of this type in classes.h.\n"
00226         << "Also, if this class has any transient members,\n"
00227         << "you need to specify them in classes_def.xml.";
00228     }
00229   }
00230 
00231   void loadMissingDictionaries() {
00232     while (!missingTypes().empty()) {
00233       StringSet missing(missingTypes());
00234       for (StringSet::const_iterator it = missing.begin(), itEnd = missing.end();
00235          it != itEnd; ++it) {
00236         try {
00237           gROOT->GetClass(it->c_str(), kTRUE);
00238         }
00239         // We don't want to fail if we can't load a plug-in.
00240         catch(...) {}
00241       }
00242       missingTypes().clear();
00243       for (StringSet::const_iterator it = missing.begin(), itEnd = missing.end();
00244          it != itEnd; ++it) {
00245         checkDictionaries(*it);
00246       }
00247       if (missingTypes() == missing) {
00248         break;
00249       }
00250     }
00251     if (missingTypes().empty()) {
00252       return;
00253     }
00254     throwMissingDictionariesException();
00255   }
00256 
00257   void public_base_classes(Type const& type,
00258                            std::vector<Type>& baseTypes) {
00259 
00260     if(type.IsClass() || type.IsStruct()) {
00261 
00262       int nBase = type.BaseSize();
00263       for(int i = 0; i < nBase; ++i) {
00264 
00265         Base base = type.BaseAt(i);
00266         if(base.IsPublic()) {
00267 
00268           Type baseType = type.BaseAt(i).ToType();
00269           if(bool(baseType)) {
00270 
00271             while(baseType.IsTypedef() == true) {
00272               baseType = baseType.ToType();
00273             }
00274 
00275             // Check to make sure this base appears only once in the
00276             // inheritance heirarchy.
00277             if(!search_all(baseTypes, baseType)) {
00278               // Save the type and recursive look for its base types
00279               baseTypes.push_back(baseType);
00280               public_base_classes(baseType, baseTypes);
00281             }
00282             // For now just ignore it if the class appears twice,
00283             // After some more testing we may decide to uncomment the following
00284             // exception.
00285             /*
00286             else {
00287               throw Exception(errors::UnimplementedFeature)
00288                 << "DataFormats/Common/src/ReflexTools.cc in function public_base_classes.\n"
00289                 << "Encountered class that has a public base class that appears\n"
00290                 << "multiple times in its inheritance heirarchy.\n"
00291                 << "Please contact the EDM Framework group with details about\n"
00292                 << "this exception. It was our hope that this complicated situation\n"
00293                 << "would not occur. There are three possible solutions. 1. Change\n"
00294                 << "the class design so the public base class does not appear multiple\n"
00295                 << "times in the inheritance heirarchy. In many cases, this is a\n"
00296                 << "sign of bad design. 2. Modify the code that supports Views to\n"
00297                 << "ignore these base classes, but not supply support for creating a\n"
00298                 << "View of this base class. 3. Improve the View infrastructure to\n"
00299                 << "deal with this case. Class name of base class: " << baseType.Name() << "\n\n";
00300             }
00301             */
00302           }
00303         }
00304       }
00305     }
00306   }
00307 
00308   void const*
00309   reflex_pointer_adjust(void* raw,
00310                         Type const& dynamicType,
00311                         std::type_info const& toType) {
00312     Object obj(dynamicType, raw);
00313     return obj.CastObject(Type::ByTypeInfo(toType)).Address();
00314   }
00315 }