CMS 3D CMS Logo

/data/git/CMSSW_5_3_11_patch5/src/FWCore/ParameterSet/src/ParameterSetDescription.cc

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 //
00003 // Package:     ParameterSet
00004 // Class  :     ParameterSetDescription
00005 // 
00006 // Implementation:
00007 //     <Notes on implementation>
00008 //
00009 // Original Author:  Chris Jones
00010 //         Created:  Tue Jul 31 15:30:35 EDT 2007
00011 //
00012 
00013 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
00014 
00015 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00016 #include "FWCore/ParameterSet/interface/IfExistsDescription.h"
00017 #include "FWCore/ParameterSet/interface/IllegalParameters.h"
00018 #include "FWCore/ParameterSet/interface/DocFormatHelper.h"
00019 #include "FWCore/Utilities/interface/Algorithms.h"
00020 #include "FWCore/Utilities/interface/EDMException.h"
00021 
00022 #include "boost/bind.hpp"
00023 
00024 #include <sstream>
00025 #include <ostream>
00026 #include <iomanip>
00027 #include <algorithm>
00028 
00029 namespace edm {
00030 
00031   ParameterSetDescription::ParameterSetDescription():
00032   anythingAllowed_(false),
00033   unknown_(false) {
00034   }
00035 
00036   ParameterSetDescription::~ParameterSetDescription() {
00037   }
00038 
00039   void
00040   ParameterSetDescription::setComment(std::string const & value)
00041   { comment_ = value; }
00042 
00043   void
00044   ParameterSetDescription::setComment(char const* value)
00045   { comment_ = value; }
00046 
00047   void 
00048   ParameterSetDescription::setAllowAnything()
00049   {
00050     anythingAllowed_ = true;
00051   }
00052 
00053   void 
00054   ParameterSetDescription::setUnknown()
00055   {
00056     unknown_ = true;
00057   }
00058 
00059   ParameterDescriptionNode*
00060   ParameterSetDescription::
00061   addNode(ParameterDescriptionNode const& node) {
00062     std::auto_ptr<ParameterDescriptionNode> clonedNode(node.clone());
00063     return addNode(clonedNode, false, true);
00064   }
00065 
00066   ParameterDescriptionNode*
00067   ParameterSetDescription::
00068   addNode(std::auto_ptr<ParameterDescriptionNode> node) {
00069     return addNode(node, false, true);
00070   }
00071 
00072   ParameterDescriptionNode*
00073   ParameterSetDescription::
00074   addOptionalNode(ParameterDescriptionNode const& node, bool writeToCfi) {
00075     std::auto_ptr<ParameterDescriptionNode> clonedNode(node.clone());
00076     return addNode(clonedNode, true, writeToCfi);
00077   }
00078 
00079   ParameterDescriptionNode*
00080   ParameterSetDescription::
00081   addOptionalNode(std::auto_ptr<ParameterDescriptionNode> node, bool writeToCfi) {
00082     return addNode(node, true, writeToCfi);
00083   }
00084 
00085   ParameterDescriptionNode*
00086   ParameterSetDescription::
00087   addNode(std::auto_ptr<ParameterDescriptionNode> node,
00088       bool optional,
00089       bool writeToCfi) {
00090   
00091     std::set<std::string> nodeLabels;
00092     std::set<ParameterTypes> nodeParameterTypes;
00093     std::set<ParameterTypes> nodeWildcardTypes;
00094     node->checkAndGetLabelsAndTypes(nodeLabels, nodeParameterTypes, nodeWildcardTypes);
00095     throwIfLabelsAlreadyUsed(nodeLabels);
00096     throwIfWildcardCollision(nodeParameterTypes, nodeWildcardTypes);
00097 
00098     SetDescriptionEntry entry;
00099     entry.setOptional(optional);
00100     entry.setWriteToCfi(writeToCfi);
00101     entries_.push_back(entry);
00102     return entries_.back().setNode(node);
00103   }
00104 
00105   void
00106   ParameterSetDescription::validate(ParameterSet & pset) const
00107   {
00108     if (unknown_) return;
00109 
00110     std::set<std::string> validatedLabels;
00111     for_all(entries_,
00112             boost::bind(&ParameterSetDescription::validateNode, _1, boost::ref(pset), boost::ref(validatedLabels)));
00113 
00114     std::vector<std::string> parameterNames = pset.getParameterNames();
00115     if (validatedLabels.size() != parameterNames.size()) {
00116 
00117       // Three labels will be magically inserted into the top level
00118       // of a module ParameterSet even though they are not in the
00119       // python configuration files.  If these are present, then
00120       // assume they are OK and count them as validated.
00121 
00122       std::string module_label("@module_label");
00123       if (pset.exists(module_label)) {
00124         validatedLabels.insert(module_label);
00125       }
00126 
00127       std::string module_type("@module_type");
00128       if (pset.exists(module_type)) {
00129         validatedLabels.insert(module_type);
00130       }
00131 
00132       std::string module_edm_type("@module_edm_type");
00133       if (pset.exists(module_edm_type)) {
00134         validatedLabels.insert(module_edm_type);
00135       }
00136 
00137       std::string service_type("@service_type");
00138       if (pset.exists(service_type)) {
00139         validatedLabels.insert(service_type);
00140       }
00141 
00142       // Try again
00143       if (validatedLabels.size() != parameterNames.size()) {
00144 
00145         if (IllegalParameters::throwAnException() && !anythingAllowed()) {
00146           throwIllegalParameters(parameterNames, validatedLabels);
00147         }
00148       }
00149     }
00150   }
00151 
00152   void
00153   ParameterSetDescription::writeCfi(std::ostream & os,
00154                                     bool startWithComma,
00155                                     int indentation) const {
00156     bool wroteSomething = false;
00157 
00158     for_all(entries_, boost::bind(&ParameterSetDescription::writeNode,
00159                                   _1,
00160                                   boost::ref(os),
00161                                   boost::ref(startWithComma),
00162                                   indentation,
00163                                   boost::ref(wroteSomething)));
00164 
00165     if (wroteSomething) {
00166       char oldFill = os.fill();
00167       os << "\n" << std::setfill(' ') << std::setw(indentation - 2) << "" << std::setfill(oldFill);
00168     }
00169   }
00170 
00171   void ParameterSetDescription::
00172   validateNode(SetDescriptionEntry const& entry,
00173                ParameterSet & pset,
00174                std::set<std::string> & validatedLabels) {
00175     entry.node()->validate(pset, validatedLabels, entry.optional());
00176   }
00177 
00178   void ParameterSetDescription::
00179   print(std::ostream & os, DocFormatHelper & dfh) const {
00180 
00181     if (isUnknown()) {
00182       dfh.indent(os);
00183       os << "Description is unknown.  The configured PSet will not be validated\n";
00184       dfh.indent(os);
00185       os << "because the plugin has not defined this parameter set description.\n";
00186       if (!dfh.brief()) os << "\n";
00187     }
00188 
00189     if (anythingAllowed()) {
00190       dfh.indent(os);
00191       os << "Description allows anything. If the configured PSet contains illegal parameters,\n";
00192       dfh.indent(os);
00193       os << "then validation will ignore them instead of throwing an exception.\n";
00194       if (!dfh.brief()) os << "\n";
00195     }
00196 
00197     if (entries_.empty()) {
00198       dfh.indent(os);
00199       os << "Description is empty\n";
00200       if (!dfh.brief()) os << "\n";
00201       return;
00202     }
00203 
00204     // Zeroth pass is only to calculate column widths in advance of any printing
00205     dfh.setPass(0);
00206     dfh.setCounter(0);
00207     for_all(entries_, boost::bind(&ParameterSetDescription::printNode,
00208                                   _1,
00209                                   boost::ref(os),
00210                                   boost::ref(dfh)));
00211 
00212     // First pass prints top level parameters and references to structure
00213     dfh.setPass(1);
00214     dfh.setCounter(0);
00215     for_all(entries_, boost::bind(&ParameterSetDescription::printNode,
00216                                   _1,
00217                                   boost::ref(os),
00218                                   boost::ref(dfh)));
00219 
00220     // Second pass prints substructure that goes into different sections of the
00221     // output document
00222     dfh.setPass(2);
00223     dfh.setCounter(0);
00224     for_all(entries_, boost::bind(&ParameterSetDescription::printNode,
00225                                   _1,
00226                                   boost::ref(os),
00227                                   boost::ref(dfh)));
00228   }
00229 
00230   bool
00231   ParameterSetDescription::
00232   isLabelUnused(std::string const& label) const {
00233     return usedLabels_.find(label) == usedLabels_.end();
00234   }
00235 
00236   void
00237   ParameterSetDescription::throwIllegalParameters(
00238     std::vector<std::string> const& parameterNames,
00239     std::set<std::string> const& validatedLabels) {
00240 
00241     std::set<std::string> parNames(parameterNames.begin(), parameterNames.end());
00242 
00243 
00244     std::set<std::string> diffNames;
00245     std::insert_iterator<std::set<std::string> > insertIter(diffNames, diffNames.begin());
00246     std::set_difference(parNames.begin(), parNames.end(),
00247                         validatedLabels.begin(), validatedLabels.end(),
00248                         insertIter);
00249 
00250     std::stringstream ss;
00251     for (std::set<std::string>::const_iterator iter = diffNames.begin(),
00252                                                iEnd = diffNames.end();
00253          iter != iEnd;
00254          ++iter) {
00255       ss << " '" << *iter <<  "'\n";
00256     }
00257     if (diffNames.size() == 1U) {
00258       throw edm::Exception(errors::Configuration)
00259         << "Illegal parameter found in configuration.  The parameter is named:\n" 
00260         << ss.str()
00261         << "You could be trying to use a parameter name that is not\n"
00262         << "allowed for this plugin or it could be misspelled.\n";
00263     }
00264     else {
00265       throw edm::Exception(errors::Configuration)
00266         << "Illegal parameters found in configuration.  The parameters are named:\n" 
00267         << ss.str()
00268         << "You could be trying to use parameter names that are not\n"
00269         << "allowed for this plugin or they could be misspelled.\n";
00270     }
00271   }
00272 
00273   void
00274   ParameterSetDescription::writeNode(SetDescriptionEntry const& entry,
00275                                      std::ostream & os,
00276                                      bool & startWithComma,
00277                                      int indentation,
00278                                      bool & wroteSomething) {
00279     if (entry.writeToCfi()) {
00280       entry.node()->writeCfi(os, startWithComma, indentation, wroteSomething);
00281     }
00282   }
00283 
00284   void
00285   ParameterSetDescription::printNode(SetDescriptionEntry const& entry,
00286                                      std::ostream & os,
00287                                      DocFormatHelper & dfh) {
00288     if (dfh.pass() < 2) {
00289       entry.node()->print(os, entry.optional(), entry.writeToCfi(), dfh);
00290     }
00291     else {
00292       entry.node()->printNestedContent(os, entry.optional(), dfh);
00293     }
00294   }
00295 
00296   void
00297   ParameterSetDescription::
00298   throwIfLabelsAlreadyUsed(std::set<std::string> const& nodeLabels) {
00299 
00300     std::set<std::string> duplicateLabels;
00301     std::insert_iterator<std::set<std::string> > insertIter(duplicateLabels, duplicateLabels.begin());
00302     std::set_intersection(nodeLabels.begin(), nodeLabels.end(),
00303                           usedLabels_.begin(), usedLabels_.end(),
00304                           insertIter);
00305     if (duplicateLabels.empty()) {
00306       usedLabels_.insert(nodeLabels.begin(), nodeLabels.end());
00307     }
00308     else {
00309 
00310       std::stringstream ss;
00311       for (std::set<std::string>::const_iterator iter = duplicateLabels.begin(),
00312                                                  iEnd = duplicateLabels.end();
00313            iter != iEnd;
00314            ++iter) {
00315         ss << " \"" << *iter <<  "\"\n";
00316       }
00317       throw edm::Exception(errors::LogicError)
00318         << "Labels used in different nodes of a ParameterSetDescription\n"
00319         << "must be unique.  The following duplicate labels were detected:\n"
00320         << ss.str()
00321         << "\n";
00322     }
00323   }
00324 
00325   void
00326   ParameterSetDescription::
00327   throwIfWildcardCollision(std::set<ParameterTypes> const& nodeParameterTypes,
00328                            std::set<ParameterTypes> const& nodeWildcardTypes) {
00329 
00330     // 1. Check that the new wildcard types do not collide with the existing
00331     // parameter types.
00332     // 2. Check that the new parameter types do not collide with the existing
00333     // wildcard types.
00334     // 3. Then insert them.
00335     // The order of those steps is important because a wildcard with a default
00336     // value could insert a type in both sets and this is OK.
00337 
00338     // We assume the node already checked for collisions between the new parameter
00339     // types and the new wildcard types before passing the sets to this function.
00340 
00341     if (!nodeWildcardTypes.empty()) {
00342 
00343       std::set<ParameterTypes> duplicateTypes1;
00344       std::insert_iterator<std::set<ParameterTypes> > insertIter1(duplicateTypes1, duplicateTypes1.begin());
00345       std::set_intersection(typesUsedForParameters_.begin(), typesUsedForParameters_.end(),
00346                             nodeWildcardTypes.begin(), nodeWildcardTypes.end(),
00347                             insertIter1);
00348 
00349       if (!duplicateTypes1.empty()) {
00350 
00351         std::stringstream ss;
00352         for (std::set<ParameterTypes>::const_iterator iter = duplicateTypes1.begin(),
00353                                                       iEnd = duplicateTypes1.end();
00354              iter != iEnd;
00355              ++iter) {
00356           ss << " \"" << parameterTypeEnumToString(*iter) <<  "\"\n";
00357         }
00358         throw edm::Exception(errors::LogicError)
00359           << "Within a ParameterSetDescription, the type used for a wildcard must\n"
00360           << "not be the same as the type used for other parameters. This rule\n"
00361           << "is violated for the following types:\n"
00362           << ss.str()
00363           << "\n";
00364       }
00365     }
00366 
00367     if (!typesUsedForWildcards_.empty()) {
00368 
00369       std::set<ParameterTypes> duplicateTypes2;
00370       std::insert_iterator<std::set<ParameterTypes> > insertIter2(duplicateTypes2, duplicateTypes2.begin());
00371       std::set_intersection(typesUsedForWildcards_.begin(), typesUsedForWildcards_.end(),
00372                             nodeParameterTypes.begin(), nodeParameterTypes.end(),
00373                             insertIter2);
00374 
00375       if (!duplicateTypes2.empty()) {
00376 
00377         std::stringstream ss;
00378         for (std::set<ParameterTypes>::const_iterator iter = duplicateTypes2.begin(),
00379                                                       iEnd = duplicateTypes2.end();
00380              iter != iEnd;
00381              ++iter) {
00382           ss << " \"" << parameterTypeEnumToString(*iter) <<  "\"\n";
00383         }
00384         throw edm::Exception(errors::LogicError)
00385           << "Within a ParameterSetDescription, the type used for a wildcard must\n"
00386           << "not be the same as the type used for other parameters. This rule is\n"
00387           << "violated for the following types :\n"
00388           << ss.str()
00389           << "\n";
00390       }
00391     }
00392 
00393     typesUsedForParameters_.insert(nodeParameterTypes.begin(), nodeParameterTypes.end());
00394     typesUsedForWildcards_.insert(nodeWildcardTypes.begin(), nodeWildcardTypes.end());
00395   }
00396 
00397   ParameterDescriptionNode*
00398   ParameterSetDescription::
00399   ifExists(ParameterDescriptionNode const& node1,
00400            ParameterDescriptionNode const& node2,
00401            bool optional, bool writeToCfi) {
00402     std::auto_ptr<ParameterDescriptionNode> pdIfExists(new IfExistsDescription(node1, node2));
00403     return addNode(pdIfExists, optional, writeToCfi);
00404   }
00405 }