CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_4_1_8_patch9/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/DocFormatHelper.h"
00018 #include "FWCore/Utilities/interface/Algorithms.h"
00019 #include "FWCore/Utilities/interface/EDMException.h"
00020 
00021 #include "boost/bind.hpp"
00022 
00023 #include <sstream>
00024 #include <ostream>
00025 #include <iomanip>
00026 #include <algorithm>
00027 
00028 namespace edm {
00029 
00030   ParameterSetDescription::ParameterSetDescription():
00031   anythingAllowed_(false),
00032   unknown_(false) {
00033   }
00034 
00035   ParameterSetDescription::~ParameterSetDescription() {
00036   }
00037 
00038   void
00039   ParameterSetDescription::setComment(std::string const & value)
00040   { comment_ = value; }
00041 
00042   void
00043   ParameterSetDescription::setComment(char const* value)
00044   { comment_ = value; }
00045 
00046   void 
00047   ParameterSetDescription::setAllowAnything()
00048   {
00049     anythingAllowed_ = true;
00050   }
00051 
00052   void 
00053   ParameterSetDescription::setUnknown()
00054   {
00055     unknown_ = true;
00056   }
00057 
00058   ParameterDescriptionNode*
00059   ParameterSetDescription::
00060   addNode(ParameterDescriptionNode const& node) {
00061     std::auto_ptr<ParameterDescriptionNode> clonedNode(node.clone());
00062     return addNode(clonedNode, false, true);
00063   }
00064 
00065   ParameterDescriptionNode*
00066   ParameterSetDescription::
00067   addNode(std::auto_ptr<ParameterDescriptionNode> node) {
00068     return addNode(node, false, true);
00069   }
00070 
00071   ParameterDescriptionNode*
00072   ParameterSetDescription::
00073   addOptionalNode(ParameterDescriptionNode const& node, bool writeToCfi) {
00074     std::auto_ptr<ParameterDescriptionNode> clonedNode(node.clone());
00075     return addNode(clonedNode, true, writeToCfi);
00076   }
00077 
00078   ParameterDescriptionNode*
00079   ParameterSetDescription::
00080   addOptionalNode(std::auto_ptr<ParameterDescriptionNode> node, bool writeToCfi) {
00081     return addNode(node, true, writeToCfi);
00082   }
00083 
00084   ParameterDescriptionNode*
00085   ParameterSetDescription::
00086   addNode(std::auto_ptr<ParameterDescriptionNode> node,
00087       bool optional,
00088       bool writeToCfi) {
00089   
00090     std::set<std::string> nodeLabels;
00091     std::set<ParameterTypes> nodeParameterTypes;
00092     std::set<ParameterTypes> nodeWildcardTypes;
00093     node->checkAndGetLabelsAndTypes(nodeLabels, nodeParameterTypes, nodeWildcardTypes);
00094     throwIfLabelsAlreadyUsed(nodeLabels);
00095     throwIfWildcardCollision(nodeParameterTypes, nodeWildcardTypes);
00096 
00097     SetDescriptionEntry entry;
00098     entry.setOptional(optional);
00099     entry.setWriteToCfi(writeToCfi);
00100     entries_.push_back(entry);
00101     ParameterDescriptionNode* returnValue = node.get();
00102     entries_.back().setNode(node);
00103     return returnValue;
00104   }
00105 
00106   void
00107   ParameterSetDescription::validate(ParameterSet & pset) const
00108   {
00109     if (unknown_ || anythingAllowed()) return;
00110 
00111     std::set<std::string> validatedLabels;
00112     for_all(entries_,
00113             boost::bind(&ParameterSetDescription::validateNode, _1, boost::ref(pset), boost::ref(validatedLabels)));
00114 
00115     std::vector<std::string> parameterNames = pset.getParameterNames();
00116     if (validatedLabels.size() != parameterNames.size()) {
00117 
00118       // Three labels will be magically inserted into the top level
00119       // of a module ParameterSet even though they are not in the
00120       // python configuration files.  If these are present, then
00121       // assume they are OK and count them as validated.
00122 
00123       std::string module_label("@module_label");
00124       if (pset.exists(module_label)) {
00125         validatedLabels.insert(module_label);
00126       }
00127 
00128       std::string module_type("@module_type");
00129       if (pset.exists(module_type)) {
00130         validatedLabels.insert(module_type);
00131       }
00132 
00133       std::string module_edm_type("@module_edm_type");
00134       if (pset.exists(module_edm_type)) {
00135         validatedLabels.insert(module_edm_type);
00136       }
00137 
00138       std::string service_type("@service_type");
00139       if (pset.exists(service_type)) {
00140         validatedLabels.insert(service_type);
00141       }
00142 
00143       // Try again
00144       if (validatedLabels.size() != parameterNames.size()) {
00145 
00146         throwIllegalParameters(parameterNames, validatedLabels);
00147       }
00148     }
00149   }
00150 
00151   void
00152   ParameterSetDescription::writeCfi(std::ostream & os,
00153                                     bool startWithComma,
00154                                     int indentation) const {
00155     bool wroteSomething = false;
00156 
00157     for_all(entries_, boost::bind(&ParameterSetDescription::writeNode,
00158                                   _1,
00159                                   boost::ref(os),
00160                                   boost::ref(startWithComma),
00161                                   indentation,
00162                                   boost::ref(wroteSomething)));
00163 
00164     if (wroteSomething) {
00165       char oldFill = os.fill();
00166       os << "\n" << std::setfill(' ') << std::setw(indentation - 2) << "";
00167       os.fill(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 and requires nothing.\n";
00192       dfh.indent(os);
00193       os << "The configured PSet will not be validated.\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   void
00231   ParameterSetDescription::throwIllegalParameters(
00232     std::vector<std::string> const& parameterNames,
00233     std::set<std::string> const& validatedLabels) {
00234 
00235     std::set<std::string> parNames(parameterNames.begin(), parameterNames.end());
00236 
00237 
00238     std::set<std::string> diffNames;
00239     std::insert_iterator<std::set<std::string> > insertIter(diffNames, diffNames.begin());
00240     std::set_difference(parNames.begin(), parNames.end(),
00241                         validatedLabels.begin(), validatedLabels.end(),
00242                         insertIter);
00243 
00244     std::stringstream ss;
00245     for (std::set<std::string>::const_iterator iter = diffNames.begin(),
00246                                                iEnd = diffNames.end();
00247          iter != iEnd;
00248          ++iter) {
00249       ss << " \"" << *iter <<  "\"\n";
00250     }
00251     if (diffNames.size() == 1U) {
00252       throw edm::Exception(errors::Configuration)
00253         << "Illegal parameter found in configuration.  The parameter is named:\n" 
00254         << ss.str()
00255         << "You could be trying to use a parameter name that is not\n"
00256         << "allowed for this plugin or it could be misspelled.\n";
00257     }
00258     else {
00259       throw edm::Exception(errors::Configuration)
00260         << "Illegal parameters found in configuration.  The parameters are named:\n" 
00261         << ss.str()
00262         << "You could be trying to use parameter names that are not\n"
00263         << "allowed for this plugin or they could be misspelled.\n";
00264     }
00265   }
00266 
00267   void
00268   ParameterSetDescription::writeNode(SetDescriptionEntry const& entry,
00269                                      std::ostream & os,
00270                                      bool & startWithComma,
00271                                      int indentation,
00272                                      bool & wroteSomething) {
00273     if (entry.writeToCfi()) {
00274       entry.node()->writeCfi(os, startWithComma, indentation, wroteSomething);
00275     }
00276   }
00277 
00278   void
00279   ParameterSetDescription::printNode(SetDescriptionEntry const& entry,
00280                                      std::ostream & os,
00281                                      DocFormatHelper & dfh) {
00282     if (dfh.pass() < 2) {
00283       entry.node()->print(os, entry.optional(), entry.writeToCfi(), dfh);
00284     }
00285     else {
00286       entry.node()->printNestedContent(os, entry.optional(), dfh);
00287     }
00288   }
00289 
00290   void
00291   ParameterSetDescription::
00292   throwIfLabelsAlreadyUsed(std::set<std::string> const& nodeLabels) {
00293 
00294     std::set<std::string> duplicateLabels;
00295     std::insert_iterator<std::set<std::string> > insertIter(duplicateLabels, duplicateLabels.begin());
00296     std::set_intersection(nodeLabels.begin(), nodeLabels.end(),
00297                           usedLabels_.begin(), usedLabels_.end(),
00298                           insertIter);
00299     if (duplicateLabels.empty()) {
00300       usedLabels_.insert(nodeLabels.begin(), nodeLabels.end());
00301     }
00302     else {
00303 
00304       std::stringstream ss;
00305       for (std::set<std::string>::const_iterator iter = duplicateLabels.begin(),
00306                                                  iEnd = duplicateLabels.end();
00307            iter != iEnd;
00308            ++iter) {
00309         ss << " \"" << *iter <<  "\"\n";
00310       }
00311       throw edm::Exception(errors::LogicError)
00312         << "Labels used in different nodes of a ParameterSetDescription\n"
00313         << "must be unique.  The following duplicate labels were detected:\n"
00314         << ss.str()
00315         << "\n";
00316     }
00317   }
00318 
00319   void
00320   ParameterSetDescription::
00321   throwIfWildcardCollision(std::set<ParameterTypes> const& nodeParameterTypes,
00322                            std::set<ParameterTypes> const& nodeWildcardTypes) {
00323 
00324     // 1. Check that the new wildcard types do not collide with the existing
00325     // parameter types.
00326     // 2. Check that the new parameter types do not collide with the existing
00327     // wildcard types.
00328     // 3. Then insert them.
00329     // The order of those steps is important because a wildcard with a default
00330     // value could insert a type in both sets and this is OK.
00331 
00332     // We assume the node already checked for collisions between the new parameter
00333     // types and the new wildcard types before passing the sets to this function.
00334 
00335     if (!nodeWildcardTypes.empty()) {
00336 
00337       std::set<ParameterTypes> duplicateTypes1;
00338       std::insert_iterator<std::set<ParameterTypes> > insertIter1(duplicateTypes1, duplicateTypes1.begin());
00339       std::set_intersection(typesUsedForParameters_.begin(), typesUsedForParameters_.end(),
00340                             nodeWildcardTypes.begin(), nodeWildcardTypes.end(),
00341                             insertIter1);
00342 
00343       if (!duplicateTypes1.empty()) {
00344 
00345         std::stringstream ss;
00346         for (std::set<ParameterTypes>::const_iterator iter = duplicateTypes1.begin(),
00347                                                       iEnd = duplicateTypes1.end();
00348              iter != iEnd;
00349              ++iter) {
00350           ss << " \"" << parameterTypeEnumToString(*iter) <<  "\"\n";
00351         }
00352         throw edm::Exception(errors::LogicError)
00353           << "Within a ParameterSetDescription, the type used for a wildcard must\n"
00354           << "not be the same as the type used for other parameters. This rule\n"
00355           << "is violated for the following types:\n"
00356           << ss.str()
00357           << "\n";
00358       }
00359     }
00360 
00361     if (!typesUsedForWildcards_.empty()) {
00362 
00363       std::set<ParameterTypes> duplicateTypes2;
00364       std::insert_iterator<std::set<ParameterTypes> > insertIter2(duplicateTypes2, duplicateTypes2.begin());
00365       std::set_intersection(typesUsedForWildcards_.begin(), typesUsedForWildcards_.end(),
00366                             nodeParameterTypes.begin(), nodeParameterTypes.end(),
00367                             insertIter2);
00368 
00369       if (!duplicateTypes2.empty()) {
00370 
00371         std::stringstream ss;
00372         for (std::set<ParameterTypes>::const_iterator iter = duplicateTypes2.begin(),
00373                                                       iEnd = duplicateTypes2.end();
00374              iter != iEnd;
00375              ++iter) {
00376           ss << " \"" << parameterTypeEnumToString(*iter) <<  "\"\n";
00377         }
00378         throw edm::Exception(errors::LogicError)
00379           << "Within a ParameterSetDescription, the type used for a wildcard must\n"
00380           << "not be the same as the type used for other parameters. This rule is\n"
00381           << "violated for the following types :\n"
00382           << ss.str()
00383           << "\n";
00384       }
00385     }
00386 
00387     typesUsedForParameters_.insert(nodeParameterTypes.begin(), nodeParameterTypes.end());
00388     typesUsedForWildcards_.insert(nodeWildcardTypes.begin(), nodeWildcardTypes.end());
00389   }
00390 
00391   ParameterDescriptionNode*
00392   ParameterSetDescription::
00393   ifExists(ParameterDescriptionNode const& node1,
00394            ParameterDescriptionNode const& node2,
00395            bool optional, bool writeToCfi) {
00396     std::auto_ptr<ParameterDescriptionNode> pdIfExists(new IfExistsDescription(node1, node2));
00397     return addNode(pdIfExists, optional, writeToCfi);
00398   }
00399 }