Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-16 09:03:56

0001 // InputParser.h is a part of the PYTHIA event generator.
0002 // Copyright (C) 2025 Christian Bierlich, Torbjorn Sjostrand.
0003 // PYTHIA is licenced under the GNU GPL v2 or later, see COPYING for details.
0004 // Please respect the MCnet Guidelines, see GUIDELINES for details.
0005 
0006 #ifndef Pythia8_InputParser_H
0007 #define Pythia8_InputParser_H
0008 
0009 // Includes.
0010 #include "Pythia8/PythiaStdlib.h"
0011 
0012 namespace Pythia8 {
0013 
0014 //==========================================================================
0015 
0016 // Convenience class for parsing C++ command-line arguments on the form
0017 // ./mainXX -a A -b B etc.
0018 //
0019 // Usage: (1) Create an InputParser object in your main program. (2)
0020 // Specify the command-line options that should be available, including
0021 // default values, using add. (3) Call the parse(int& argc, char** argv)
0022 // method, with the two aruments forwarded from argc and argv from your
0023 // main. (4) Extract given command-line values of type T, using get<T>.
0024 
0025 class InputParser {
0026 public:
0027 
0028   // Constructor.
0029   // usage: Text to print when describing usage with help.
0030   // examples: Vector of examples to print with help.
0031   // extra: Extra text to print with help.
0032   // stream: Optional pointer to stream to print messages to.
0033   // optName: Option name for the help flag.
0034   // aliases: Aliases for the help flag.
0035   InputParser(string usage = "", vector<string> examples = {},
0036     string extra = "", ostream* stream = &cout,
0037     string optName = "h", set<string> aliases = {"-help","H"}) :
0038     usageText(usage), examplesText(examples), extraText(extra),
0039       streamPtr(stream), helpFlag(optName) {
0040     add(optName, "false", "Show this help message and exit.", aliases);
0041   }
0042 
0043   // Add an optional command line option to the parser. Do this before parsing.
0044   // Parameters:
0045   // optName: The name of the option.
0046   // defString: The default value for the option.
0047   // helpText: The help text describing the option (optional).
0048   // aliases: A set of aliases for the option (optional).
0049   bool add(const string& optName, const string& defString,
0050     const string& helpText = "", set<string> aliases = {}) {
0051     // Check for name conflicts with existing options or aliases.
0052     if (options.find(optName) != options.end() ||
0053       aliasMap.find(optName) != aliasMap.end()) {
0054       print("Name conflict for '" + optName + "'.\n");
0055       return false;
0056     }
0057     // Create an OptionInfo object and add it to the options map.
0058     OptionInfo optInfo(optName, defString, helpText, aliases);
0059     options[optName] = optInfo;
0060     // Add aliases to the alias map.
0061     for (const string& alias : aliases) {
0062       if (options.find(alias) != options.end() ||
0063         aliasMap.find(alias) != aliasMap.end()) {
0064         print("Name conflict for alias '" + alias + "'.\n");
0065         return false;
0066       }
0067       aliasMap[alias] = optName;
0068     }
0069     return true;
0070   }
0071 
0072   // Add required command line option to the parser. Do this before parsing.
0073   bool require(const string& optName, const string& helpText = "",
0074     set<string> aliases = {}) {
0075     if (!add(optName, "", helpText, aliases)) return false;
0076     options[optName].required = true;
0077     return true;
0078   }
0079 
0080   // Initialize the parser. This includes parsing, printing help if
0081   // requested, and checking the required options.
0082   enum Status {Valid = -1, Invalid = EXIT_FAILURE, Help = EXIT_SUCCESS};
0083   Status init(int& argc, char** argv) {
0084 
0085     // Parse the arguments.
0086     bool valid = parse(argc, argv);
0087     if (!valid) return Status::Invalid;
0088 
0089     // Print the help if requested.
0090     if (options.find(helpFlag) != options.end() && get<bool>(helpFlag)) {
0091       string out;
0092       if (usageText != "") out = "Usage: " + usageText;
0093       if (examplesText.size() > 0) {
0094         out += "\nExample" + string(examplesText.size() > 1 ? "s:" : ":");
0095         for (const string& text: examplesText) out += "\n\t" + text;
0096       }
0097       if (options.size() > 0) {
0098         out += "\nOption" + string(options.size() > 1 ? "s:\n" : ":\n")
0099           + help() + "\n";
0100       }
0101       print(out + extraText);
0102       return Status::Help;
0103     }
0104 
0105     // Check the required options are set.
0106     for (map<string, OptionInfo>::iterator opt = options.begin();
0107          opt != options.end(); opt++) {
0108       if (opt->second.required && !opt->second.provided) {
0109         print("Option '-" + opt->first + "' is required but was not set.\n"
0110           "\t -" + opt->first + " " + opt->second.helpText + "\n");
0111         valid = false;
0112       }
0113     }
0114     return valid ? Status::Valid : Status::Invalid;
0115 
0116   }
0117 
0118   // Method to parse command line arguments.
0119   // Returns true if parsing was successful, false otherwise.
0120   // Print error messages to stream.
0121   // The hflag option specifies the help option.
0122   bool parse(int& argc, char** argv) {
0123     for (int i = 1; i < argc; ++i) {
0124       string arg = argv[i];
0125       // Check if the argument is an option (starts with '-').
0126       if (arg[0] == '-') {
0127         string optName = arg.substr(1);
0128         // Check for aliases and get the actual option name.
0129         if (aliasMap.find(optName) != aliasMap.end())
0130           optName = aliasMap[optName];
0131          // Check if the option is defined.
0132         if (options.find(optName) != options.end()) {
0133           // If the next argument is not an option, set the value for
0134           // this option.
0135           if (i + 1 < argc && argv[i + 1][0] != '-') {
0136             options[optName].stringValues.push_back(argv[++i]);
0137             options[optName].provided = true;
0138           } else {
0139             // Treat as boolean flag and flip its value.
0140             const string& def = options[optName].defaultValue;
0141             if (def == "false" || def == "False" || def == "0"
0142               || def == "off") {
0143               options[optName].stringValues.push_back("true");
0144               options[optName].provided = true;
0145             } else if (def == "true" || def == "True" || def == "1"
0146               || def == "on") {
0147               options[optName].stringValues.push_back("false");
0148               options[optName].provided = true;
0149             } else {
0150               print("Failed to parse command line arguments.\n"
0151                 "No value passed for option '" + string(arg) + "'.\n");
0152               return false;
0153             }
0154           }
0155         } else {
0156           print("Failed to parse command line arguments.\n"
0157             "Unknown option '" + string(arg) + "'.\n");
0158           return false;
0159         }
0160       }
0161     }
0162     return true;
0163   }
0164 
0165   // Check if an option is defined.
0166   // Returns true if the option is defined, false otherwise.
0167   bool has(const string& optName) const {
0168     return options.find(optName) != options.end();
0169   }
0170 
0171   // Templated method to get the last value of an option.
0172   // Returns the last value of the option converted to the specified type.
0173   template<typename T>
0174   T get(const string& optName) {
0175     if (!has(optName)) {
0176       print("Failed to find option '" + optName + "'.\n");
0177       return T();
0178     }
0179     // Retrieve the OptionInfo object for the given option name.
0180     const OptionInfo& optInfo = options.at(optName);
0181     // Return default-constructed T if string is empty.
0182     if (optInfo.stringValues.empty()) return T();
0183     if (optInfo.stringValues.back().empty()) return T();
0184     // Convert the string value to the specified type.
0185     stringstream conv(optInfo.stringValues.back());
0186     T value;
0187     conv >> std::boolalpha >> value;
0188     // Error message and default constructed T() is conversion failed.
0189     if (conv.fail()) {
0190       print("Failed to convert '" + optInfo.optName + "'.\n");
0191       return T();
0192     }
0193     return value;
0194   }
0195 
0196   // Templated method to get all the values of an option.
0197   template<typename T>
0198   vector<T> getVector(const string& optName) {
0199     vector<T> values;
0200     if (!has(optName)) {
0201       print("Failed to find option '" + optName + "'.\n");
0202       return values;
0203     }
0204     // Retrieve the OptionInfo object for the given option name.
0205     const OptionInfo& optInfo = options.at(optName);
0206     // Return empty vector if no values.
0207     if (optInfo.stringValues.empty()) return values;
0208     // Convert the string value to the specified type.
0209     for (const string& stringValue: optInfo.stringValues) {
0210       if (stringValue.empty()) {
0211         values.push_back(T());
0212         continue;
0213       }
0214       stringstream conv(stringValue);
0215       T value;
0216       conv >> std::boolalpha >> value;
0217       // Error message and default constructed T() is conversion failed.
0218       if (conv.fail()) {
0219         print("Failed to convert '" + optInfo.optName + "'.\n");
0220         return values;
0221       }
0222       values.push_back(value);
0223     }
0224     return values;
0225   }
0226 
0227   // Method to generate the help text for all options.
0228   // Returns a formatted string containing the help text.
0229   const string help() const {
0230     stringstream out;
0231     auto oItr = options.cbegin();
0232     while (oItr != options.cend()) {
0233       out << "\t-" << oItr->second.optName;
0234       if (!oItr->second.aliases.empty()) {
0235         out << " (";
0236         auto aItr = oItr->second.aliases.cbegin();
0237         while(aItr != oItr->second.aliases.cend()) {
0238           out << "-" << *aItr;
0239           if (++aItr != oItr->second.aliases.cend()) out << ", ";
0240         }
0241         out << ")";
0242       }
0243       else out << "\t";
0244       out << "\t" << oItr->second.helpText;
0245       if (oItr->second.required)
0246         out << " (required)";
0247       else if (oItr->second.defaultValue != "")
0248         out << " (default: " << oItr->second.defaultValue << ")";
0249       if (++oItr != options.cend()) out << "\n";
0250     }
0251     return out.str();
0252   }
0253 
0254 private:
0255 
0256   // Struct to hold information about each option.
0257   struct OptionInfo {
0258     // Default constructor must exist.
0259     OptionInfo() {}
0260     // Constructor to initialize all fields.
0261     OptionInfo(const string& n, const string& v, const string& h,
0262       set<string> a) : optName(n), defaultValue(v),
0263       stringValues(1, v), helpText(h), aliases(a) {}
0264     string optName;              // Name of the option.
0265     string defaultValue;         // Default value of the option.
0266     vector<string> stringValues; // Values of the option.
0267     string helpText;             // Help text for the option.
0268     set<string> aliases;         // Aliases for the option.
0269     bool required{false};        // Flag if this option must be provided.
0270     bool provided{false};        // Flag that the user provided this option.
0271   };
0272 
0273   // Members.
0274   string usageText{};            // Text for usage.
0275   vector<string> examplesText{}; // Text for examples.
0276   string extraText{};            // Extra text to print.
0277   ostream* streamPtr{};          // Optional stream to print messages.
0278   string helpFlag{};             // The flag used to access help.
0279 
0280   // Method to print to stream.
0281   void print(string out) {if (streamPtr != nullptr) *streamPtr << out;}
0282 
0283   // Map to store options with their names as keys.
0284   map<string, OptionInfo> options;
0285   // Map to store aliases with aliases as keys and option names as values.
0286   map<string, string> aliasMap;
0287 
0288 };
0289 
0290 } // end namespace Pythia8
0291 
0292 #endif // end Pythia8_InputParser_H