CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_5/src/DataFormats/Provenance/src/BranchDescription.cc

Go to the documentation of this file.
00001 #include "DataFormats/Provenance/interface/BranchDescription.h"
00002 #include "FWCore/Utilities/interface/Exception.h"
00003 #include "FWCore/Utilities/interface/EDMException.h"
00004 #include "FWCore/Utilities/interface/FriendlyName.h"
00005 #include "FWCore/Utilities/interface/TypeWithDict.h"
00006 #include "FWCore/Utilities/interface/WrappedClassName.h"
00007 
00008 #include <ostream>
00009 #include <sstream>
00010 #include <stdlib.h>
00011 
00012 class TClass;
00013 /*----------------------------------------------------------------------
00014 
00015 
00016 ----------------------------------------------------------------------*/
00017 
00018 namespace edm {
00019   BranchDescription::Transients::Transients() :
00020     parameterSetID_(),
00021     moduleName_(),
00022     branchName_(),
00023     wrappedName_(),
00024     produced_(false),
00025     onDemand_(false),
00026     dropped_(false),
00027     parameterSetIDs_(),
00028     moduleNames_(),
00029     transient_(false),
00030     wrappedType_(),
00031     unwrappedType_(),
00032     wrapperInterfaceBase_(nullptr),
00033     splitLevel_(),
00034     basketSize_() {
00035    }
00036 
00037   void
00038   BranchDescription::Transients::reset() {
00039     *this = BranchDescription::Transients();
00040   }
00041 
00042   BranchDescription::BranchDescription() :
00043     branchType_(InEvent),
00044     moduleLabel_(),
00045     processName_(),
00046     branchID_(),
00047     fullClassName_(),
00048     friendlyClassName_(),
00049     productInstanceName_(),
00050     branchAliases_(),
00051     aliasForBranchID_(),
00052     transient_() {
00053     // do not call init here! It will result in an exception throw.
00054   }
00055 
00056   BranchDescription::BranchDescription(
00057                         BranchType const& branchType,
00058                         std::string const& moduleLabel,
00059                         std::string const& processName,
00060                         std::string const& className,
00061                         std::string const& friendlyClassName,
00062                         std::string const& productInstanceName,
00063                         std::string const& moduleName,
00064                         ParameterSetID const& parameterSetID,
00065                         TypeWithDict const& theTypeWithDict,
00066                         bool produced,
00067                         std::set<std::string> const& aliases) :
00068       branchType_(branchType),
00069       moduleLabel_(moduleLabel),
00070       processName_(processName),
00071       branchID_(),
00072       fullClassName_(className),
00073       friendlyClassName_(friendlyClassName),
00074       productInstanceName_(productInstanceName),
00075       branchAliases_(aliases),
00076       transient_() {
00077     dropped() = false;
00078     transient_.produced_ = produced,
00079     onDemand() = false;
00080     transient_.moduleName_ = moduleName;
00081     transient_.parameterSetID_ = parameterSetID;
00082     unwrappedType() = theTypeWithDict;
00083     init();
00084   }
00085 
00086   BranchDescription::BranchDescription(
00087                         BranchDescription const& aliasForBranch,
00088                         std::string const& moduleLabelAlias,
00089                         std::string const& productInstanceAlias) :
00090       branchType_(aliasForBranch.branchType()),
00091       moduleLabel_(moduleLabelAlias),
00092       processName_(aliasForBranch.processName()),
00093       branchID_(),
00094       fullClassName_(aliasForBranch.className()),
00095       friendlyClassName_(aliasForBranch.friendlyClassName()),
00096       productInstanceName_(productInstanceAlias),
00097       branchAliases_(aliasForBranch.branchAliases()),
00098       aliasForBranchID_(aliasForBranch.branchID()),
00099       transient_() {
00100     dropped() = false;
00101     transient_.produced_ = aliasForBranch.produced(),
00102     onDemand() = aliasForBranch.onDemand();
00103     transient_.moduleName_ = aliasForBranch.moduleName();
00104     transient_.parameterSetID_ = aliasForBranch.parameterSetID();
00105     unwrappedType() = aliasForBranch.unwrappedType();
00106     init();
00107   }
00108 
00109   void
00110   BranchDescription::initBranchName() const {
00111     if(!branchName().empty()) {
00112       return;  // already called
00113     }
00114     throwIfInvalid_();
00115 
00116     char const underscore('_');
00117     char const period('.');
00118 
00119     if(friendlyClassName_.find(underscore) != std::string::npos) {
00120       throw cms::Exception("IllegalCharacter") << "Class name '" << friendlyClassName()
00121       << "' contains an underscore ('_'), which is illegal in the name of a product.\n";
00122     }
00123 
00124     if(moduleLabel_.find(underscore) != std::string::npos) {
00125       throw cms::Exception("IllegalCharacter") << "Module label '" << moduleLabel()
00126       << "' contains an underscore ('_'), which is illegal in a module label.\n";
00127     }
00128 
00129     if(productInstanceName_.find(underscore) != std::string::npos) {
00130       throw cms::Exception("IllegalCharacter") << "Product instance name '" << productInstanceName()
00131       << "' contains an underscore ('_'), which is illegal in a product instance name.\n";
00132     }
00133 
00134     if(processName_.find(underscore) != std::string::npos) {
00135       throw cms::Exception("IllegalCharacter") << "Process name '" << processName()
00136       << "' contains an underscore ('_'), which is illegal in a process name.\n";
00137     }
00138 
00139     branchName().reserve(friendlyClassName().size() +
00140                          moduleLabel().size() +
00141                          productInstanceName().size() +
00142                          processName().size() + 4);
00143     branchName() += friendlyClassName();
00144     branchName() += underscore;
00145     branchName() += moduleLabel();
00146     branchName() += underscore;
00147     branchName() += productInstanceName();
00148     branchName() += underscore;
00149     branchName() += processName();
00150     branchName() += period;
00151 
00152     if(!branchID_.isValid()) {
00153       branchID_.setID(branchName());
00154     }
00155   }
00156 
00157   void
00158   BranchDescription::initFromDictionary() const {
00159     if(bool(wrappedType())) {
00160       return;  // already initialized;
00161     }
00162 
00163     throwIfInvalid_();
00164 
00165     wrappedName() = wrappedClassName(fullClassName());
00166 
00167     // unwrapped type.
00168     unwrappedType() = TypeWithDict::byName(fullClassName());
00169     if(!bool(unwrappedType())) {
00170       splitLevel() = invalidSplitLevel;
00171       basketSize() = invalidBasketSize;
00172       transient() = false;
00173       return;
00174     }
00175 
00176     wrappedType() = TypeWithDict::byName(wrappedName());
00177     if(!bool(wrappedType())) {
00178       splitLevel() = invalidSplitLevel;
00179       basketSize() = invalidBasketSize;
00180       return;
00181     }
00182     Reflex::PropertyList wp = Reflex::Type::ByTypeInfo(wrappedType().typeInfo()).Properties();
00183     transient() = (wp.HasProperty("persistent") ? wp.PropertyAsString("persistent") == std::string("false") : false);
00184     if(transient()) {
00185       splitLevel() = invalidSplitLevel;
00186       basketSize() = invalidBasketSize;
00187       return;
00188     }
00189     if(wp.HasProperty("splitLevel")) {
00190       splitLevel() = strtol(wp.PropertyAsString("splitLevel").c_str(), 0, 0);
00191       if(splitLevel() < 0) {
00192         throw cms::Exception("IllegalSplitLevel") << "' An illegal ROOT split level of " <<
00193         splitLevel() << " is specified for class " << wrappedName() << ".'\n";
00194       }
00195       ++splitLevel(); //Compensate for wrapper
00196     } else {
00197       splitLevel() = invalidSplitLevel;
00198     }
00199     if(wp.HasProperty("basketSize")) {
00200       basketSize() = strtol(wp.PropertyAsString("basketSize").c_str(), 0, 0);
00201       if(basketSize() <= 0) {
00202         throw cms::Exception("IllegalBasketSize") << "' An illegal ROOT basket size of " <<
00203         basketSize() << " is specified for class " << wrappedName() << "'.\n";
00204       }
00205     } else {
00206       basketSize() = invalidBasketSize;
00207     }
00208   }
00209 
00210   ParameterSetID const&
00211     BranchDescription::psetID() const {
00212     assert(!parameterSetIDs().empty());
00213     if(parameterSetIDs().size() != 1) {
00214       throw cms::Exception("Ambiguous")
00215         << "Your application requires all events on Branch '" << branchName()
00216         << "'\n to have the same provenance. This file has events with mixed provenance\n"
00217         << "on this branch.  Use a different input file.\n";
00218     }
00219     return parameterSetIDs().begin()->second;
00220   }
00221 
00222   void
00223   BranchDescription::merge(BranchDescription const& other) {
00224     parameterSetIDs().insert(other.parameterSetIDs().begin(), other.parameterSetIDs().end());
00225     moduleNames().insert(other.moduleNames().begin(), other.moduleNames().end());
00226     branchAliases_.insert(other.branchAliases().begin(), other.branchAliases().end());
00227     if(splitLevel() == invalidSplitLevel) splitLevel() = other.splitLevel();
00228     if(basketSize() == invalidBasketSize) basketSize() = other.basketSize();
00229   }
00230 
00231   void
00232   BranchDescription::write(std::ostream& os) const {
00233     os << "Branch Type = " << branchType() << std::endl;
00234     os << "Process Name = " << processName() << std::endl;
00235     os << "ModuleLabel = " << moduleLabel() << std::endl;
00236     os << "Branch ID = " << branchID() << '\n';
00237     os << "Class Name = " << fullClassName() << '\n';
00238     os << "Friendly Class Name = " << friendlyClassName() << '\n';
00239     os << "Product Instance Name = " << productInstanceName() << std::endl;
00240   }
00241 
00242   void throwExceptionWithText(char const* txt) {
00243     Exception e(errors::LogicError);
00244     e << "Problem using an incomplete BranchDescription\n"
00245       << txt
00246       << "\nPlease report this error to the FWCore developers";
00247     throw e;
00248   }
00249 
00250   void
00251   BranchDescription::throwIfInvalid_() const {
00252     if(branchType_ >= NumBranchTypes)
00253       throwExceptionWithText("Illegal BranchType detected");
00254 
00255     if(moduleLabel_.empty())
00256       throwExceptionWithText("Module label is not allowed to be empty");
00257 
00258     if(processName_.empty())
00259       throwExceptionWithText("Process name is not allowed to be empty");
00260 
00261     if(fullClassName_.empty())
00262       throwExceptionWithText("Full class name is not allowed to be empty");
00263 
00264     if(friendlyClassName_.empty())
00265       throwExceptionWithText("Friendly class name is not allowed to be empty");
00266 
00267     if(produced() && !parameterSetID().isValid())
00268       throwExceptionWithText("Invalid ParameterSetID detected");
00269   }
00270 
00271   void
00272   BranchDescription::updateFriendlyClassName() {
00273     friendlyClassName_ = friendlyname::friendlyName(fullClassName());
00274     branchName().clear();
00275     initBranchName();
00276   }
00277 
00278   bool
00279   operator<(BranchDescription const& a, BranchDescription const& b) {
00280     if(a.processName() < b.processName()) return true;
00281     if(b.processName() < a.processName()) return false;
00282     if(a.fullClassName() < b.fullClassName()) return true;
00283     if(b.fullClassName() < a.fullClassName()) return false;
00284     if(a.friendlyClassName() < b.friendlyClassName()) return true;
00285     if(b.friendlyClassName() < a.friendlyClassName()) return false;
00286     if(a.productInstanceName() < b.productInstanceName()) return true;
00287     if(b.productInstanceName() < a.productInstanceName()) return false;
00288     if(a.moduleLabel() < b.moduleLabel()) return true;
00289     if(b.moduleLabel() < a.moduleLabel()) return false;
00290     if(a.branchType() < b.branchType()) return true;
00291     if(b.branchType() < a.branchType()) return false;
00292     if(a.branchID() < b.branchID()) return true;
00293     if(b.branchID() < a.branchID()) return false;
00294     if(a.parameterSetIDs() < b.parameterSetIDs()) return true;
00295     if(b.parameterSetIDs() < a.parameterSetIDs()) return false;
00296     if(a.moduleNames() < b.moduleNames()) return true;
00297     if(b.moduleNames() < a.moduleNames()) return false;
00298     if(a.branchAliases() < b.branchAliases()) return true;
00299     if(b.branchAliases() < a.branchAliases()) return false;
00300     if(a.present() < b.present()) return true;
00301     if(b.present() < a.present()) return false;
00302     return false;
00303   }
00304 
00305   bool
00306   combinable(BranchDescription const& a, BranchDescription const& b) {
00307     return
00308     (a.branchType() == b.branchType()) &&
00309     (a.processName() == b.processName()) &&
00310     (a.fullClassName() == b.fullClassName()) &&
00311     (a.friendlyClassName() == b.friendlyClassName()) &&
00312     (a.productInstanceName() == b.productInstanceName()) &&
00313     (a.moduleLabel() == b.moduleLabel()) &&
00314     (a.branchID() == b.branchID());
00315   }
00316 
00317   bool
00318   operator==(BranchDescription const& a, BranchDescription const& b) {
00319     return combinable(a, b) &&
00320        (a.dropped() == b.dropped()) &&
00321        (a.moduleNames() == b.moduleNames()) &&
00322        (a.parameterSetIDs() == b.parameterSetIDs()) &&
00323        (a.branchAliases() == b.branchAliases());
00324   }
00325 
00326   std::string
00327   match(BranchDescription const& a, BranchDescription const& b,
00328         std::string const& fileName,
00329         BranchDescription::MatchMode m) {
00330     std::ostringstream differences;
00331     if(a.branchName() != b.branchName()) {
00332       differences << "Branch name '" << b.branchName() << "' does not match '" << a.branchName() << "'.\n";
00333       // Need not compare components of branch name individually.
00334       // (a.friendlyClassName() != b.friendlyClassName())
00335       // (a.moduleLabel() != b.moduleLabel())
00336       // (a.productInstanceName() != b.productInstanceName())
00337       // (a.processName() != b.processName())
00338     }
00339     if(a.branchType() != b.branchType()) {
00340       differences << "Branch '" << b.branchName() << "' is a(n) '" << b.branchType() << "' branch\n";
00341       differences << "    in file '" << fileName << "', but a(n) '" << a.branchType() << "' branch in previous files.\n";
00342     }
00343     if(a.branchID() != b.branchID()) {
00344       differences << "Branch '" << b.branchName() << "' has a branch ID of '" << b.branchID() << "'\n";
00345       differences << "    in file '" << fileName << "', but '" << a.branchID() << "' in previous files.\n";
00346     }
00347     if(a.fullClassName() != b.fullClassName()) {
00348       differences << "Products on branch '" << b.branchName() << "' have type '" << b.fullClassName() << "'\n";
00349       differences << "    in file '" << fileName << "', but '" << a.fullClassName() << "' in previous files.\n";
00350     }
00351     if(!b.dropped() && a.dropped()) {
00352       differences << "Branch '" << a.branchName() << "' was dropped in the first input file but is present in '" << fileName << "'.\n";
00353     }
00354     if(m == BranchDescription::Strict) {
00355         if(b.parameterSetIDs().size() > 1) {
00356           differences << "Branch '" << b.branchName() << "' uses more than one parameter set in file '" << fileName << "'.\n";
00357         } else if(a.parameterSetIDs().size() > 1) {
00358           differences << "Branch '" << a.branchName() << "' uses more than one parameter set in previous files.\n";
00359         } else if(a.parameterSetIDs() != b.parameterSetIDs()) {
00360           differences << "Branch '" << b.branchName() << "' uses different parameter sets in file '" << fileName << "'.\n";
00361           differences << "    than in previous files.\n";
00362         }
00363     }
00364     return differences.str();
00365   }
00366 
00367   WrapperInterfaceBase const*
00368   BranchDescription::getInterface() const {
00369     if(wrapperInterfaceBase() == 0) {
00370       // This could be done in init(), but we only want to do it on demand, for performance reasons.
00371       TypeWithDict type = TypeWithDict::byName(wrappedName());
00372       type.invokeByName(wrapperInterfaceBase(), "getInterface");
00373       assert(wrapperInterfaceBase() != 0);
00374     }
00375     return wrapperInterfaceBase();
00376   }
00377 }