Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2025-03-26 01:51:14

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), Modifier::kNone, true);
0044   }
0045 
0046   ParameterDescriptionNode* ParameterSetDescription::addNode(std::unique_ptr<ParameterDescriptionNode> node) {
0047     return addNode(std::move(node), Modifier::kNone, 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), Modifier::kOptional, writeToCfi);
0054   }
0055 
0056   ParameterDescriptionNode* ParameterSetDescription::addOptionalNode(std::unique_ptr<ParameterDescriptionNode> node,
0057                                                                      bool writeToCfi) {
0058     return addNode(std::move(node), Modifier::kOptional, writeToCfi);
0059   }
0060 
0061   ParameterDescriptionNode* ParameterSetDescription::addNode(std::unique_ptr<ParameterDescriptionNode> node,
0062                                                              Modifier modifier,
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.setModifier(modifier);
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       // These 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       {
0114         std::string tryToContinue("@shouldTryToContinue");
0115         if (pset.exists(tryToContinue)) {
0116           validatedLabels.insert(tryToContinue);
0117         }
0118       }
0119       // Try again
0120       if (validatedLabels.size() != parameterNames.size()) {
0121         if (IllegalParameters::throwAnException() && !anythingAllowed()) {
0122           throwIllegalParameters(parameterNames, validatedLabels);
0123         }
0124       }
0125     }
0126   }
0127 
0128   void ParameterSetDescription::writeCfi(std::ostream& os,
0129                                          bool startWithComma,
0130                                          int indentation,
0131                                          CfiOptions& options) const {
0132     bool wroteSomething = false;
0133 
0134     bool seenWildcard = false;
0135     bool seenMultipleWildcards = false;
0136     for (auto const& entry : entries_) {
0137       //only add the first seen wildcard to the cfi. This avoids possible ambiguities.
0138       if (entry.node()->isWildcard()) {
0139         if (seenWildcard == true) {
0140           seenMultipleWildcards = true;
0141           continue;
0142         }
0143         seenWildcard = true;
0144       }
0145       writeNode(entry, os, startWithComma, indentation, options, wroteSomething);
0146     }
0147 
0148     if ((anythingAllowed() or seenMultipleWildcards)) {
0149       cfi::parameterMustBeTyped(options);
0150     }
0151 
0152     if (wroteSomething) {
0153       char oldFill = os.fill();
0154       os << "\n" << std::setfill(' ') << std::setw(indentation - 2) << "" << std::setfill(oldFill);
0155     }
0156   }
0157 
0158   void ParameterSetDescription::validateNode(SetDescriptionEntry const& entry,
0159                                              ParameterSet& pset,
0160                                              std::set<std::string>& validatedLabels) {
0161     entry.node()->validate(pset, validatedLabels, entry.modifier());
0162   }
0163 
0164   void ParameterSetDescription::print(std::ostream& os, DocFormatHelper& dfh) const {
0165     using std::placeholders::_1;
0166     if (isUnknown()) {
0167       dfh.indent(os);
0168       os << "Description is unknown.  The configured PSet will not be validated\n";
0169       dfh.indent(os);
0170       os << "because the plugin has not defined this parameter set description.\n";
0171       if (!dfh.brief())
0172         os << "\n";
0173     }
0174 
0175     if (anythingAllowed()) {
0176       dfh.indent(os);
0177       os << "Description allows anything. If the configured PSet contains illegal parameters,\n";
0178       dfh.indent(os);
0179       os << "then validation will ignore them instead of throwing an exception.\n";
0180       if (!dfh.brief())
0181         os << "\n";
0182     }
0183 
0184     if (entries_.empty()) {
0185       dfh.indent(os);
0186       os << "Description is empty\n";
0187       if (!dfh.brief())
0188         os << "\n";
0189       return;
0190     }
0191 
0192     // Zeroth pass is only to calculate column widths in advance of any printing
0193     dfh.setPass(0);
0194     dfh.setCounter(0);
0195     for_all(entries_, std::bind(&ParameterSetDescription::printNode, _1, std::ref(os), std::ref(dfh)));
0196 
0197     // First pass prints top level parameters and references to structure
0198     dfh.setPass(1);
0199     dfh.setCounter(0);
0200     for_all(entries_, std::bind(&ParameterSetDescription::printNode, _1, std::ref(os), std::ref(dfh)));
0201 
0202     // Second pass prints substructure that goes into different sections of the
0203     // output document
0204     dfh.setPass(2);
0205     dfh.setCounter(0);
0206     for_all(entries_, std::bind(&ParameterSetDescription::printNode, _1, std::ref(os), std::ref(dfh)));
0207   }
0208 
0209   bool ParameterSetDescription::isLabelUnused(std::string const& label) const {
0210     return usedLabels_.find(label) == usedLabels_.end();
0211   }
0212 
0213   void ParameterSetDescription::throwIllegalParameters(std::vector<std::string> const& parameterNames,
0214                                                        std::set<std::string> const& validatedLabels) {
0215     std::set<std::string> parNames(parameterNames.begin(), parameterNames.end());
0216 
0217     std::set<std::string> diffNames;
0218     std::insert_iterator<std::set<std::string> > insertIter(diffNames, diffNames.begin());
0219     std::set_difference(parNames.begin(), parNames.end(), validatedLabels.begin(), validatedLabels.end(), insertIter);
0220 
0221     std::stringstream ss;
0222     for (std::set<std::string>::const_iterator iter = diffNames.begin(), iEnd = diffNames.end(); iter != iEnd; ++iter) {
0223       ss << " '" << *iter << "'\n";
0224     }
0225     if (diffNames.size() == 1U) {
0226       throw edm::Exception(errors::Configuration)
0227           << "Illegal parameter found in configuration.  The parameter is named:\n"
0228           << ss.str() << "You could be trying to use a parameter name that is not\n"
0229           << "allowed for this plugin or it could be misspelled.\n";
0230     } else {
0231       throw edm::Exception(errors::Configuration)
0232           << "Illegal parameters found in configuration.  The parameters are named:\n"
0233           << ss.str() << "You could be trying to use parameter names that are not\n"
0234           << "allowed for this plugin or they could be misspelled.\n";
0235     }
0236   }
0237 
0238   void ParameterSetDescription::writeNode(SetDescriptionEntry const& entry,
0239                                           std::ostream& os,
0240                                           bool& startWithComma,
0241                                           int indentation,
0242                                           CfiOptions& options,
0243                                           bool& wroteSomething) {
0244     if (entry.writeToCfi()) {
0245       entry.node()->writeCfi(os, entry.modifier(), startWithComma, indentation, options, wroteSomething);
0246     } else {
0247       //The simplest way to handle this is to force all items to be full in this PSet
0248       cfi::parameterMustBeTyped(options);
0249     }
0250   }
0251 
0252   void ParameterSetDescription::printNode(SetDescriptionEntry const& entry, std::ostream& os, DocFormatHelper& dfh) {
0253     if (dfh.pass() < 2) {
0254       entry.node()->print(os, entry.modifier(), entry.writeToCfi(), dfh);
0255     } else {
0256       entry.node()->printNestedContent(os, entry.optional(), dfh);
0257     }
0258   }
0259 
0260   void ParameterSetDescription::throwIfLabelsAlreadyUsed(std::set<std::string> const& nodeLabels) {
0261     std::set<std::string> duplicateLabels;
0262     std::insert_iterator<std::set<std::string> > insertIter(duplicateLabels, duplicateLabels.begin());
0263     std::set_intersection(nodeLabels.begin(), nodeLabels.end(), usedLabels_.begin(), usedLabels_.end(), insertIter);
0264     if (duplicateLabels.empty()) {
0265       usedLabels_.insert(nodeLabels.begin(), nodeLabels.end());
0266     } else {
0267       std::stringstream ss;
0268       for (std::set<std::string>::const_iterator iter = duplicateLabels.begin(), iEnd = duplicateLabels.end();
0269            iter != iEnd;
0270            ++iter) {
0271         ss << " \"" << *iter << "\"\n";
0272       }
0273       throw edm::Exception(errors::LogicError) << "Labels used in different nodes of a ParameterSetDescription\n"
0274                                                << "must be unique.  The following duplicate labels were detected:\n"
0275                                                << ss.str() << "\n";
0276     }
0277   }
0278 
0279   void ParameterSetDescription::throwIfWildcardCollision(std::set<ParameterTypes> const& nodeParameterTypes,
0280                                                          std::set<ParameterTypes> const& nodeWildcardTypes) {
0281     // 1. Check that the new wildcard types do not collide with the existing
0282     // parameter types.
0283     // 2. Check that the new parameter types do not collide with the existing
0284     // wildcard types.
0285     // 3. Then insert them.
0286     // The order of those steps is important because a wildcard with a default
0287     // value could insert a type in both sets and this is OK.
0288 
0289     // We assume the node already checked for collisions between the new parameter
0290     // types and the new wildcard types before passing the sets to this function.
0291 
0292     if (!nodeWildcardTypes.empty()) {
0293       std::set<ParameterTypes> duplicateTypes1;
0294       std::insert_iterator<std::set<ParameterTypes> > insertIter1(duplicateTypes1, duplicateTypes1.begin());
0295       std::set_intersection(typesUsedForParameters_.begin(),
0296                             typesUsedForParameters_.end(),
0297                             nodeWildcardTypes.begin(),
0298                             nodeWildcardTypes.end(),
0299                             insertIter1);
0300 
0301       if (!duplicateTypes1.empty()) {
0302         std::stringstream ss;
0303         for (std::set<ParameterTypes>::const_iterator iter = duplicateTypes1.begin(), iEnd = duplicateTypes1.end();
0304              iter != iEnd;
0305              ++iter) {
0306           ss << " \"" << parameterTypeEnumToString(*iter) << "\"\n";
0307         }
0308         throw edm::Exception(errors::LogicError)
0309             << "Within a ParameterSetDescription, the type used for a wildcard must\n"
0310             << "not be the same as the type used for other parameters. This rule\n"
0311             << "is violated for the following types:\n"
0312             << ss.str() << "\n";
0313       }
0314     }
0315 
0316     if (!typesUsedForWildcards_.empty()) {
0317       std::set<ParameterTypes> duplicateTypes2;
0318       std::insert_iterator<std::set<ParameterTypes> > insertIter2(duplicateTypes2, duplicateTypes2.begin());
0319       std::set_intersection(typesUsedForWildcards_.begin(),
0320                             typesUsedForWildcards_.end(),
0321                             nodeParameterTypes.begin(),
0322                             nodeParameterTypes.end(),
0323                             insertIter2);
0324 
0325       if (!duplicateTypes2.empty()) {
0326         std::stringstream ss;
0327         for (std::set<ParameterTypes>::const_iterator iter = duplicateTypes2.begin(), iEnd = duplicateTypes2.end();
0328              iter != iEnd;
0329              ++iter) {
0330           ss << " \"" << parameterTypeEnumToString(*iter) << "\"\n";
0331         }
0332         throw edm::Exception(errors::LogicError)
0333             << "Within a ParameterSetDescription, the type used for a wildcard must\n"
0334             << "not be the same as the type used for other parameters. This rule is\n"
0335             << "violated for the following types :\n"
0336             << ss.str() << "\n";
0337       }
0338     }
0339 
0340     typesUsedForParameters_.insert(nodeParameterTypes.begin(), nodeParameterTypes.end());
0341     typesUsedForWildcards_.insert(nodeWildcardTypes.begin(), nodeWildcardTypes.end());
0342   }
0343 
0344   ParameterDescriptionNode* ParameterSetDescription::ifExists(ParameterDescriptionNode const& node1,
0345                                                               ParameterDescriptionNode const& node2,
0346                                                               Modifier modifier,
0347                                                               bool writeToCfi) {
0348     std::unique_ptr<ParameterDescriptionNode> pdIfExists = std::make_unique<IfExistsDescription>(node1, node2);
0349     return addNode(std::move(pdIfExists), modifier, writeToCfi);
0350   }
0351 }  // namespace edm