00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
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 ParameterDescriptionNode* returnValue = node.get();
00103 entries_.back().setNode(node);
00104 return returnValue;
00105 }
00106
00107 void
00108 ParameterSetDescription::validate(ParameterSet & pset) const
00109 {
00110 if (unknown_) return;
00111
00112 std::set<std::string> validatedLabels;
00113 for_all(entries_,
00114 boost::bind(&ParameterSetDescription::validateNode, _1, boost::ref(pset), boost::ref(validatedLabels)));
00115
00116 std::vector<std::string> parameterNames = pset.getParameterNames();
00117 if (validatedLabels.size() != parameterNames.size()) {
00118
00119
00120
00121
00122
00123
00124 std::string module_label("@module_label");
00125 if (pset.exists(module_label)) {
00126 validatedLabels.insert(module_label);
00127 }
00128
00129 std::string module_type("@module_type");
00130 if (pset.exists(module_type)) {
00131 validatedLabels.insert(module_type);
00132 }
00133
00134 std::string module_edm_type("@module_edm_type");
00135 if (pset.exists(module_edm_type)) {
00136 validatedLabels.insert(module_edm_type);
00137 }
00138
00139 std::string service_type("@service_type");
00140 if (pset.exists(service_type)) {
00141 validatedLabels.insert(service_type);
00142 }
00143
00144
00145 if (validatedLabels.size() != parameterNames.size()) {
00146
00147 if (IllegalParameters::throwAnException() && !anythingAllowed()) {
00148 throwIllegalParameters(parameterNames, validatedLabels);
00149 }
00150 }
00151 }
00152 }
00153
00154 void
00155 ParameterSetDescription::writeCfi(std::ostream & os,
00156 bool startWithComma,
00157 int indentation) const {
00158 bool wroteSomething = false;
00159
00160 for_all(entries_, boost::bind(&ParameterSetDescription::writeNode,
00161 _1,
00162 boost::ref(os),
00163 boost::ref(startWithComma),
00164 indentation,
00165 boost::ref(wroteSomething)));
00166
00167 if (wroteSomething) {
00168 char oldFill = os.fill();
00169 os << "\n" << std::setfill(' ') << std::setw(indentation - 2) << "";
00170 os.fill(oldFill);
00171 }
00172 }
00173
00174 void ParameterSetDescription::
00175 validateNode(SetDescriptionEntry const& entry,
00176 ParameterSet & pset,
00177 std::set<std::string> & validatedLabels) {
00178 entry.node()->validate(pset, validatedLabels, entry.optional());
00179 }
00180
00181 void ParameterSetDescription::
00182 print(std::ostream & os, DocFormatHelper & dfh) const {
00183
00184 if (isUnknown()) {
00185 dfh.indent(os);
00186 os << "Description is unknown. The configured PSet will not be validated\n";
00187 dfh.indent(os);
00188 os << "because the plugin has not defined this parameter set description.\n";
00189 if (!dfh.brief()) os << "\n";
00190 }
00191
00192 if (anythingAllowed()) {
00193 dfh.indent(os);
00194 os << "Description allows anything. If the configured PSet contains illegal parameters,\n";
00195 dfh.indent(os);
00196 os << "then validation will ignore them instead of throwing an exception.\n";
00197 if (!dfh.brief()) os << "\n";
00198 }
00199
00200 if (entries_.empty()) {
00201 dfh.indent(os);
00202 os << "Description is empty\n";
00203 if (!dfh.brief()) os << "\n";
00204 return;
00205 }
00206
00207
00208 dfh.setPass(0);
00209 dfh.setCounter(0);
00210 for_all(entries_, boost::bind(&ParameterSetDescription::printNode,
00211 _1,
00212 boost::ref(os),
00213 boost::ref(dfh)));
00214
00215
00216 dfh.setPass(1);
00217 dfh.setCounter(0);
00218 for_all(entries_, boost::bind(&ParameterSetDescription::printNode,
00219 _1,
00220 boost::ref(os),
00221 boost::ref(dfh)));
00222
00223
00224
00225 dfh.setPass(2);
00226 dfh.setCounter(0);
00227 for_all(entries_, boost::bind(&ParameterSetDescription::printNode,
00228 _1,
00229 boost::ref(os),
00230 boost::ref(dfh)));
00231 }
00232
00233 bool
00234 ParameterSetDescription::
00235 isLabelUnused(std::string const& label) const {
00236 return usedLabels_.find(label) == usedLabels_.end();
00237 }
00238
00239 void
00240 ParameterSetDescription::throwIllegalParameters(
00241 std::vector<std::string> const& parameterNames,
00242 std::set<std::string> const& validatedLabels) {
00243
00244 std::set<std::string> parNames(parameterNames.begin(), parameterNames.end());
00245
00246
00247 std::set<std::string> diffNames;
00248 std::insert_iterator<std::set<std::string> > insertIter(diffNames, diffNames.begin());
00249 std::set_difference(parNames.begin(), parNames.end(),
00250 validatedLabels.begin(), validatedLabels.end(),
00251 insertIter);
00252
00253 std::stringstream ss;
00254 for (std::set<std::string>::const_iterator iter = diffNames.begin(),
00255 iEnd = diffNames.end();
00256 iter != iEnd;
00257 ++iter) {
00258 ss << " '" << *iter << "'\n";
00259 }
00260 if (diffNames.size() == 1U) {
00261 throw edm::Exception(errors::Configuration)
00262 << "Illegal parameter found in configuration. The parameter is named:\n"
00263 << ss.str()
00264 << "You could be trying to use a parameter name that is not\n"
00265 << "allowed for this plugin or it could be misspelled.\n";
00266 }
00267 else {
00268 throw edm::Exception(errors::Configuration)
00269 << "Illegal parameters found in configuration. The parameters are named:\n"
00270 << ss.str()
00271 << "You could be trying to use parameter names that are not\n"
00272 << "allowed for this plugin or they could be misspelled.\n";
00273 }
00274 }
00275
00276 void
00277 ParameterSetDescription::writeNode(SetDescriptionEntry const& entry,
00278 std::ostream & os,
00279 bool & startWithComma,
00280 int indentation,
00281 bool & wroteSomething) {
00282 if (entry.writeToCfi()) {
00283 entry.node()->writeCfi(os, startWithComma, indentation, wroteSomething);
00284 }
00285 }
00286
00287 void
00288 ParameterSetDescription::printNode(SetDescriptionEntry const& entry,
00289 std::ostream & os,
00290 DocFormatHelper & dfh) {
00291 if (dfh.pass() < 2) {
00292 entry.node()->print(os, entry.optional(), entry.writeToCfi(), dfh);
00293 }
00294 else {
00295 entry.node()->printNestedContent(os, entry.optional(), dfh);
00296 }
00297 }
00298
00299 void
00300 ParameterSetDescription::
00301 throwIfLabelsAlreadyUsed(std::set<std::string> const& nodeLabels) {
00302
00303 std::set<std::string> duplicateLabels;
00304 std::insert_iterator<std::set<std::string> > insertIter(duplicateLabels, duplicateLabels.begin());
00305 std::set_intersection(nodeLabels.begin(), nodeLabels.end(),
00306 usedLabels_.begin(), usedLabels_.end(),
00307 insertIter);
00308 if (duplicateLabels.empty()) {
00309 usedLabels_.insert(nodeLabels.begin(), nodeLabels.end());
00310 }
00311 else {
00312
00313 std::stringstream ss;
00314 for (std::set<std::string>::const_iterator iter = duplicateLabels.begin(),
00315 iEnd = duplicateLabels.end();
00316 iter != iEnd;
00317 ++iter) {
00318 ss << " \"" << *iter << "\"\n";
00319 }
00320 throw edm::Exception(errors::LogicError)
00321 << "Labels used in different nodes of a ParameterSetDescription\n"
00322 << "must be unique. The following duplicate labels were detected:\n"
00323 << ss.str()
00324 << "\n";
00325 }
00326 }
00327
00328 void
00329 ParameterSetDescription::
00330 throwIfWildcardCollision(std::set<ParameterTypes> const& nodeParameterTypes,
00331 std::set<ParameterTypes> const& nodeWildcardTypes) {
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344 if (!nodeWildcardTypes.empty()) {
00345
00346 std::set<ParameterTypes> duplicateTypes1;
00347 std::insert_iterator<std::set<ParameterTypes> > insertIter1(duplicateTypes1, duplicateTypes1.begin());
00348 std::set_intersection(typesUsedForParameters_.begin(), typesUsedForParameters_.end(),
00349 nodeWildcardTypes.begin(), nodeWildcardTypes.end(),
00350 insertIter1);
00351
00352 if (!duplicateTypes1.empty()) {
00353
00354 std::stringstream ss;
00355 for (std::set<ParameterTypes>::const_iterator iter = duplicateTypes1.begin(),
00356 iEnd = duplicateTypes1.end();
00357 iter != iEnd;
00358 ++iter) {
00359 ss << " \"" << parameterTypeEnumToString(*iter) << "\"\n";
00360 }
00361 throw edm::Exception(errors::LogicError)
00362 << "Within a ParameterSetDescription, the type used for a wildcard must\n"
00363 << "not be the same as the type used for other parameters. This rule\n"
00364 << "is violated for the following types:\n"
00365 << ss.str()
00366 << "\n";
00367 }
00368 }
00369
00370 if (!typesUsedForWildcards_.empty()) {
00371
00372 std::set<ParameterTypes> duplicateTypes2;
00373 std::insert_iterator<std::set<ParameterTypes> > insertIter2(duplicateTypes2, duplicateTypes2.begin());
00374 std::set_intersection(typesUsedForWildcards_.begin(), typesUsedForWildcards_.end(),
00375 nodeParameterTypes.begin(), nodeParameterTypes.end(),
00376 insertIter2);
00377
00378 if (!duplicateTypes2.empty()) {
00379
00380 std::stringstream ss;
00381 for (std::set<ParameterTypes>::const_iterator iter = duplicateTypes2.begin(),
00382 iEnd = duplicateTypes2.end();
00383 iter != iEnd;
00384 ++iter) {
00385 ss << " \"" << parameterTypeEnumToString(*iter) << "\"\n";
00386 }
00387 throw edm::Exception(errors::LogicError)
00388 << "Within a ParameterSetDescription, the type used for a wildcard must\n"
00389 << "not be the same as the type used for other parameters. This rule is\n"
00390 << "violated for the following types :\n"
00391 << ss.str()
00392 << "\n";
00393 }
00394 }
00395
00396 typesUsedForParameters_.insert(nodeParameterTypes.begin(), nodeParameterTypes.end());
00397 typesUsedForWildcards_.insert(nodeWildcardTypes.begin(), nodeWildcardTypes.end());
00398 }
00399
00400 ParameterDescriptionNode*
00401 ParameterSetDescription::
00402 ifExists(ParameterDescriptionNode const& node1,
00403 ParameterDescriptionNode const& node2,
00404 bool optional, bool writeToCfi) {
00405 std::auto_ptr<ParameterDescriptionNode> pdIfExists(new IfExistsDescription(node1, node2));
00406 return addNode(pdIfExists, optional, writeToCfi);
00407 }
00408 }