File indexing completed on 2024-04-06 12:12:49
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032 #include "DataFormats/Common/interface/PathStatus.h"
0033 #include "FWCore/Framework/interface/ConsumesCollector.h"
0034 #include "FWCore/Framework/interface/Event.h"
0035 #include "FWCore/Framework/interface/global/EDFilter.h"
0036 #include "FWCore/Framework/interface/MakerMacros.h"
0037 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0038 #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
0039 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0040 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
0041 #include "FWCore/Utilities/interface/EDGetToken.h"
0042 #include "FWCore/Utilities/interface/Exception.h"
0043 #include "FWCore/Utilities/interface/InputTag.h"
0044 #include "FWCore/Utilities/interface/propagate_const.h"
0045
0046 #include <boost/spirit/include/qi.hpp>
0047
0048 #include <functional>
0049 #include <memory>
0050 #include <ostream>
0051 #include <string>
0052 #include <sstream>
0053 #include <vector>
0054 #include <utility>
0055
0056 namespace qi = boost::spirit::qi;
0057 namespace ascii = boost::spirit::ascii;
0058
0059 namespace edm {
0060
0061 class EventSetup;
0062 class StreamID;
0063
0064 namespace pathStatusExpression {
0065 class Evaluator;
0066 }
0067
0068 class PathStatusFilter : public global::EDFilter<> {
0069 public:
0070 explicit PathStatusFilter(ParameterSet const&);
0071 static void fillDescriptions(ConfigurationDescriptions&);
0072 bool filter(StreamID, Event&, EventSetup const&) const final;
0073
0074 private:
0075 edm::propagate_const<std::unique_ptr<pathStatusExpression::Evaluator>> evaluator_;
0076 bool verbose_;
0077 };
0078
0079 namespace pathStatusExpression {
0080
0081 class Evaluator {
0082 public:
0083 virtual ~Evaluator() {}
0084
0085 enum EvaluatorType { Name, Not, And, Or, BeginParen };
0086 virtual EvaluatorType type() const = 0;
0087
0088 virtual void setLeft(std::unique_ptr<Evaluator>&&) {}
0089 virtual void setRight(std::unique_ptr<Evaluator>&&) {}
0090
0091 virtual void print(std::ostream& out, unsigned int indentation) const {}
0092 virtual void init(ConsumesCollector&) {}
0093 virtual bool evaluate(Event const& event) const { return true; };
0094 };
0095
0096 class Operand : public Evaluator {
0097 public:
0098 Operand(std::vector<char> const& pathName) : pathName_(pathName.begin(), pathName.end()) {}
0099
0100 EvaluatorType type() const override { return Name; }
0101
0102 void print(std::ostream& out, unsigned int indentation) const override {
0103 out << std::string(indentation, ' ') << pathName_ << "\n";
0104 }
0105
0106 void init(ConsumesCollector& iC) override { token_ = iC.consumes<PathStatus>(InputTag(pathName_)); }
0107
0108 bool evaluate(Event const& event) const override { return event.get(token_).accept(); }
0109
0110 private:
0111 std::string pathName_;
0112 EDGetTokenT<PathStatus> token_;
0113 };
0114
0115 class NotOperator : public Evaluator {
0116 public:
0117 EvaluatorType type() const override { return Not; }
0118
0119 void setLeft(std::unique_ptr<Evaluator>&& v) override { operand_ = std::move(v); }
0120
0121 void print(std::ostream& out, unsigned int indentation) const override {
0122 out << std::string(indentation, ' ') << "not\n";
0123 operand_->print(out, indentation + 4);
0124 }
0125
0126 void init(ConsumesCollector& iC) override { operand_->init(iC); }
0127
0128 bool evaluate(Event const& event) const override { return !operand_->evaluate(event); }
0129
0130 private:
0131 edm::propagate_const<std::unique_ptr<Evaluator>> operand_;
0132 };
0133
0134 template <typename T>
0135 class BinaryOperator : public Evaluator {
0136 public:
0137 EvaluatorType type() const override;
0138
0139 void setLeft(std::unique_ptr<Evaluator>&& v) override { left_ = std::move(v); }
0140 void setRight(std::unique_ptr<Evaluator>&& v) override { right_ = std::move(v); }
0141
0142 void print(std::ostream& out, unsigned int indentation) const override;
0143
0144 void init(ConsumesCollector& iC) override {
0145 left_->init(iC);
0146 right_->init(iC);
0147 }
0148
0149 bool evaluate(Event const& event) const override {
0150 T op;
0151 return op(left_->evaluate(event), right_->evaluate(event));
0152 }
0153
0154 private:
0155 edm::propagate_const<std::unique_ptr<Evaluator>> left_;
0156 edm::propagate_const<std::unique_ptr<Evaluator>> right_;
0157 };
0158
0159 template <>
0160 inline Evaluator::EvaluatorType BinaryOperator<std::logical_and<bool>>::type() const {
0161 return And;
0162 }
0163
0164 template <>
0165 inline Evaluator::EvaluatorType BinaryOperator<std::logical_or<bool>>::type() const {
0166 return Or;
0167 }
0168
0169 template <>
0170 void BinaryOperator<std::logical_and<bool>>::print(std::ostream& out, unsigned int indentation) const {
0171 out << std::string(indentation, ' ') << "and\n";
0172 left_->print(out, indentation + 4);
0173 right_->print(out, indentation + 4);
0174 }
0175 template <>
0176 void BinaryOperator<std::logical_or<bool>>::print(std::ostream& out, unsigned int indentation) const {
0177 out << std::string(indentation, ' ') << "or\n";
0178 left_->print(out, indentation + 4);
0179 right_->print(out, indentation + 4);
0180 }
0181
0182 using AndOperator = BinaryOperator<std::logical_and<bool>>;
0183 using OrOperator = BinaryOperator<std::logical_or<bool>>;
0184
0185 class BeginParenthesis : public Evaluator {
0186 public:
0187 EvaluatorType type() const override { return BeginParen; }
0188 };
0189
0190
0191
0192
0193
0194 class ShuntingYardAlgorithm {
0195 public:
0196 void addPathName(std::vector<char> const& s) { operandStack.push_back(std::make_unique<Operand>(s)); }
0197
0198 void addOperatorNot() {
0199 if (operatorStack.empty() || operatorStack.back()->type() != Evaluator::Not) {
0200 operatorStack.push_back(std::make_unique<NotOperator>());
0201 } else {
0202
0203 operatorStack.pop_back();
0204 }
0205 }
0206
0207 void moveBinaryOperator() {
0208 std::unique_ptr<Evaluator>& backEvaluator = operatorStack.back();
0209 backEvaluator->setRight(std::move(operandStack.back()));
0210 operandStack.pop_back();
0211 backEvaluator->setLeft(std::move(operandStack.back()));
0212 operandStack.pop_back();
0213 operandStack.push_back(std::move(backEvaluator));
0214 operatorStack.pop_back();
0215 }
0216
0217 void moveNotOperator() {
0218 std::unique_ptr<Evaluator>& backEvaluator = operatorStack.back();
0219 backEvaluator->setLeft(std::move(operandStack.back()));
0220 operandStack.pop_back();
0221 operandStack.push_back(std::move(backEvaluator));
0222 operatorStack.pop_back();
0223 }
0224
0225 void addOperatorAnd() {
0226 while (!operatorStack.empty()) {
0227 std::unique_ptr<Evaluator>& backEvaluator = operatorStack.back();
0228 if (backEvaluator->type() == Evaluator::And) {
0229 moveBinaryOperator();
0230 } else if (backEvaluator->type() == Evaluator::Not) {
0231 moveNotOperator();
0232 } else {
0233 break;
0234 }
0235 }
0236 operatorStack.push_back(std::make_unique<AndOperator>());
0237 }
0238
0239 void addOperatorOr() {
0240 while (!operatorStack.empty()) {
0241 std::unique_ptr<Evaluator>& backEvaluator = operatorStack.back();
0242 if (backEvaluator->type() == Evaluator::And || backEvaluator->type() == Evaluator::Or) {
0243 moveBinaryOperator();
0244 } else if (backEvaluator->type() == Evaluator::Not) {
0245 moveNotOperator();
0246 } else {
0247 break;
0248 }
0249 }
0250 operatorStack.push_back(std::make_unique<OrOperator>());
0251 }
0252
0253 void addBeginParenthesis() { operatorStack.push_back(std::make_unique<BeginParenthesis>()); }
0254
0255 void addEndParenthesis() {
0256 while (!operatorStack.empty()) {
0257 std::unique_ptr<Evaluator>& backEvaluator = operatorStack.back();
0258 if (backEvaluator->type() == Evaluator::BeginParen) {
0259 operatorStack.pop_back();
0260 break;
0261 }
0262 if (backEvaluator->type() == Evaluator::And || backEvaluator->type() == Evaluator::Or) {
0263 moveBinaryOperator();
0264 } else if (backEvaluator->type() == Evaluator::Not) {
0265 moveNotOperator();
0266 }
0267 }
0268 }
0269
0270 std::unique_ptr<Evaluator> finish() {
0271 while (!operatorStack.empty()) {
0272 std::unique_ptr<Evaluator>& backEvaluator = operatorStack.back();
0273
0274
0275 if (backEvaluator->type() == Evaluator::BeginParen) {
0276 throw cms::Exception("LogicError")
0277 << "Should be impossible to get this error. Contact a Framework developer";
0278 }
0279 if (backEvaluator->type() == Evaluator::And || backEvaluator->type() == Evaluator::Or) {
0280 moveBinaryOperator();
0281 } else if (backEvaluator->type() == Evaluator::Not) {
0282 moveNotOperator();
0283 }
0284 }
0285
0286
0287 if (!operatorStack.empty() || operandStack.size() != 1U) {
0288 throw cms::Exception("LogicError") << "Should be impossible to get this error. Contact a Framework developer";
0289 }
0290 std::unique_ptr<Evaluator> temp = std::move(operandStack.back());
0291 operandStack.pop_back();
0292 return temp;
0293 }
0294
0295 private:
0296 std::vector<std::unique_ptr<Evaluator>> operandStack;
0297 std::vector<std::unique_ptr<Evaluator>> operatorStack;
0298 };
0299
0300
0301 template <typename Iterator>
0302 class Grammar : public qi::grammar<Iterator, ascii::space_type> {
0303 public:
0304 Grammar(ShuntingYardAlgorithm* algorithm) : Grammar::base_type(expression), algorithm_(algorithm) {
0305
0306 auto addPathName = std::bind(&ShuntingYardAlgorithm::addPathName, algorithm_, std::placeholders::_1);
0307 auto addOperatorNot = std::bind(&ShuntingYardAlgorithm::addOperatorNot, algorithm_);
0308 auto addOperatorAnd = std::bind(&ShuntingYardAlgorithm::addOperatorAnd, algorithm_);
0309 auto addOperatorOr = std::bind(&ShuntingYardAlgorithm::addOperatorOr, algorithm_);
0310 auto addBeginParenthesis = std::bind(&ShuntingYardAlgorithm::addBeginParenthesis, algorithm_);
0311 auto addEndParenthesis = std::bind(&ShuntingYardAlgorithm::addEndParenthesis, algorithm_);
0312
0313
0314 pathName = !unaryOperator >> !binaryOperatorTest >> (+qi::char_("a-zA-Z0-9_"))[addPathName];
0315 binaryOperand = (qi::lit('(')[addBeginParenthesis] >> expression >> qi::lit(')')[addEndParenthesis]) |
0316 (unaryOperator[addOperatorNot] >> binaryOperand) | pathName;
0317 afterOperator = ascii::space | &qi::lit('(') | &qi::eoi;
0318 unaryOperator = qi::lit("not") >> afterOperator;
0319
0320 binaryOperatorTest = (qi::lit("and") >> afterOperator) | (qi::lit("or") >> afterOperator);
0321 binaryOperator =
0322 (qi::lit("and") >> afterOperator)[addOperatorAnd] | (qi::lit("or") >> afterOperator)[addOperatorOr];
0323 expression = binaryOperand % binaryOperator;
0324 }
0325
0326 private:
0327 qi::rule<Iterator> pathName;
0328 qi::rule<Iterator, ascii::space_type> binaryOperand;
0329 qi::rule<Iterator> afterOperator;
0330 qi::rule<Iterator> unaryOperator;
0331 qi::rule<Iterator> binaryOperatorTest;
0332 qi::rule<Iterator> binaryOperator;
0333 qi::rule<Iterator, ascii::space_type> expression;
0334
0335 ShuntingYardAlgorithm* algorithm_;
0336 };
0337 }
0338
0339 PathStatusFilter::PathStatusFilter(ParameterSet const& pset)
0340 : evaluator_(nullptr), verbose_(pset.getUntrackedParameter<bool>("verbose")) {
0341 std::string const logicalExpression = pset.getParameter<std::string>("logicalExpression");
0342 if (verbose_) {
0343 LogAbsolute("PathStatusFilter") << "PathStatusFilter logicalExpression = " << logicalExpression;
0344 }
0345
0346 if (logicalExpression.empty()) {
0347 return;
0348 }
0349
0350 pathStatusExpression::ShuntingYardAlgorithm shuntingYardAlgorithm;
0351
0352 pathStatusExpression::Grammar<std::string::const_iterator> grammar(&shuntingYardAlgorithm);
0353
0354 auto it = logicalExpression.cbegin();
0355 if (!qi::phrase_parse(it, logicalExpression.cend(), grammar, ascii::space) || (it != logicalExpression.cend())) {
0356 throw cms::Exception("Configuration") << "Syntax error in logical expression. Here is an example of how\n"
0357 << "the syntax should look:\n"
0358 << " \"path1 and not (path2 or not path3)\"\n"
0359 << "The expression must contain alternating appearances of operands\n"
0360 << "which are path names and binary operators which can be \'and\'\n"
0361 << "or \'or\', with a path name at the beginning and end. There\n"
0362 << "must be at least one path name. In addition to the alternating\n"
0363 << "path names and binary operators, the unary operator \'not\' can\n"
0364 << "be inserted before a path name or a begin parenthesis.\n"
0365 << "Parentheses are allowed. Parentheses must come in matching pairs.\n"
0366 << "Matching begin and end parentheses must contain a complete and\n"
0367 << "syntactically correct logical expression. There must be at least\n"
0368 << "one space or parenthesis between operators and path names. Extra\n"
0369 << "space is ignored and OK. Path names can only contain upper and\n"
0370 << "lower case letters, numbers, and underscores. A path name cannot\n"
0371 << "be the same as an operator name.\n";
0372 }
0373
0374 evaluator_ = shuntingYardAlgorithm.finish();
0375 if (verbose_) {
0376 std::stringstream out;
0377 evaluator_->print(out, 0);
0378 LogAbsolute("PathStatusFilter") << out.str();
0379 }
0380 ConsumesCollector iC(consumesCollector());
0381 evaluator_->init(iC);
0382 }
0383
0384 void PathStatusFilter::fillDescriptions(ConfigurationDescriptions& descriptions) {
0385 ParameterSetDescription desc;
0386 desc.add<std::string>("logicalExpression", std::string())
0387 ->setComment(
0388 "Operands are path names. Operators in precedence order "
0389 "\'not\', \'and\', and \'or\'. Parentheses allowed.");
0390 desc.addUntracked<bool>("verbose", false)->setComment("For debugging only");
0391 descriptions.add("pathStatusFilter", desc);
0392 }
0393
0394 bool PathStatusFilter::filter(StreamID, Event& event, EventSetup const&) const {
0395 if (evaluator_ == nullptr) {
0396 return true;
0397 }
0398 return evaluator_->evaluate(event);
0399 }
0400 }
0401
0402 using edm::PathStatusFilter;
0403 DEFINE_FWK_MODULE(PathStatusFilter);