Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-03-17 11:03:28

0001 // -*- C++ -*-
0002 //
0003 // Package:     ParameterSet
0004 // Class  :     ParameterSetDescription
0005 //
0006 // Implementation:
0007 //     <Notes on implementation>
0008 //
0009 // Original Author:  Chris Jones
0010 //         Created:  Tue Jul 31 15:30:35 EDT 2007
0011 //
0012 
0013 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
0014 
0015 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0016 #include "FWCore/ParameterSet/interface/IfExistsDescription.h"
0017 #include "FWCore/ParameterSet/interface/IllegalParameters.h"
0018 #include "FWCore/ParameterSet/interface/DocFormatHelper.h"
0019 #include "FWCore/Utilities/interface/Algorithms.h"
0020 #include "FWCore/Utilities/interface/EDMException.h"
0021 
0022 #include <sstream>
0023 #include <ostream>
0024 #include <iomanip>
0025 #include <algorithm>
0026 
0027 namespace edm {
0028 
0029   ParameterSetDescription::ParameterSetDescription() : anythingAllowed_(false), unknown_(false) {}
0030 
0031   ParameterSetDescription::~ParameterSetDescription() {}
0032 
0033   void ParameterSetDescription::setComment(std::string const& value) { comment_ = value; }
0034 
0035   void ParameterSetDescription::setComment(char const* value) { comment_ = value; }
0036 
0037   void ParameterSetDescription::setAllowAnything() { anythingAllowed_ = true; }
0038 
0039   void ParameterSetDescription::setUnknown() { unknown_ = true; }
0040 
0041   ParameterDescriptionNode* ParameterSetDescription::addNode(ParameterDescriptionNode const& node) {
0042     std::unique_ptr<ParameterDescriptionNode> clonedNode(node.clone());
0043     return addNode(std::move(clonedNode), false, true);
0044   }
0045 
0046   ParameterDescriptionNode* ParameterSetDescription::addNode(std::unique_ptr<ParameterDescriptionNode> node) {
0047     return addNode(std::move(node), false, true);
0048   }
0049 
0050   ParameterDescriptionNode* ParameterSetDescription::addOptionalNode(ParameterDescriptionNode const& node,
0051                                                                      bool writeToCfi) {
0052     std::unique_ptr<ParameterDescriptionNode> clonedNode(node.clone());
0053     return addNode(std::move(clonedNode), true, writeToCfi);
0054   }
0055 
0056   ParameterDescriptionNode* ParameterSetDescription::addOptionalNode(std::unique_ptr<ParameterDescriptionNode> node,
0057                                                                      bool writeToCfi) {
0058     return addNode(std::move(node), true, writeToCfi);
0059   }
0060 
0061   ParameterDescriptionNode* ParameterSetDescription::addNode(std::unique_ptr<ParameterDescriptionNode> node,
0062                                                              bool optional,
0063                                                              bool writeToCfi) {
0064     std::set<std::string> nodeLabels;
0065     std::set<ParameterTypes> nodeParameterTypes;
0066     std::set<ParameterTypes> nodeWildcardTypes;
0067     node->checkAndGetLabelsAndTypes(nodeLabels, nodeParameterTypes, nodeWildcardTypes);
0068     throwIfLabelsAlreadyUsed(nodeLabels);
0069     throwIfWildcardCollision(nodeParameterTypes, nodeWildcardTypes);
0070 
0071     SetDescriptionEntry entry;
0072     entry.setOptional(optional);
0073     entry.setWriteToCfi(writeToCfi);
0074     entries_.push_back(entry);
0075     return entries_.back().setNode(std::move(node));
0076   }
0077 
0078   void ParameterSetDescription::validate(ParameterSet& pset) const {
0079     using std::placeholders::_1;
0080     if (unknown_)
0081       return;
0082 
0083     std::set<std::string> validatedLabels;
0084     for_all(entries_, std::bind(&ParameterSetDescription::validateNode, _1, std::ref(pset), std::ref(validatedLabels)));
0085 
0086     std::vector<std::string> parameterNames = pset.getParameterNames();
0087     if (validatedLabels.size() != parameterNames.size()) {
0088       // Three labels will be magically inserted into the top level
0089       // of a module ParameterSet even though they are not in the
0090       // python configuration files.  If these are present, then
0091       // assume they are OK and count them as validated.
0092 
0093       std::string module_label("@module_label");
0094       if (pset.exists(module_label)) {
0095         validatedLabels.insert(module_label);
0096       }
0097 
0098       std::string module_type("@module_type");
0099       if (pset.exists(module_type)) {
0100         validatedLabels.insert(module_type);
0101       }
0102 
0103       std::string module_edm_type("@module_edm_type");
0104       if (pset.exists(module_edm_type)) {
0105         validatedLabels.insert(module_edm_type);
0106       }
0107 
0108       std::string service_type("@service_type");
0109       if (pset.exists(service_type)) {
0110         validatedLabels.insert(service_type);
0111       }
0112 
0113       // Try again
0114       if (validatedLabels.size() != parameterNames.size()) {
0115         if (IllegalParameters::throwAnException() && !anythingAllowed()) {
0116           throwIllegalParameters(parameterNames, validatedLabels);
0117         }
0118       }
0119     }
0120   }
0121 
0122   void ParameterSetDescription::writeCfi(std::ostream& os, bool startWithComma, int indentation) const {
0123     using std::placeholders::_1;
0124     bool wroteSomething = false;
0125 
0126     for_all(entries_,
0127             std::bind(&ParameterSetDescription::writeNode,
0128                       _1,
0129                       std::ref(os),
0130                       std::ref(startWithComma),
0131                       indentation,
0132                       std::ref(wroteSomething)));
0133 
0134     if (wroteSomething) {
0135       char oldFill = os.fill();
0136       os << "\n" << std::setfill(' ') << std::setw(indentation - 2) << "" << std::setfill(oldFill);
0137     }
0138   }
0139 
0140   void ParameterSetDescription::validateNode(SetDescriptionEntry const& entry,
0141                                              ParameterSet& pset,
0142                                              std::set<std::string>& validatedLabels) {
0143     entry.node()->validate(pset, validatedLabels, entry.optional());
0144   }
0145 
0146   void ParameterSetDescription::print(std::ostream& os, DocFormatHelper& dfh) const {
0147     using std::placeholders::_1;
0148     if (isUnknown()) {
0149       dfh.indent(os);
0150       os << "Description is unknown.  The configured PSet will not be validated\n";
0151       dfh.indent(os);
0152       os << "because the plugin has not defined this parameter set description.\n";
0153       if (!dfh.brief())
0154         os << "\n";
0155     }
0156 
0157     if (anythingAllowed()) {
0158       dfh.indent(os);
0159       os << "Description allows anything. If the configured PSet contains illegal parameters,\n";
0160       dfh.indent(os);
0161       os << "then validation will ignore them instead of throwing an exception.\n";
0162       if (!dfh.brief())
0163         os << "\n";
0164     }
0165 
0166     if (entries_.empty()) {
0167       dfh.indent(os);
0168       os << "Description is empty\n";
0169       if (!dfh.brief())
0170         os << "\n";
0171       return;
0172     }
0173 
0174     // Zeroth pass is only to calculate column widths in advance of any printing
0175     dfh.setPass(0);
0176     dfh.setCounter(0);
0177     for_all(entries_, std::bind(&ParameterSetDescription::printNode, _1, std::ref(os), std::ref(dfh)));
0178 
0179     // First pass prints top level parameters and references to structure
0180     dfh.setPass(1);
0181     dfh.setCounter(0);
0182     for_all(entries_, std::bind(&ParameterSetDescription::printNode, _1, std::ref(os), std::ref(dfh)));
0183 
0184     // Second pass prints substructure that goes into different sections of the
0185     // output document
0186     dfh.setPass(2);
0187     dfh.setCounter(0);
0188     for_all(entries_, std::bind(&ParameterSetDescription::printNode, _1, std::ref(os), std::ref(dfh)));
0189   }
0190 
0191   bool ParameterSetDescription::isLabelUnused(std::string const& label) const {
0192     return usedLabels_.find(label) == usedLabels_.end();
0193   }
0194 
0195   void ParameterSetDescription::throwIllegalParameters(std::vector<std::string> const& parameterNames,
0196                                                        std::set<std::string> const& validatedLabels) {
0197     std::set<std::string> parNames(parameterNames.begin(), parameterNames.end());
0198 
0199     std::set<std::string> diffNames;
0200     std::insert_iterator<std::set<std::string> > insertIter(diffNames, diffNames.begin());
0201     std::set_difference(parNames.begin(), parNames.end(), validatedLabels.begin(), validatedLabels.end(), insertIter);
0202 
0203     std::stringstream ss;
0204     for (std::set<std::string>::const_iterator iter = diffNames.begin(), iEnd = diffNames.end(); iter != iEnd; ++iter) {
0205       ss << " '" << *iter << "'\n";
0206     }
0207     if (diffNames.size() == 1U) {
0208       throw edm::Exception(errors::Configuration)
0209           << "Illegal parameter found in configuration.  The parameter is named:\n"
0210           << ss.str() << "You could be trying to use a parameter name that is not\n"
0211           << "allowed for this plugin or it could be misspelled.\n";
0212     } else {
0213       throw edm::Exception(errors::Configuration)
0214           << "Illegal parameters found in configuration.  The parameters are named:\n"
0215           << ss.str() << "You could be trying to use parameter names that are not\n"
0216           << "allowed for this plugin or they could be misspelled.\n";
0217     }
0218   }
0219 
0220   void ParameterSetDescription::writeNode(
0221       SetDescriptionEntry const& entry, std::ostream& os, bool& startWithComma, int indentation, bool& wroteSomething) {
0222     if (entry.writeToCfi()) {
0223       entry.node()->writeCfi(os, entry.optional(), startWithComma, indentation, wroteSomething);
0224     }
0225   }
0226 
0227   void ParameterSetDescription::printNode(SetDescriptionEntry const& entry, std::ostream& os, DocFormatHelper& dfh) {
0228     if (dfh.pass() < 2) {
0229       entry.node()->print(os, entry.optional(), entry.writeToCfi(), dfh);
0230     } else {
0231       entry.node()->printNestedContent(os, entry.optional(), dfh);
0232     }
0233   }
0234 
0235   void ParameterSetDescription::throwIfLabelsAlreadyUsed(std::set<std::string> const& nodeLabels) {
0236     std::set<std::string> duplicateLabels;
0237     std::insert_iterator<std::set<std::string> > insertIter(duplicateLabels, duplicateLabels.begin());
0238     std::set_intersection(nodeLabels.begin(), nodeLabels.end(), usedLabels_.begin(), usedLabels_.end(), insertIter);
0239     if (duplicateLabels.empty()) {
0240       usedLabels_.insert(nodeLabels.begin(), nodeLabels.end());
0241     } else {
0242       std::stringstream ss;
0243       for (std::set<std::string>::const_iterator iter = duplicateLabels.begin(), iEnd = duplicateLabels.end();
0244            iter != iEnd;
0245            ++iter) {
0246         ss << " \"" << *iter << "\"\n";
0247       }
0248       throw edm::Exception(errors::LogicError) << "Labels used in different nodes of a ParameterSetDescription\n"
0249                                                << "must be unique.  The following duplicate labels were detected:\n"
0250                                                << ss.str() << "\n";
0251     }
0252   }
0253 
0254   void ParameterSetDescription::throwIfWildcardCollision(std::set<ParameterTypes> const& nodeParameterTypes,
0255                                                          std::set<ParameterTypes> const& nodeWildcardTypes) {
0256     // 1. Check that the new wildcard types do not collide with the existing
0257     // parameter types.
0258     // 2. Check that the new parameter types do not collide with the existing
0259     // wildcard types.
0260     // 3. Then insert them.
0261     // The order of those steps is important because a wildcard with a default
0262     // value could insert a type in both sets and this is OK.
0263 
0264     // We assume the node already checked for collisions between the new parameter
0265     // types and the new wildcard types before passing the sets to this function.
0266 
0267     if (!nodeWildcardTypes.empty()) {
0268       std::set<ParameterTypes> duplicateTypes1;
0269       std::insert_iterator<std::set<ParameterTypes> > insertIter1(duplicateTypes1, duplicateTypes1.begin());
0270       std::set_intersection(typesUsedForParameters_.begin(),
0271                             typesUsedForParameters_.end(),
0272                             nodeWildcardTypes.begin(),
0273                             nodeWildcardTypes.end(),
0274                             insertIter1);
0275 
0276       if (!duplicateTypes1.empty()) {
0277         std::stringstream ss;
0278         for (std::set<ParameterTypes>::const_iterator iter = duplicateTypes1.begin(), iEnd = duplicateTypes1.end();
0279              iter != iEnd;
0280              ++iter) {
0281           ss << " \"" << parameterTypeEnumToString(*iter) << "\"\n";
0282         }
0283         throw edm::Exception(errors::LogicError)
0284             << "Within a ParameterSetDescription, the type used for a wildcard must\n"
0285             << "not be the same as the type used for other parameters. This rule\n"
0286             << "is violated for the following types:\n"
0287             << ss.str() << "\n";
0288       }
0289     }
0290 
0291     if (!typesUsedForWildcards_.empty()) {
0292       std::set<ParameterTypes> duplicateTypes2;
0293       std::insert_iterator<std::set<ParameterTypes> > insertIter2(duplicateTypes2, duplicateTypes2.begin());
0294       std::set_intersection(typesUsedForWildcards_.begin(),
0295                             typesUsedForWildcards_.end(),
0296                             nodeParameterTypes.begin(),
0297                             nodeParameterTypes.end(),
0298                             insertIter2);
0299 
0300       if (!duplicateTypes2.empty()) {
0301         std::stringstream ss;
0302         for (std::set<ParameterTypes>::const_iterator iter = duplicateTypes2.begin(), iEnd = duplicateTypes2.end();
0303              iter != iEnd;
0304              ++iter) {
0305           ss << " \"" << parameterTypeEnumToString(*iter) << "\"\n";
0306         }
0307         throw edm::Exception(errors::LogicError)
0308             << "Within a ParameterSetDescription, the type used for a wildcard must\n"
0309             << "not be the same as the type used for other parameters. This rule is\n"
0310             << "violated for the following types :\n"
0311             << ss.str() << "\n";
0312       }
0313     }
0314 
0315     typesUsedForParameters_.insert(nodeParameterTypes.begin(), nodeParameterTypes.end());
0316     typesUsedForWildcards_.insert(nodeWildcardTypes.begin(), nodeWildcardTypes.end());
0317   }
0318 
0319   ParameterDescriptionNode* ParameterSetDescription::ifExists(ParameterDescriptionNode const& node1,
0320                                                               ParameterDescriptionNode const& node2,
0321                                                               bool optional,
0322                                                               bool writeToCfi) {
0323     std::unique_ptr<ParameterDescriptionNode> pdIfExists = std::make_unique<IfExistsDescription>(node1, node2);
0324     return addNode(std::move(pdIfExists), optional, writeToCfi);
0325   }
0326 }  // namespace edm