Line Code
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
#include <algorithm>
#include <string>
#include <string_view>
#include <regex>
#include <vector>

#include <boost/algorithm/string/replace.hpp>

#include "DataFormats/Provenance/interface/ProductNamePattern.h"
#include "FWCore/Utilities/interface/EDMException.h"

namespace edm {

  /* glob_to_regex
   *
   * Utility function to convert a shell-like glob expression to a regex.
   */
  static std::regex glob_to_regex(std::string pattern) {
    boost::replace_all(pattern, "*", ".*");
    boost::replace_all(pattern, "?", ".");
    return std::regex(pattern);
  }

  /* ProductNamePattern
   *
   * A ProductNamePattern is constructed from a string representing either a module label (e.g. "<module label>") or a
   * a branch name (e.g. "<product type>_<module label>_<instance name>_<process name>").
   *
   * For transient products, the module label may contain additional underscores.
   *
   * See DataFormats/Provenance/interface/ProductNamePattern.h for more details.
   */
  ProductNamePattern::ProductNamePattern(std::string const& label) {
    static constexpr char kSeparator = '_';
    static constexpr std::string_view kWildcard{"*"};
    static const std::regex kAny{".*"};
    static const std::regex kFields{"([a-zA-Z0-9*]+)_([a-zA-Z0-9_*]+)_([a-zA-Z0-9*]*)_([a-zA-Z0-9*]+)"};

    // empty label
    if (label.empty()) {
      throw edm::Exception(edm::errors::Configuration) << "Invalid module label or branch name: \"" << label << "\"";
    }

    // wildcard
    if (label == kWildcard) {
      type_ = kAny;
      moduleLabel_ = kAny;
      productInstanceName_ = kAny;
      processName_ = kAny;
      return;
    }

    int underscores = std::count(label.begin(), label.end(), kSeparator);
    if (underscores == 0) {
      // Convert the module label into a regular expression.
      type_ = kAny;
      moduleLabel_ = glob_to_regex(label);
      productInstanceName_ = kAny;
      processName_ = kAny;
      return;
    }

    if (underscores >= 3) {
      // Split the branch name into <product type>_<module label>_<instance name>_<process name>
      // and convert the glob expressions into regular expressions.
      // Note that:
      //   - the <instance name> may be empty;
      //   - for non-persistable branches, <module label> may contain additional underscores.
      std::smatch fields;
      if (std::regex_match(label, fields, kFields)) {
        type_ = glob_to_regex(fields[1]);
        moduleLabel_ = glob_to_regex(fields[2]);
        productInstanceName_ = glob_to_regex(fields[3]);
        processName_ = glob_to_regex(fields[4]);
        return;
      }
    }

    // Invalid input.
    throw edm::Exception(edm::errors::Configuration) << "Invalid module label or branch name: \"" << label << "\"";
  }

  /* ProductNamePattern::match
   *
   * Compare a ProductNamePattern object with a ProductDescription object.
   */
  bool ProductNamePattern::match(edm::ProductDescription const& product) const {
    return (std::regex_match(product.friendlyClassName(), type_) and
            std::regex_match(product.moduleLabel(), moduleLabel_) and
            std::regex_match(product.productInstanceName(), productInstanceName_) and
            std::regex_match(product.processName(), processName_));
  }

  /* productPatterns
   *
   * Utility function to construct a vector<edm::ProductNamePattern> from a vector<std::string>.
   */
  std::vector<ProductNamePattern> productPatterns(std::vector<std::string> const& labels) {
    std::vector<ProductNamePattern> patterns;
    patterns.reserve(labels.size());
    for (auto const& label : labels)
      patterns.emplace_back(label);
    return patterns;
  }

}  // namespace edm