Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-05-23 03:13:12

0001 #ifndef FWCore_ParameterSet_ParameterDescriptionNode_h
0002 #define FWCore_ParameterSet_ParameterDescriptionNode_h
0003 
0004 // This is a base class for the class that describes
0005 // the parameters that are allowed or required to be
0006 // in a ParameterSet.  It is also a base class for
0007 // other more complex logical structures which describe
0008 // which combinations of parameters are allowed to be
0009 // in a ParameterSet.
0010 
0011 #include "FWCore/Utilities/interface/value_ptr.h"
0012 
0013 #include <string>
0014 #include <set>
0015 #include <iosfwd>
0016 #include <memory>
0017 #include <variant>
0018 #include <optional>
0019 #include <unordered_map>
0020 #include <vector>
0021 #include <cassert>
0022 
0023 namespace edm {
0024 
0025   class ParameterSet;
0026   template <typename T>
0027   class ParameterDescriptionCases;
0028   class DocFormatHelper;
0029 
0030   // Originally these were defined such that the values were the
0031   // same as in the ParameterSet Entry class and the validation
0032   // depended on that.  But at the moment I'm typing this comment,
0033   // the code no longer depends on the values being the same (which
0034   // is probably good because nothing enforces the correspondence,
0035   // a task for the future when someone has free time would be
0036   // to define the values in a common header, but that would involve
0037   // significant changes to ParameterSet ...)
0038   enum ParameterTypes {
0039     k_int32 = 'I',
0040     k_vint32 = 'i',
0041     k_uint32 = 'U',
0042     k_vuint32 = 'u',
0043     k_int64 = 'L',
0044     k_vint64 = 'l',
0045     k_uint64 = 'X',
0046     k_vuint64 = 'x',
0047     k_double = 'D',
0048     k_vdouble = 'd',
0049     k_bool = 'B',
0050     k_stringRaw = 'Z',
0051     k_vstringRaw = 'z',
0052     k_stringHex = 'S',
0053     k_vstringHex = 's',
0054     k_EventID = 'E',
0055     k_VEventID = 'e',
0056     k_LuminosityBlockID = 'M',
0057     k_VLuminosityBlockID = 'm',
0058     k_InputTag = 't',
0059     k_VInputTag = 'v',
0060     k_ESInputTag = 'g',
0061     k_VESInputTag = 'G',
0062     k_FileInPath = 'F',
0063     k_LuminosityBlockRange = 'A',
0064     k_VLuminosityBlockRange = 'a',
0065     k_EventRange = 'R',
0066     k_VEventRange = 'r',
0067     k_PSet = 'Q',
0068     k_VPSet = 'q'
0069   };
0070 
0071   std::string parameterTypeEnumToString(ParameterTypes iType);
0072 
0073   namespace cfi {
0074     struct Paths {
0075       //This is the 'path' through the cms.PSet hierarchy.
0076       // E.g. foo.bar.tar would have a Path for foo, bar, and tar with
0077       // tar having a null nodes_ variable.
0078       std::optional<std::unordered_map<std::string, Paths>> nodes_;
0079     };
0080     struct Typed {};
0081     struct ClassFile {
0082       void parameterMustBeTyped() {
0083         Paths* p = &fullPaths_;
0084         for (auto n : presentPath_) {
0085           if (not p->nodes_) {
0086             p->nodes_ = std::unordered_map<std::string, Paths>();
0087           }
0088           p = &(p->nodes_.value().emplace(n, Paths{})).first->second;
0089         }
0090       }
0091       void pushNode(std::string_view iNode) { presentPath_.push_back(iNode); }
0092       void popNode() {
0093         assert(not presentPath_.empty());
0094         presentPath_.pop_back();
0095       }
0096 
0097       Paths releasePaths() { return std::move(fullPaths_); }
0098 
0099     private:
0100       std::vector<std::string_view> presentPath_;
0101       Paths fullPaths_;
0102     };
0103     struct Untyped {
0104       Untyped(Paths iPaths) : paths_(iPaths) {}
0105       bool needToSwitchToTyped(std::string_view iNode) {
0106         presentPath_.push_back(iNode);
0107         if (not paths_.nodes_.has_value()) {
0108           return false;
0109         }
0110         const Paths* p = &paths_;
0111         for (auto const& n : presentPath_) {
0112           if (not paths_.nodes_.has_value()) {
0113             return false;
0114           }
0115           auto f = paths_.nodes_->find(std::string(n));
0116           if (f == paths_.nodes_->end()) {
0117             return false;
0118           }
0119           p = &f->second;
0120         }
0121         return not p->nodes_.has_value();
0122       }
0123       void popNode() {
0124         assert(not presentPath_.empty());
0125         presentPath_.pop_back();
0126       }
0127 
0128     private:
0129       std::vector<std::string_view> presentPath_;
0130       Paths paths_;
0131     };
0132 
0133     using CfiOptions = std::variant<cfi::Typed, cfi::ClassFile, cfi::Untyped>;
0134 
0135     inline void parameterMustBeTyped(CfiOptions& iOps) noexcept {
0136       if (std::holds_alternative<cfi::ClassFile>(iOps)) {
0137         std::get<cfi::ClassFile>(iOps).parameterMustBeTyped();
0138       }
0139     }
0140     inline void parameterMustBeTyped(CfiOptions& iOps, std::string_view iNode) noexcept {
0141       if (std::holds_alternative<cfi::ClassFile>(iOps)) {
0142         auto& d = std::get<cfi::ClassFile>(iOps);
0143         d.pushNode(iNode);
0144         d.parameterMustBeTyped();
0145         d.popNode();
0146       }
0147     }
0148     [[nodiscard]] inline bool shouldWriteUntyped(CfiOptions const& iOps) noexcept {
0149       return std::holds_alternative<cfi::Untyped>(iOps);
0150     }
0151 
0152     struct NodeGuard {
0153       NodeGuard(CfiOptions& iOp) : options_(&iOp) {}
0154       NodeGuard() = delete;
0155       NodeGuard(NodeGuard const&) = delete;
0156       NodeGuard& operator=(NodeGuard const&) = delete;
0157       NodeGuard(NodeGuard&& iOther) : options_{iOther.options_} { iOther.options_ = nullptr; }
0158       NodeGuard& operator=(NodeGuard&& iOther) {
0159         NodeGuard temp{std::move(iOther)};
0160         options_ = temp.options_;
0161         temp.options_ = nullptr;
0162         return *this;
0163       }
0164       ~NodeGuard() {
0165         if (nullptr == options_) {
0166           return;
0167         }
0168         if (std::holds_alternative<ClassFile>(*options_)) {
0169           std::get<ClassFile>(*options_).popNode();
0170         } else if (std::holds_alternative<Untyped>(*options_)) {
0171           std::get<Untyped>(*options_).popNode();
0172         }
0173       }
0174       CfiOptions* options_;
0175     };
0176 
0177     [[nodiscard]] inline std::pair<bool, NodeGuard> needToSwitchToTyped(std::string_view iNode,
0178                                                                         CfiOptions& iOpt) noexcept {
0179       if (std::holds_alternative<Untyped>(iOpt)) {
0180         return std::pair(std::get<Untyped>(iOpt).needToSwitchToTyped(iNode), NodeGuard(iOpt));
0181       } else if (std::holds_alternative<ClassFile>(iOpt)) {
0182         std::get<ClassFile>(iOpt).pushNode(iNode);
0183       }
0184       return std::pair(false, NodeGuard(iOpt));
0185     }
0186   }  // namespace cfi
0187   using CfiOptions = cfi::CfiOptions;
0188 
0189   struct ParameterTypeToEnum {
0190     template <class T>
0191     static ParameterTypes toEnum();
0192   };
0193 
0194   class Comment {
0195   public:
0196     Comment();
0197     explicit Comment(std::string const& iComment);
0198     explicit Comment(char const* iComment);
0199     std::string const& comment() const { return comment_; }
0200 
0201   private:
0202     std::string comment_;
0203   };
0204 
0205   class ParameterDescriptionNode {
0206   public:
0207     ParameterDescriptionNode() {}
0208 
0209     explicit ParameterDescriptionNode(Comment const& iComment) : comment_(iComment.comment()) {}
0210 
0211     virtual ~ParameterDescriptionNode();
0212 
0213     virtual ParameterDescriptionNode* clone() const = 0;
0214 
0215     std::string const& comment() const { return comment_; }
0216     void setComment(std::string const& value);
0217     void setComment(char const* value);
0218 
0219     // The validate function should do one of three things, find that the
0220     // node "exists", make the node "exist" by inserting missing parameters
0221     // or throw.  The only exception to this rule occurs when the argument
0222     // named "optional" is true, which should only be possible for the
0223     // top level nodes of a ParameterSetDescription.  When a parameter is
0224     // found or inserted its label is added into the list of validatedLabels.
0225     void validate(ParameterSet& pset, std::set<std::string>& validatedLabels, bool optional) const {
0226       validate_(pset, validatedLabels, optional);
0227     }
0228 
0229     // As long as it has default values, this will attempt to write
0230     // parameters associated with a node into a cfi file that is
0231     // being automatically generated.  It is quite possible for
0232     // to produce a cfi that will fail validation.  In some cases,
0233     // this will imply the user is required to supply certain missing
0234     // parameters that do not appear in the cfi and do not have defaults
0235     // in the description.  It is also possible to create a pathological
0236     // ParameterSetDescription where the algorithm fails to write
0237     // a valid cfi, in some cases the description can be so pathological
0238     // that it is impossible to write a cfi that will pass validation.
0239     void writeCfi(std::ostream& os,
0240                   bool optional,
0241                   bool& startWithComma,
0242                   int indentation,
0243                   CfiOptions& options,
0244                   bool& wroteSomething) const {
0245       writeCfi_(os, optional, startWithComma, indentation, options, wroteSomething);
0246     }
0247 
0248     // Print out the description in human readable format
0249     void print(std::ostream& os, bool optional, bool writeToCfi, DocFormatHelper& dfh) const;
0250 
0251     bool hasNestedContent() const { return hasNestedContent_(); }
0252 
0253     void printNestedContent(std::ostream& os, bool optional, DocFormatHelper& dfh) const;
0254 
0255     // The next three functions are only called by the logical nodes
0256     // on their subnodes.  When executing these functions, the
0257     // insertion of missing parameters does not occur.
0258 
0259     // Usually checks to see if a parameter exists in the configuration, but
0260     // if the node is a logical node, then it returns the value of the logical
0261     // expression.
0262     bool exists(ParameterSet const& pset) const { return exists_(pset); }
0263 
0264     // For most nodes, this simply returns the same value as the exists
0265     // function.  But for AND nodes this returns true if either its subnodes
0266     // exists.  Used by operator&& during validation, if either of an AND node's
0267     // subnodes exists, then both subnodes get validated.
0268     bool partiallyExists(ParameterSet const& pset) const { return partiallyExists_(pset); }
0269 
0270     // For most nodes, this simply returns the same value as the exists
0271     // function. It is different for an XOR node.  It counts
0272     // XOR subnodes whose exists function returns true.  And it
0273     // does this recursively into XOR nodes that are contained in
0274     // other XOR nodes.
0275     // Used by operator^ during validation:
0276     // -- if it returns more than 1, then validation will throw,
0277     // -- if it returns exactly one, then only the nonzero subnode gets validated
0278     // -- if it returns zero, then validation tries to validate the first node and
0279     // then rechecks to see what the missing parameter insertion did (there could
0280     // be side effects on the nodes that were not validated)
0281     int howManyXORSubNodesExist(ParameterSet const& pset) const { return howManyXORSubNodesExist_(pset); }
0282 
0283     /* Validation puts requirements on which parameters can and cannot exist
0284     within a ParameterSet.  The evaluation of whether a ParameterSet passes
0285     or fails the rules in the ParameterSetDescription is complicated by
0286     the fact that we allow missing parameters to be injected into the
0287     ParameterSet during validation.  One must worry whether injecting a
0288     missing parameter invalidates some other part of the ParameterSet that
0289     was already checked and determined to be OK.  The following restrictions
0290     avoid that problem.
0291 
0292         - The same parameter labels cannot occur in different nodes of the
0293         same ParameterSetDescription.  There are two exceptions to this.
0294         Nodes that are contained in the cases of a ParameterSwitch or the
0295         subnodes of an "exclusive or" are allowed to use the same labels.
0296 
0297         - If insertion is necessary to make an "exclusive or" node pass
0298         validation, then the insertion could make more than one of the
0299         possibilities evaluate true.  This must be checked for after the
0300         insertions occur. The behavior is to throw a Configuration exception
0301         if this problem is encountered. (Example: (A && B) ^ (A && C) where
0302         C already exists in the ParameterSet but A and B do not.  A and B
0303         get inserted by the algorithm, because it tries to make the first
0304         possibility true when all fail without insertion.  Then both
0305         parts of the "exclusive or" pass, which is a validation failure).
0306 
0307         - Another potential problem is that a parameter insertion related
0308         to one ParameterDescription could match unrelated wildcards causing
0309         other validation requirements to change from being passing to failing
0310         or vice versa.  This makes it almost impossible to determine if a
0311         ParameterSet passes validation.  Each time you try to loop through
0312         and check, the result of validation could change.  To avoid this problem,
0313         a list is maintained of the type for all wildcards.  Another list is
0314         maintained for the type of all parameters.  As new items are added
0315         we check for collisions.  The function that builds the ParameterSetDescription,
0316         will throw if this rule is violated.  At the moment, the criteria
0317         for a collision is matching types between a parameter and a wildcard.
0318         (This criteria is overrestrictive.  With some additional CPU and
0319         code development the restriction could be loosened to parameters that
0320         might be injected cannot match the type, trackiness, and wildcard label
0321         pattern of any wildcard that requires a match.  And further this
0322         could not apply to wildcards on different branches of a ParameterSwitch
0323         or "exclusive or".)
0324 
0325     These restrictions have the additional benefit that the things they prohibit
0326     would tend to confuse a user trying to configure a module or a module developer
0327     writing the code to extract the parameters from a ParameterSet.  These rules
0328     tend to prohibit bad design.
0329 
0330     One strategy to avoid problems with wildcard parameters is to add a nested
0331     ParameterSet and put the wildcard parameters in the nested ParameterSet.
0332     The names and types in a nested ParameterSet will not interfere with names
0333     in the containing ParameterSet.
0334     */
0335     void checkAndGetLabelsAndTypes(std::set<std::string>& usedLabels,
0336                                    std::set<ParameterTypes>& parameterTypes,
0337                                    std::set<ParameterTypes>& wildcardTypes) const {
0338       checkAndGetLabelsAndTypes_(usedLabels, parameterTypes, wildcardTypes);
0339     }
0340 
0341     virtual bool isWildcard() const { return false; }
0342     static void printSpaces(std::ostream& os, int n);
0343 
0344   protected:
0345     virtual void checkAndGetLabelsAndTypes_(std::set<std::string>& usedLabels,
0346                                             std::set<ParameterTypes>& parameterTypes,
0347                                             std::set<ParameterTypes>& wildcardTypes) const = 0;
0348 
0349     virtual void validate_(ParameterSet& pset, std::set<std::string>& validatedLabels, bool optional) const = 0;
0350 
0351     virtual void writeCfi_(std::ostream& os,
0352                            bool optional,
0353                            bool& startWithComma,
0354                            int indentation,
0355                            CfiOptions&,
0356                            bool& wroteSomething) const = 0;
0357 
0358     virtual void print_(std::ostream&, bool /*optional*/, bool /*writeToCfi*/, DocFormatHelper&) const {}
0359 
0360     virtual bool hasNestedContent_() const { return false; }
0361 
0362     virtual void printNestedContent_(std::ostream&, bool /*optional*/, DocFormatHelper&) const {}
0363 
0364     virtual bool exists_(ParameterSet const& pset) const = 0;
0365 
0366     virtual bool partiallyExists_(ParameterSet const& pset) const = 0;
0367 
0368     virtual int howManyXORSubNodesExist_(ParameterSet const& pset) const = 0;
0369 
0370     std::string comment_;
0371   };
0372 
0373   template <>
0374   struct value_ptr_traits<ParameterDescriptionNode> {
0375     static ParameterDescriptionNode* clone(ParameterDescriptionNode const* p) { return p->clone(); }
0376     static void destroy(ParameterDescriptionNode* p) { delete p; }
0377   };
0378 
0379   // operator>> ---------------------------------------------
0380 
0381   std::unique_ptr<ParameterDescriptionCases<bool>> operator>>(bool caseValue, ParameterDescriptionNode const& node);
0382 
0383   std::unique_ptr<ParameterDescriptionCases<int>> operator>>(int caseValue, ParameterDescriptionNode const& node);
0384 
0385   std::unique_ptr<ParameterDescriptionCases<std::string>> operator>>(std::string const& caseValue,
0386                                                                      ParameterDescriptionNode const& node);
0387 
0388   std::unique_ptr<ParameterDescriptionCases<std::string>> operator>>(char const* caseValue,
0389                                                                      ParameterDescriptionNode const& node);
0390 
0391   std::unique_ptr<ParameterDescriptionCases<bool>> operator>>(bool caseValue,
0392                                                               std::unique_ptr<ParameterDescriptionNode> node);
0393 
0394   std::unique_ptr<ParameterDescriptionCases<int>> operator>>(int caseValue,
0395                                                              std::unique_ptr<ParameterDescriptionNode> node);
0396 
0397   std::unique_ptr<ParameterDescriptionCases<std::string>> operator>>(std::string const& caseValue,
0398                                                                      std::unique_ptr<ParameterDescriptionNode> node);
0399 
0400   std::unique_ptr<ParameterDescriptionCases<std::string>> operator>>(char const* caseValue,
0401                                                                      std::unique_ptr<ParameterDescriptionNode> node);
0402 
0403   // operator&& ---------------------------------------------
0404 
0405   std::unique_ptr<ParameterDescriptionNode> operator&&(ParameterDescriptionNode const& node_left,
0406                                                        ParameterDescriptionNode const& node_right);
0407 
0408   std::unique_ptr<ParameterDescriptionNode> operator&&(std::unique_ptr<ParameterDescriptionNode> node_left,
0409                                                        ParameterDescriptionNode const& node_right);
0410 
0411   std::unique_ptr<ParameterDescriptionNode> operator&&(ParameterDescriptionNode const& node_left,
0412                                                        std::unique_ptr<ParameterDescriptionNode> node_right);
0413 
0414   std::unique_ptr<ParameterDescriptionNode> operator&&(std::unique_ptr<ParameterDescriptionNode> node_left,
0415                                                        std::unique_ptr<ParameterDescriptionNode> node_right);
0416 
0417   // operator|| ---------------------------------------------
0418 
0419   std::unique_ptr<ParameterDescriptionNode> operator||(ParameterDescriptionNode const& node_left,
0420                                                        ParameterDescriptionNode const& node_right);
0421 
0422   std::unique_ptr<ParameterDescriptionNode> operator||(std::unique_ptr<ParameterDescriptionNode> node_left,
0423                                                        ParameterDescriptionNode const& node_right);
0424 
0425   std::unique_ptr<ParameterDescriptionNode> operator||(ParameterDescriptionNode const& node_left,
0426                                                        std::unique_ptr<ParameterDescriptionNode> node_right);
0427 
0428   std::unique_ptr<ParameterDescriptionNode> operator||(std::unique_ptr<ParameterDescriptionNode> node_left,
0429                                                        std::unique_ptr<ParameterDescriptionNode> node_right);
0430 
0431   // operator^  ---------------------------------------------
0432 
0433   std::unique_ptr<ParameterDescriptionNode> operator^(ParameterDescriptionNode const& node_left,
0434                                                       ParameterDescriptionNode const& node_right);
0435 
0436   std::unique_ptr<ParameterDescriptionNode> operator^(std::unique_ptr<ParameterDescriptionNode> node_left,
0437                                                       ParameterDescriptionNode const& node_right);
0438 
0439   std::unique_ptr<ParameterDescriptionNode> operator^(ParameterDescriptionNode const& node_left,
0440                                                       std::unique_ptr<ParameterDescriptionNode> node_right);
0441 
0442   std::unique_ptr<ParameterDescriptionNode> operator^(std::unique_ptr<ParameterDescriptionNode> node_left,
0443                                                       std::unique_ptr<ParameterDescriptionNode> node_right);
0444 }  // namespace edm
0445 #endif