1
0
mirror of https://github.com/CLIUtils/CLI11.git synced 2025-05-03 14:03:52 +00:00

get_subcommand_no_throw (#1016)

get_subcommand when used for parsing config files, was throwing and
catching as part of control flow and expected operation, this resulting
in a performance hit in select cases. A get_subcommand_no_throw was
added to resolve this issue.

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
Philip Top 2024-03-12 09:45:17 -07:00 committed by GitHub
parent c04c9b2252
commit 6cd171ad3f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 19 additions and 12 deletions

View File

@ -733,6 +733,10 @@ class App {
/// Check to see if a subcommand is part of this command (text version) /// Check to see if a subcommand is part of this command (text version)
CLI11_NODISCARD App *get_subcommand(std::string subcom) const; CLI11_NODISCARD App *get_subcommand(std::string subcom) const;
/// Get a subcommand by name (noexcept non-const version)
/// returns null if subcommand doesn't exist
CLI11_NODISCARD App *get_subcommand_no_throw(std::string subcom) const noexcept;
/// Get a pointer to subcommand by index /// Get a pointer to subcommand by index
CLI11_NODISCARD App *get_subcommand(int index = 0) const; CLI11_NODISCARD App *get_subcommand(int index = 0) const;
@ -907,8 +911,9 @@ class App {
} }
/// Check with name instead of pointer to see if subcommand was selected /// Check with name instead of pointer to see if subcommand was selected
CLI11_NODISCARD bool got_subcommand(std::string subcommand_name) const { CLI11_NODISCARD bool got_subcommand(std::string subcommand_name) const noexcept {
return get_subcommand(subcommand_name)->parsed_ > 0; App *sub = get_subcommand_no_throw(subcommand_name);
return (sub != nullptr) ? (sub->parsed_ > 0) : false;
} }
/// Sets excluded options for the subcommand /// Sets excluded options for the subcommand
@ -1038,7 +1043,7 @@ class App {
std::vector<Option *> get_options(const std::function<bool(Option *)> filter = {}); std::vector<Option *> get_options(const std::function<bool(Option *)> filter = {});
/// Get an option by name (noexcept non-const version) /// Get an option by name (noexcept non-const version)
Option *get_option_no_throw(std::string option_name) noexcept; CLI11_NODISCARD Option *get_option_no_throw(std::string option_name) noexcept;
/// Get an option by name (noexcept const version) /// Get an option by name (noexcept const version)
CLI11_NODISCARD const Option *get_option_no_throw(std::string option_name) const noexcept; CLI11_NODISCARD const Option *get_option_no_throw(std::string option_name) const noexcept;

View File

@ -457,6 +457,10 @@ CLI11_NODISCARD CLI11_INLINE App *App::get_subcommand(std::string subcom) const
return subc; return subc;
} }
CLI11_NODISCARD CLI11_INLINE App *App::get_subcommand_no_throw(std::string subcom) const noexcept {
return _find_subcommand(subcom, false, false);
}
CLI11_NODISCARD CLI11_INLINE App *App::get_subcommand(int index) const { CLI11_NODISCARD CLI11_INLINE App *App::get_subcommand(int index) const {
if(index >= 0) { if(index >= 0) {
auto uindex = static_cast<unsigned>(index); auto uindex = static_cast<unsigned>(index);
@ -796,7 +800,7 @@ CLI11_INLINE std::vector<Option *> App::get_options(const std::function<bool(Opt
return options; return options;
} }
CLI11_INLINE Option *App::get_option_no_throw(std::string option_name) noexcept { CLI11_NODISCARD CLI11_INLINE Option *App::get_option_no_throw(std::string option_name) noexcept {
for(Option_p &opt : options_) { for(Option_p &opt : options_) {
if(opt->check_name(option_name)) { if(opt->check_name(option_name)) {
return opt.get(); return opt.get();
@ -1441,12 +1445,8 @@ CLI11_INLINE void App::_parse_config(const std::vector<ConfigItem> &args) {
CLI11_INLINE bool App::_parse_single_config(const ConfigItem &item, std::size_t level) { CLI11_INLINE bool App::_parse_single_config(const ConfigItem &item, std::size_t level) {
if(level < item.parents.size()) { if(level < item.parents.size()) {
try { auto *subcom = get_subcommand_no_throw(item.parents.at(level));
auto *subcom = get_subcommand(item.parents.at(level)); return (subcom != nullptr) ? subcom->_parse_single_config(item, level + 1) : false;
return subcom->_parse_single_config(item, level + 1);
} catch(const OptionNotFound &) {
return false;
}
} }
// check for section open // check for section open
if(item.name == "++") { if(item.name == "++") {

View File

@ -16,8 +16,10 @@ TEST_CASE_METHOD(TApp, "BasicSubcommands", "[subcom]") {
CHECK(app.get_subcommand(sub1) == sub1); CHECK(app.get_subcommand(sub1) == sub1);
CHECK(app.get_subcommand("sub1") == sub1); CHECK(app.get_subcommand("sub1") == sub1);
CHECK(app.get_subcommand_no_throw("sub1") == sub1);
CHECK_THROWS_AS(app.get_subcommand("sub3"), CLI::OptionNotFound); CHECK_THROWS_AS(app.get_subcommand("sub3"), CLI::OptionNotFound);
CHECK_NOTHROW(app.get_subcommand_no_throw("sub3"));
CHECK(app.get_subcommand_no_throw("sub3") == nullptr);
run(); run();
CHECK(app.get_subcommands().empty()); CHECK(app.get_subcommands().empty());
@ -90,7 +92,7 @@ TEST_CASE_METHOD(TApp, "MultiSubFallthrough", "[subcom]") {
CHECK(!sub2->parsed()); CHECK(!sub2->parsed());
CHECK(0u == sub2->count()); CHECK(0u == sub2->count());
CHECK_THROWS_AS(app.got_subcommand("sub3"), CLI::OptionNotFound); CHECK(!app.got_subcommand("sub3"));
} }
TEST_CASE_METHOD(TApp, "CrazyNameSubcommand", "[subcom]") { TEST_CASE_METHOD(TApp, "CrazyNameSubcommand", "[subcom]") {