24 #ifndef ARM_COMPUTE_UTILS_COMMANDLINEPARSER
25 #define ARM_COMPUTE_UTILS_COMMANDLINEPARSER
57 template <
typename T,
typename... As>
66 template <
typename T,
typename... As>
74 void parse(
int argc,
char **argv);
90 void print_help(
const std::string &program_name)
const;
93 using OptionsMap = std::map<std::string, std::unique_ptr<Option>>;
94 using PositionalOptionsVector = std::vector<std::unique_ptr<Option>>;
96 OptionsMap _options{};
97 PositionalOptionsVector _positional_options{};
98 std::vector<std::string> _unknown_options{};
99 std::vector<std::string> _invalid_options{};
102 template <
typename T,
typename... As>
105 auto result = _options.emplace(
name, std::make_unique<T>(
name, std::forward<As>(
args)...));
106 return static_cast<T *
>(result.first->second.get());
109 template <
typename T,
typename... As>
112 _positional_options.emplace_back(std::make_unique<T>(std::forward<As>(
args)...));
113 return static_cast<T *
>(_positional_options.back().get());
118 const std::regex option_regex{
"--((?:no-)?)([^=]+)(?:=(.*))?"};
120 const auto set_option = [&](
const std::string &option,
const std::string &
name,
const std::string &value)
122 if (_options.find(
name) == _options.end())
124 _unknown_options.push_back(option);
128 const bool success = _options[
name]->parse(value);
132 _invalid_options.push_back(option);
136 unsigned int positional_index = 0;
138 for (
int i = 1; i < argc; ++i)
140 std::string mixed_case_opt{argv[i]};
141 int equal_sign = mixed_case_opt.find(
'=');
142 int pos = (equal_sign == -1) ? strlen(argv[i]) : equal_sign;
144 const std::string option =
146 std::smatch option_matches;
148 if (std::regex_match(option, option_matches, option_regex))
151 if (option_matches.str(3).empty())
153 set_option(option, option_matches.str(2), option_matches.str(1).empty() ?
"true" :
"false");
158 if (!option_matches.str(1).empty())
160 _invalid_options.emplace_back(option);
164 set_option(option, option_matches.str(2), option_matches.str(3));
170 if (positional_index >= _positional_options.size())
172 _invalid_options.push_back(mixed_case_opt);
176 _positional_options[positional_index]->parse(mixed_case_opt);
187 for (
const auto &option : _options)
189 if (option.second->is_required() && !option.second->is_set())
192 std::cerr <<
"ERROR: Option '" << option.second->name() <<
"' is required but not given!\n";
196 for (
const auto &option : _positional_options)
198 if (option->is_required() && !option->is_set())
201 std::cerr <<
"ERROR: Option '" << option->name() <<
"' is required but not given!\n";
205 for (
const auto &option : _unknown_options)
207 std::cerr <<
"WARNING: Skipping unknown option '" << option <<
"'!\n";
210 for (
const auto &option : _invalid_options)
212 std::cerr <<
"WARNING: Skipping invalid option '" << option <<
"'!\n";
220 std::cout <<
"usage: " << program_name <<
" \n";
222 for (
const auto &option : _options)
224 std::cout << option.second->help() <<
"\n";
227 for (
const auto &option : _positional_options)
229 std::string help_to_print;
232 const std::string help_str = option->help();
233 const size_t help_pos = help_str.find(
" - ");
234 if (help_pos != std::string::npos)
236 help_to_print = help_str.substr(help_pos);
239 std::cout << option->name() << help_to_print <<
"\n";