CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_5/src/FWCore/Utilities/src/DictionaryTools.cc

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