CMS 3D CMS Logo

ParameterDescriptionNode.h
Go to the documentation of this file.
1 #ifndef FWCore_ParameterSet_ParameterDescriptionNode_h
2 #define FWCore_ParameterSet_ParameterDescriptionNode_h
3 
4 // This is a base class for the class that describes
5 // the parameters that are allowed or required to be
6 // in a ParameterSet. It is also a base class for
7 // other more complex logical structures which describe
8 // which combinations of parameters are allowed to be
9 // in a ParameterSet.
10 
12 
13 #include <string>
14 #include <set>
15 #include <iosfwd>
16 #include <memory>
17 #include <variant>
18 #include <optional>
19 #include <unordered_map>
20 #include <vector>
21 #include <cassert>
22 
23 namespace edm {
24 
25  class ParameterSet;
26  template <typename T>
27  class ParameterDescriptionCases;
28  class DocFormatHelper;
29 
30  // Originally these were defined such that the values were the
31  // same as in the ParameterSet Entry class and the validation
32  // depended on that. But at the moment I'm typing this comment,
33  // the code no longer depends on the values being the same (which
34  // is probably good because nothing enforces the correspondence,
35  // a task for the future when someone has free time would be
36  // to define the values in a common header, but that would involve
37  // significant changes to ParameterSet ...)
39  k_int32 = 'I',
40  k_vint32 = 'i',
41  k_uint32 = 'U',
42  k_vuint32 = 'u',
43  k_int64 = 'L',
44  k_vint64 = 'l',
45  k_uint64 = 'X',
46  k_vuint64 = 'x',
47  k_double = 'D',
48  k_vdouble = 'd',
49  k_bool = 'B',
50  k_stringRaw = 'Z',
51  k_vstringRaw = 'z',
52  k_stringHex = 'S',
53  k_vstringHex = 's',
54  k_EventID = 'E',
55  k_VEventID = 'e',
58  k_InputTag = 't',
59  k_VInputTag = 'v',
60  k_ESInputTag = 'g',
62  k_FileInPath = 'F',
65  k_EventRange = 'R',
67  k_PSet = 'Q',
68  k_VPSet = 'q'
69  };
70 
72 
73  namespace cfi {
74  struct Paths {
75  //This is the 'path' through the cms.PSet hierarchy.
76  // E.g. foo.bar.tar would have a Path for foo, bar, and tar with
77  // tar having a null nodes_ variable.
78  std::optional<std::unordered_map<std::string, Paths>> nodes_;
79  };
80  struct Typed {};
81  struct ClassFile {
83  Paths* p = &fullPaths_;
84  for (auto n : presentPath_) {
85  if (not p->nodes_) {
86  p->nodes_ = std::unordered_map<std::string, Paths>();
87  }
88  p = &(p->nodes_.value().emplace(n, Paths{})).first->second;
89  }
90  }
91  void pushNode(std::string_view iNode) { presentPath_.push_back(iNode); }
92  void popNode() {
93  assert(not presentPath_.empty());
94  presentPath_.pop_back();
95  }
96 
98 
99  private:
100  std::vector<std::string_view> presentPath_;
102  };
103  struct Untyped {
104  Untyped(Paths iPaths) : paths_(iPaths) {}
105  bool needToSwitchToTyped(std::string_view iNode) {
106  presentPath_.push_back(iNode);
107  if (not paths_.nodes_.has_value()) {
108  return false;
109  }
110  const Paths* p = &paths_;
111  for (auto const& n : presentPath_) {
112  if (not paths_.nodes_.has_value()) {
113  return false;
114  }
115  auto f = paths_.nodes_->find(std::string(n));
116  if (f == paths_.nodes_->end()) {
117  return false;
118  }
119  p = &f->second;
120  }
121  return not p->nodes_.has_value();
122  }
123  void popNode() {
124  assert(not presentPath_.empty());
125  presentPath_.pop_back();
126  }
127 
128  private:
129  std::vector<std::string_view> presentPath_;
131  };
132 
133  using CfiOptions = std::variant<cfi::Typed, cfi::ClassFile, cfi::Untyped>;
134 
135  inline void parameterMustBeTyped(CfiOptions& iOps) noexcept {
136  if (std::holds_alternative<cfi::ClassFile>(iOps)) {
137  std::get<cfi::ClassFile>(iOps).parameterMustBeTyped();
138  }
139  }
140  inline void parameterMustBeTyped(CfiOptions& iOps, std::string_view iNode) noexcept {
141  if (std::holds_alternative<cfi::ClassFile>(iOps)) {
142  auto& d = std::get<cfi::ClassFile>(iOps);
143  d.pushNode(iNode);
144  d.parameterMustBeTyped();
145  d.popNode();
146  }
147  }
148  [[nodiscard]] inline bool shouldWriteUntyped(CfiOptions const& iOps) noexcept {
149  return std::holds_alternative<cfi::Untyped>(iOps);
150  }
151 
152  struct NodeGuard {
153  NodeGuard(CfiOptions& iOp) : options_(&iOp) {}
154  NodeGuard() = delete;
155  NodeGuard(NodeGuard const&) = delete;
156  NodeGuard& operator=(NodeGuard const&) = delete;
157  NodeGuard(NodeGuard&& iOther) : options_{iOther.options_} { iOther.options_ = nullptr; }
159  NodeGuard temp{std::move(iOther)};
160  options_ = temp.options_;
161  temp.options_ = nullptr;
162  return *this;
163  }
165  if (nullptr == options_) {
166  return;
167  }
168  if (std::holds_alternative<ClassFile>(*options_)) {
169  std::get<ClassFile>(*options_).popNode();
170  } else if (std::holds_alternative<Untyped>(*options_)) {
171  std::get<Untyped>(*options_).popNode();
172  }
173  }
175  };
176 
177  [[nodiscard]] inline std::pair<bool, NodeGuard> needToSwitchToTyped(std::string_view iNode,
178  CfiOptions& iOpt) noexcept {
179  if (std::holds_alternative<Untyped>(iOpt)) {
180  return std::pair(std::get<Untyped>(iOpt).needToSwitchToTyped(iNode), NodeGuard(iOpt));
181  } else if (std::holds_alternative<ClassFile>(iOpt)) {
182  std::get<ClassFile>(iOpt).pushNode(iNode);
183  }
184  return std::pair(false, NodeGuard(iOpt));
185  }
186  } // namespace cfi
188 
190  template <class T>
191  static ParameterTypes toEnum();
192  };
193 
194  class Comment {
195  public:
196  Comment();
197  explicit Comment(std::string const& iComment);
198  explicit Comment(char const* iComment);
199  std::string const& comment() const { return comment_; }
200 
201  private:
203  };
204 
206  public:
208 
209  explicit ParameterDescriptionNode(Comment const& iComment) : comment_(iComment.comment()) {}
210 
211  virtual ~ParameterDescriptionNode();
212 
213  virtual ParameterDescriptionNode* clone() const = 0;
214 
215  std::string const& comment() const { return comment_; }
216  void setComment(std::string const& value);
217  void setComment(char const* value);
218 
219  // The validate function should do one of three things, find that the
220  // node "exists", make the node "exist" by inserting missing parameters
221  // or throw. The only exception to this rule occurs when the argument
222  // named "optional" is true, which should only be possible for the
223  // top level nodes of a ParameterSetDescription. When a parameter is
224  // found or inserted its label is added into the list of validatedLabels.
225  void validate(ParameterSet& pset, std::set<std::string>& validatedLabels, bool optional) const {
226  validate_(pset, validatedLabels, optional);
227  }
228 
229  // As long as it has default values, this will attempt to write
230  // parameters associated with a node into a cfi file that is
231  // being automatically generated. It is quite possible for
232  // to produce a cfi that will fail validation. In some cases,
233  // this will imply the user is required to supply certain missing
234  // parameters that do not appear in the cfi and do not have defaults
235  // in the description. It is also possible to create a pathological
236  // ParameterSetDescription where the algorithm fails to write
237  // a valid cfi, in some cases the description can be so pathological
238  // that it is impossible to write a cfi that will pass validation.
239  void writeCfi(std::ostream& os,
240  bool optional,
241  bool& startWithComma,
242  int indentation,
244  bool& wroteSomething) const {
245  writeCfi_(os, optional, startWithComma, indentation, options, wroteSomething);
246  }
247 
248  // Print out the description in human readable format
249  void print(std::ostream& os, bool optional, bool writeToCfi, DocFormatHelper& dfh) const;
250 
251  bool hasNestedContent() const { return hasNestedContent_(); }
252 
253  void printNestedContent(std::ostream& os, bool optional, DocFormatHelper& dfh) const;
254 
255  // The next three functions are only called by the logical nodes
256  // on their subnodes. When executing these functions, the
257  // insertion of missing parameters does not occur.
258 
259  // Usually checks to see if a parameter exists in the configuration, but
260  // if the node is a logical node, then it returns the value of the logical
261  // expression.
262  bool exists(ParameterSet const& pset) const { return exists_(pset); }
263 
264  // For most nodes, this simply returns the same value as the exists
265  // function. But for AND nodes this returns true if either its subnodes
266  // exists. Used by operator&& during validation, if either of an AND node's
267  // subnodes exists, then both subnodes get validated.
268  bool partiallyExists(ParameterSet const& pset) const { return partiallyExists_(pset); }
269 
270  // For most nodes, this simply returns the same value as the exists
271  // function. It is different for an XOR node. It counts
272  // XOR subnodes whose exists function returns true. And it
273  // does this recursively into XOR nodes that are contained in
274  // other XOR nodes.
275  // Used by operator^ during validation:
276  // -- if it returns more than 1, then validation will throw,
277  // -- if it returns exactly one, then only the nonzero subnode gets validated
278  // -- if it returns zero, then validation tries to validate the first node and
279  // then rechecks to see what the missing parameter insertion did (there could
280  // be side effects on the nodes that were not validated)
282 
283  /* Validation puts requirements on which parameters can and cannot exist
284  within a ParameterSet. The evaluation of whether a ParameterSet passes
285  or fails the rules in the ParameterSetDescription is complicated by
286  the fact that we allow missing parameters to be injected into the
287  ParameterSet during validation. One must worry whether injecting a
288  missing parameter invalidates some other part of the ParameterSet that
289  was already checked and determined to be OK. The following restrictions
290  avoid that problem.
291 
292  - The same parameter labels cannot occur in different nodes of the
293  same ParameterSetDescription. There are two exceptions to this.
294  Nodes that are contained in the cases of a ParameterSwitch or the
295  subnodes of an "exclusive or" are allowed to use the same labels.
296 
297  - If insertion is necessary to make an "exclusive or" node pass
298  validation, then the insertion could make more than one of the
299  possibilities evaluate true. This must be checked for after the
300  insertions occur. The behavior is to throw a Configuration exception
301  if this problem is encountered. (Example: (A && B) ^ (A && C) where
302  C already exists in the ParameterSet but A and B do not. A and B
303  get inserted by the algorithm, because it tries to make the first
304  possibility true when all fail without insertion. Then both
305  parts of the "exclusive or" pass, which is a validation failure).
306 
307  - Another potential problem is that a parameter insertion related
308  to one ParameterDescription could match unrelated wildcards causing
309  other validation requirements to change from being passing to failing
310  or vice versa. This makes it almost impossible to determine if a
311  ParameterSet passes validation. Each time you try to loop through
312  and check, the result of validation could change. To avoid this problem,
313  a list is maintained of the type for all wildcards. Another list is
314  maintained for the type of all parameters. As new items are added
315  we check for collisions. The function that builds the ParameterSetDescription,
316  will throw if this rule is violated. At the moment, the criteria
317  for a collision is matching types between a parameter and a wildcard.
318  (This criteria is overrestrictive. With some additional CPU and
319  code development the restriction could be loosened to parameters that
320  might be injected cannot match the type, trackiness, and wildcard label
321  pattern of any wildcard that requires a match. And further this
322  could not apply to wildcards on different branches of a ParameterSwitch
323  or "exclusive or".)
324 
325  These restrictions have the additional benefit that the things they prohibit
326  would tend to confuse a user trying to configure a module or a module developer
327  writing the code to extract the parameters from a ParameterSet. These rules
328  tend to prohibit bad design.
329 
330  One strategy to avoid problems with wildcard parameters is to add a nested
331  ParameterSet and put the wildcard parameters in the nested ParameterSet.
332  The names and types in a nested ParameterSet will not interfere with names
333  in the containing ParameterSet.
334  */
335  void checkAndGetLabelsAndTypes(std::set<std::string>& usedLabels,
336  std::set<ParameterTypes>& parameterTypes,
337  std::set<ParameterTypes>& wildcardTypes) const {
338  checkAndGetLabelsAndTypes_(usedLabels, parameterTypes, wildcardTypes);
339  }
340 
341  virtual bool isWildcard() const { return false; }
342  static void printSpaces(std::ostream& os, int n);
343 
344  protected:
345  virtual void checkAndGetLabelsAndTypes_(std::set<std::string>& usedLabels,
346  std::set<ParameterTypes>& parameterTypes,
347  std::set<ParameterTypes>& wildcardTypes) const = 0;
348 
349  virtual void validate_(ParameterSet& pset, std::set<std::string>& validatedLabels, bool optional) const = 0;
350 
351  virtual void writeCfi_(std::ostream& os,
352  bool optional,
353  bool& startWithComma,
354  int indentation,
355  CfiOptions&,
356  bool& wroteSomething) const = 0;
357 
358  virtual void print_(std::ostream&, bool /*optional*/, bool /*writeToCfi*/, DocFormatHelper&) const {}
359 
360  virtual bool hasNestedContent_() const { return false; }
361 
362  virtual void printNestedContent_(std::ostream&, bool /*optional*/, DocFormatHelper&) const {}
363 
364  virtual bool exists_(ParameterSet const& pset) const = 0;
365 
366  virtual bool partiallyExists_(ParameterSet const& pset) const = 0;
367 
368  virtual int howManyXORSubNodesExist_(ParameterSet const& pset) const = 0;
369 
371  };
372 
373  template <>
375  static ParameterDescriptionNode* clone(ParameterDescriptionNode const* p) { return p->clone(); }
376  static void destroy(ParameterDescriptionNode* p) { delete p; }
377  };
378 
379  // operator>> ---------------------------------------------
380 
381  std::unique_ptr<ParameterDescriptionCases<bool>> operator>>(bool caseValue, ParameterDescriptionNode const& node);
382 
383  std::unique_ptr<ParameterDescriptionCases<int>> operator>>(int caseValue, ParameterDescriptionNode const& node);
384 
385  std::unique_ptr<ParameterDescriptionCases<std::string>> operator>>(std::string const& caseValue,
386  ParameterDescriptionNode const& node);
387 
388  std::unique_ptr<ParameterDescriptionCases<std::string>> operator>>(char const* caseValue,
389  ParameterDescriptionNode const& node);
390 
391  std::unique_ptr<ParameterDescriptionCases<bool>> operator>>(bool caseValue,
392  std::unique_ptr<ParameterDescriptionNode> node);
393 
394  std::unique_ptr<ParameterDescriptionCases<int>> operator>>(int caseValue,
395  std::unique_ptr<ParameterDescriptionNode> node);
396 
397  std::unique_ptr<ParameterDescriptionCases<std::string>> operator>>(std::string const& caseValue,
398  std::unique_ptr<ParameterDescriptionNode> node);
399 
400  std::unique_ptr<ParameterDescriptionCases<std::string>> operator>>(char const* caseValue,
401  std::unique_ptr<ParameterDescriptionNode> node);
402 
403  // operator&& ---------------------------------------------
404 
405  std::unique_ptr<ParameterDescriptionNode> operator&&(ParameterDescriptionNode const& node_left,
406  ParameterDescriptionNode const& node_right);
407 
408  std::unique_ptr<ParameterDescriptionNode> operator&&(std::unique_ptr<ParameterDescriptionNode> node_left,
409  ParameterDescriptionNode const& node_right);
410 
411  std::unique_ptr<ParameterDescriptionNode> operator&&(ParameterDescriptionNode const& node_left,
412  std::unique_ptr<ParameterDescriptionNode> node_right);
413 
414  std::unique_ptr<ParameterDescriptionNode> operator&&(std::unique_ptr<ParameterDescriptionNode> node_left,
415  std::unique_ptr<ParameterDescriptionNode> node_right);
416 
417  // operator|| ---------------------------------------------
418 
419  std::unique_ptr<ParameterDescriptionNode> operator||(ParameterDescriptionNode const& node_left,
420  ParameterDescriptionNode const& node_right);
421 
422  std::unique_ptr<ParameterDescriptionNode> operator||(std::unique_ptr<ParameterDescriptionNode> node_left,
423  ParameterDescriptionNode const& node_right);
424 
425  std::unique_ptr<ParameterDescriptionNode> operator||(ParameterDescriptionNode const& node_left,
426  std::unique_ptr<ParameterDescriptionNode> node_right);
427 
428  std::unique_ptr<ParameterDescriptionNode> operator||(std::unique_ptr<ParameterDescriptionNode> node_left,
429  std::unique_ptr<ParameterDescriptionNode> node_right);
430 
431  // operator^ ---------------------------------------------
432 
433  std::unique_ptr<ParameterDescriptionNode> operator^(ParameterDescriptionNode const& node_left,
434  ParameterDescriptionNode const& node_right);
435 
436  std::unique_ptr<ParameterDescriptionNode> operator^(std::unique_ptr<ParameterDescriptionNode> node_left,
437  ParameterDescriptionNode const& node_right);
438 
439  std::unique_ptr<ParameterDescriptionNode> operator^(ParameterDescriptionNode const& node_left,
440  std::unique_ptr<ParameterDescriptionNode> node_right);
441 
442  std::unique_ptr<ParameterDescriptionNode> operator^(std::unique_ptr<ParameterDescriptionNode> node_left,
443  std::unique_ptr<ParameterDescriptionNode> node_right);
444 } // namespace edm
445 #endif
bool shouldWriteUntyped(CfiOptions const &iOps) noexcept
std::vector< std::string_view > presentPath_
void setComment(std::string const &value)
virtual ParameterDescriptionNode * clone() const =0
virtual bool partiallyExists_(ParameterSet const &pset) const =0
std::unique_ptr< ParameterDescriptionNode > operator &&(ParameterDescriptionNode const &node_left, ParameterDescriptionNode const &node_right)
virtual void checkAndGetLabelsAndTypes_(std::set< std::string > &usedLabels, std::set< ParameterTypes > &parameterTypes, std::set< ParameterTypes > &wildcardTypes) const =0
void pushNode(std::string_view iNode)
void print(std::ostream &os, bool optional, bool writeToCfi, DocFormatHelper &dfh) const
std::unique_ptr< ParameterDescriptionCases< bool > > operator>>(bool caseValue, ParameterDescriptionNode const &node)
NodeGuard(NodeGuard &&iOther)
assert(be >=bs)
virtual int howManyXORSubNodesExist_(ParameterSet const &pset) const =0
bool needToSwitchToTyped(std::string_view iNode)
std::string parameterTypeEnumToString(ParameterTypes iType)
static ParameterDescriptionNode * clone(ParameterDescriptionNode const *p)
void parameterMustBeTyped(CfiOptions &iOps) noexcept
void printNestedContent(std::ostream &os, bool optional, DocFormatHelper &dfh) const
std::vector< std::string_view > presentPath_
double f[11][100]
optional
Definition: Types.py:245
Definition: value.py:1
d
Definition: ztail.py:151
static void printSpaces(std::ostream &os, int n)
std::variant< cfi::Typed, cfi::ClassFile, cfi::Untyped > CfiOptions
std::string const & comment() const
bool partiallyExists(ParameterSet const &pset) const
std::unique_ptr< ParameterDescriptionCases< bool > > operator||(std::unique_ptr< ParameterDescriptionCases< bool > >, std::unique_ptr< ParameterDescriptionCases< bool > >)
void checkAndGetLabelsAndTypes(std::set< std::string > &usedLabels, std::set< ParameterTypes > &parameterTypes, std::set< ParameterTypes > &wildcardTypes) const
std::string const & comment() const
int howManyXORSubNodesExist(ParameterSet const &pset) const
bool exists(ParameterSet const &pset) const
virtual void validate_(ParameterSet &pset, std::set< std::string > &validatedLabels, bool optional) const =0
static ParameterTypes toEnum()
HLT enums.
static void destroy(ParameterDescriptionNode *p)
std::optional< std::unordered_map< std::string, Paths > > nodes_
std::unique_ptr< ParameterDescriptionNode > operator^(ParameterDescriptionNode const &node_left, ParameterDescriptionNode const &node_right)
virtual bool exists_(ParameterSet const &pset) const =0
void writeCfi(std::ostream &os, bool optional, bool &startWithComma, int indentation, CfiOptions &options, bool &wroteSomething) const
NodeGuard & operator=(NodeGuard &&iOther)
virtual void print_(std::ostream &, bool, bool, DocFormatHelper &) const
virtual void printNestedContent_(std::ostream &, bool, DocFormatHelper &) const
NodeGuard & operator=(NodeGuard const &)=delete
void validate(ParameterSet &pset, std::set< std::string > &validatedLabels, bool optional) const
ParameterDescriptionNode(Comment const &iComment)
std::pair< bool, NodeGuard > needToSwitchToTyped(std::string_view iNode, CfiOptions &iOpt) noexcept
def move(src, dest)
Definition: eostools.py:511
cfi::CfiOptions CfiOptions
virtual void writeCfi_(std::ostream &os, bool optional, bool &startWithComma, int indentation, CfiOptions &, bool &wroteSomething) const =0