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/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
00119
00120
00121
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
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
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
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
00221
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
00325
00326
00327
00328
00329
00330
00331
00332
00333
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 }