1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
|
// -*- C++ -*-
//
// Package: ParameterSet
// Class : ParameterSetDescription
//
// Implementation:
// <Notes on implementation>
//
// Original Author: Chris Jones
// Created: Tue Jul 31 15:30:35 EDT 2007
//
#include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
#include "FWCore/ParameterSet/interface/ParameterSet.h"
#include "FWCore/ParameterSet/interface/IfExistsDescription.h"
#include "FWCore/ParameterSet/interface/IllegalParameters.h"
#include "FWCore/ParameterSet/interface/DocFormatHelper.h"
#include "FWCore/Utilities/interface/Algorithms.h"
#include "FWCore/Utilities/interface/EDMException.h"
#include <sstream>
#include <ostream>
#include <iomanip>
#include <algorithm>
namespace edm {
ParameterSetDescription::ParameterSetDescription() : anythingAllowed_(false), unknown_(false) {}
ParameterSetDescription::~ParameterSetDescription() {}
void ParameterSetDescription::setComment(std::string const& value) { comment_ = value; }
void ParameterSetDescription::setComment(char const* value) { comment_ = value; }
void ParameterSetDescription::setAllowAnything() { anythingAllowed_ = true; }
void ParameterSetDescription::setUnknown() { unknown_ = true; }
ParameterDescriptionNode* ParameterSetDescription::addNode(ParameterDescriptionNode const& node) {
std::unique_ptr<ParameterDescriptionNode> clonedNode(node.clone());
return addNode(std::move(clonedNode), Modifier::kNone, true);
}
ParameterDescriptionNode* ParameterSetDescription::addNode(std::unique_ptr<ParameterDescriptionNode> node) {
return addNode(std::move(node), Modifier::kNone, true);
}
ParameterDescriptionNode* ParameterSetDescription::addOptionalNode(ParameterDescriptionNode const& node,
bool writeToCfi) {
std::unique_ptr<ParameterDescriptionNode> clonedNode(node.clone());
return addNode(std::move(clonedNode), Modifier::kOptional, writeToCfi);
}
ParameterDescriptionNode* ParameterSetDescription::addOptionalNode(std::unique_ptr<ParameterDescriptionNode> node,
bool writeToCfi) {
return addNode(std::move(node), Modifier::kOptional, writeToCfi);
}
ParameterDescriptionNode* ParameterSetDescription::addNode(std::unique_ptr<ParameterDescriptionNode> node,
Modifier modifier,
bool writeToCfi) {
std::set<std::string> nodeLabels;
std::set<ParameterTypes> nodeParameterTypes;
std::set<ParameterTypes> nodeWildcardTypes;
node->checkAndGetLabelsAndTypes(nodeLabels, nodeParameterTypes, nodeWildcardTypes);
throwIfLabelsAlreadyUsed(nodeLabels);
throwIfWildcardCollision(nodeParameterTypes, nodeWildcardTypes);
SetDescriptionEntry entry;
entry.setModifier(modifier);
entry.setWriteToCfi(writeToCfi);
entries_.push_back(entry);
return entries_.back().setNode(std::move(node));
}
void ParameterSetDescription::validate(ParameterSet& pset) const {
using std::placeholders::_1;
if (unknown_)
return;
std::set<std::string> validatedLabels;
for_all(entries_, std::bind(&ParameterSetDescription::validateNode, _1, std::ref(pset), std::ref(validatedLabels)));
std::vector<std::string> parameterNames = pset.getParameterNames();
if (validatedLabels.size() != parameterNames.size()) {
// These labels will be magically inserted into the top level
// of a module ParameterSet even though they are not in the
// python configuration files. If these are present, then
// assume they are OK and count them as validated.
std::string module_label("@module_label");
if (pset.exists(module_label)) {
validatedLabels.insert(module_label);
}
std::string module_type("@module_type");
if (pset.exists(module_type)) {
validatedLabels.insert(module_type);
}
std::string module_edm_type("@module_edm_type");
if (pset.exists(module_edm_type)) {
validatedLabels.insert(module_edm_type);
}
std::string service_type("@service_type");
if (pset.exists(service_type)) {
validatedLabels.insert(service_type);
}
{
std::string tryToContinue("@shouldTryToContinue");
if (pset.exists(tryToContinue)) {
validatedLabels.insert(tryToContinue);
}
}
// Try again
if (validatedLabels.size() != parameterNames.size()) {
if (IllegalParameters::throwAnException() && !anythingAllowed()) {
throwIllegalParameters(parameterNames, validatedLabels);
}
}
}
}
void ParameterSetDescription::writeCfi(std::ostream& os,
bool startWithComma,
int indentation,
CfiOptions& options) const {
bool wroteSomething = false;
bool seenWildcard = false;
bool seenMultipleWildcards = false;
for (auto const& entry : entries_) {
//only add the first seen wildcard to the cfi. This avoids possible ambiguities.
if (entry.node()->isWildcard()) {
if (seenWildcard == true) {
seenMultipleWildcards = true;
continue;
}
seenWildcard = true;
}
writeNode(entry, os, startWithComma, indentation, options, wroteSomething);
}
if ((anythingAllowed() or seenMultipleWildcards)) {
cfi::parameterMustBeTyped(options);
}
if (wroteSomething) {
char oldFill = os.fill();
os << "\n" << std::setfill(' ') << std::setw(indentation - 2) << "" << std::setfill(oldFill);
}
}
void ParameterSetDescription::validateNode(SetDescriptionEntry const& entry,
ParameterSet& pset,
std::set<std::string>& validatedLabels) {
entry.node()->validate(pset, validatedLabels, entry.modifier());
}
void ParameterSetDescription::print(std::ostream& os, DocFormatHelper& dfh) const {
using std::placeholders::_1;
if (isUnknown()) {
dfh.indent(os);
os << "Description is unknown. The configured PSet will not be validated\n";
dfh.indent(os);
os << "because the plugin has not defined this parameter set description.\n";
if (!dfh.brief())
os << "\n";
}
if (anythingAllowed()) {
dfh.indent(os);
os << "Description allows anything. If the configured PSet contains illegal parameters,\n";
dfh.indent(os);
os << "then validation will ignore them instead of throwing an exception.\n";
if (!dfh.brief())
os << "\n";
}
if (entries_.empty()) {
dfh.indent(os);
os << "Description is empty\n";
if (!dfh.brief())
os << "\n";
return;
}
// Zeroth pass is only to calculate column widths in advance of any printing
dfh.setPass(0);
dfh.setCounter(0);
for_all(entries_, std::bind(&ParameterSetDescription::printNode, _1, std::ref(os), std::ref(dfh)));
// First pass prints top level parameters and references to structure
dfh.setPass(1);
dfh.setCounter(0);
for_all(entries_, std::bind(&ParameterSetDescription::printNode, _1, std::ref(os), std::ref(dfh)));
// Second pass prints substructure that goes into different sections of the
// output document
dfh.setPass(2);
dfh.setCounter(0);
for_all(entries_, std::bind(&ParameterSetDescription::printNode, _1, std::ref(os), std::ref(dfh)));
}
bool ParameterSetDescription::isLabelUnused(std::string const& label) const {
return usedLabels_.find(label) == usedLabels_.end();
}
void ParameterSetDescription::throwIllegalParameters(std::vector<std::string> const& parameterNames,
std::set<std::string> const& validatedLabels) {
std::set<std::string> parNames(parameterNames.begin(), parameterNames.end());
std::set<std::string> diffNames;
std::insert_iterator<std::set<std::string> > insertIter(diffNames, diffNames.begin());
std::set_difference(parNames.begin(), parNames.end(), validatedLabels.begin(), validatedLabels.end(), insertIter);
std::stringstream ss;
for (std::set<std::string>::const_iterator iter = diffNames.begin(), iEnd = diffNames.end(); iter != iEnd; ++iter) {
ss << " '" << *iter << "'\n";
}
if (diffNames.size() == 1U) {
throw edm::Exception(errors::Configuration)
<< "Illegal parameter found in configuration. The parameter is named:\n"
<< ss.str() << "You could be trying to use a parameter name that is not\n"
<< "allowed for this plugin or it could be misspelled.\n";
} else {
throw edm::Exception(errors::Configuration)
<< "Illegal parameters found in configuration. The parameters are named:\n"
<< ss.str() << "You could be trying to use parameter names that are not\n"
<< "allowed for this plugin or they could be misspelled.\n";
}
}
void ParameterSetDescription::writeNode(SetDescriptionEntry const& entry,
std::ostream& os,
bool& startWithComma,
int indentation,
CfiOptions& options,
bool& wroteSomething) {
if (entry.writeToCfi()) {
entry.node()->writeCfi(os, entry.modifier(), startWithComma, indentation, options, wroteSomething);
} else {
//The simplest way to handle this is to force all items to be full in this PSet
cfi::parameterMustBeTyped(options);
}
}
void ParameterSetDescription::printNode(SetDescriptionEntry const& entry, std::ostream& os, DocFormatHelper& dfh) {
if (dfh.pass() < 2) {
entry.node()->print(os, entry.modifier(), entry.writeToCfi(), dfh);
} else {
entry.node()->printNestedContent(os, entry.optional(), dfh);
}
}
void ParameterSetDescription::throwIfLabelsAlreadyUsed(std::set<std::string> const& nodeLabels) {
std::set<std::string> duplicateLabels;
std::insert_iterator<std::set<std::string> > insertIter(duplicateLabels, duplicateLabels.begin());
std::set_intersection(nodeLabels.begin(), nodeLabels.end(), usedLabels_.begin(), usedLabels_.end(), insertIter);
if (duplicateLabels.empty()) {
usedLabels_.insert(nodeLabels.begin(), nodeLabels.end());
} else {
std::stringstream ss;
for (std::set<std::string>::const_iterator iter = duplicateLabels.begin(), iEnd = duplicateLabels.end();
iter != iEnd;
++iter) {
ss << " \"" << *iter << "\"\n";
}
throw edm::Exception(errors::LogicError) << "Labels used in different nodes of a ParameterSetDescription\n"
<< "must be unique. The following duplicate labels were detected:\n"
<< ss.str() << "\n";
}
}
void ParameterSetDescription::throwIfWildcardCollision(std::set<ParameterTypes> const& nodeParameterTypes,
std::set<ParameterTypes> const& nodeWildcardTypes) {
// 1. Check that the new wildcard types do not collide with the existing
// parameter types.
// 2. Check that the new parameter types do not collide with the existing
// wildcard types.
// 3. Then insert them.
// The order of those steps is important because a wildcard with a default
// value could insert a type in both sets and this is OK.
// We assume the node already checked for collisions between the new parameter
// types and the new wildcard types before passing the sets to this function.
if (!nodeWildcardTypes.empty()) {
std::set<ParameterTypes> duplicateTypes1;
std::insert_iterator<std::set<ParameterTypes> > insertIter1(duplicateTypes1, duplicateTypes1.begin());
std::set_intersection(typesUsedForParameters_.begin(),
typesUsedForParameters_.end(),
nodeWildcardTypes.begin(),
nodeWildcardTypes.end(),
insertIter1);
if (!duplicateTypes1.empty()) {
std::stringstream ss;
for (std::set<ParameterTypes>::const_iterator iter = duplicateTypes1.begin(), iEnd = duplicateTypes1.end();
iter != iEnd;
++iter) {
ss << " \"" << parameterTypeEnumToString(*iter) << "\"\n";
}
throw edm::Exception(errors::LogicError)
<< "Within a ParameterSetDescription, the type used for a wildcard must\n"
<< "not be the same as the type used for other parameters. This rule\n"
<< "is violated for the following types:\n"
<< ss.str() << "\n";
}
}
if (!typesUsedForWildcards_.empty()) {
std::set<ParameterTypes> duplicateTypes2;
std::insert_iterator<std::set<ParameterTypes> > insertIter2(duplicateTypes2, duplicateTypes2.begin());
std::set_intersection(typesUsedForWildcards_.begin(),
typesUsedForWildcards_.end(),
nodeParameterTypes.begin(),
nodeParameterTypes.end(),
insertIter2);
if (!duplicateTypes2.empty()) {
std::stringstream ss;
for (std::set<ParameterTypes>::const_iterator iter = duplicateTypes2.begin(), iEnd = duplicateTypes2.end();
iter != iEnd;
++iter) {
ss << " \"" << parameterTypeEnumToString(*iter) << "\"\n";
}
throw edm::Exception(errors::LogicError)
<< "Within a ParameterSetDescription, the type used for a wildcard must\n"
<< "not be the same as the type used for other parameters. This rule is\n"
<< "violated for the following types :\n"
<< ss.str() << "\n";
}
}
typesUsedForParameters_.insert(nodeParameterTypes.begin(), nodeParameterTypes.end());
typesUsedForWildcards_.insert(nodeWildcardTypes.begin(), nodeWildcardTypes.end());
}
ParameterDescriptionNode* ParameterSetDescription::ifExists(ParameterDescriptionNode const& node1,
ParameterDescriptionNode const& node2,
Modifier modifier,
bool writeToCfi) {
std::unique_ptr<ParameterDescriptionNode> pdIfExists = std::make_unique<IfExistsDescription>(node1, node2);
return addNode(std::move(pdIfExists), modifier, writeToCfi);
}
} // namespace edm
|