diff --git a/cmdopt.cpp b/cmdopt.cpp index b1d87082..04dc5246 100644 --- a/cmdopt.cpp +++ b/cmdopt.cpp @@ -247,31 +247,32 @@ bytes::execute (const char *restrict str) /////////////////////////////////////////////////////////////////////////////// int -parser::scan (int argc, const char *const *argv) +parser::scan (int argc, char const *const *argv) { - CHECK_GE (argc, 0); - CHECK (argv); + CHECK_GT (argc, 0); + CHECK (argv); for (auto &j: m_options) - std::get> (j)->start (); + j.handler->start (); // start iterating after our program's name int i = 1; while (i < argc) { - auto len = strlen (argv[i]); + auto arg = argv[i]; + auto len = strlen (arg); // bail if there's no potential for an option - if (len < 2 || argv[i][0] != '-') + if (len < 2 || arg[0] != '-') break; // stop processing named options on '--' - if (len == 2 && argv[i][1] == '-') { + if (len == 2 && arg[1] == '-') { ++i; break; } // parse longopt - auto inc = argv[i][1] == '-' + auto inc = arg[1] == '-' ? parse_long (i, argc, argv) : parse_short (i, argc, argv); @@ -289,7 +290,7 @@ parser::scan (int argc, const char *const *argv) // allow arguments to check if they've been successfully handled for (auto &j: m_options) - std::get> (j)->finish (); + j.handler->finish (); return i; } @@ -316,14 +317,7 @@ parser::parse_long (int pos, int argc, const char *const *argv) if (key == "help") print_help (argc, argv); - // find the handler - auto handle_pos = std::find_if (m_long.begin (), - m_long.end (), - [&] (auto i) { return std::get (i) == key; }); - if (handle_pos == m_long.end ()) - throw invalid_key (key); - - auto &handler = std::get (*handle_pos); + auto &handler = m_long.at (key).get (); // maybe grab a value from the next atom and dispatch if (!eq) { @@ -363,12 +357,7 @@ parser::parse_short (int pos, int argc, const char *const *argv) if (letter == 'h') print_help (argc, argv); - auto hpos = std::find_if (m_short.begin (), - m_short.end (), - [letter] (auto j) { return std::get (j) == letter; }); - if (hpos == m_short.end ()) - throw invalid_key (std::string (1, letter)); - std::get (*hpos).execute (); + m_short.at(letter).get ().execute (); } return 1; @@ -376,13 +365,7 @@ parser::parse_short (int pos, int argc, const char *const *argv) // we have a value following auto letter = argv[pos][1]; - auto hpos = std::find_if (m_short.begin (), - m_short.end (), - [letter] (auto i) { return std::get (i) == letter; }); - if (hpos == m_short.end ()) - throw invalid_key (std::string (1, letter)); - std::get (*hpos).execute (argv[pos+1]); - + m_short.at (letter).get ().execute (argv[pos + 1]); return 2; } @@ -406,9 +389,13 @@ parser::print_help (const int argc, m_long.end (), [] (const auto &a, const auto &b) { - return std::get (a).size () < std::get (b).size (); + auto const &[a_key,a_obj] = a; + auto const &[b_key,b_obj] = b; + + return a_key.size () < b_key.size (); }); - auto longwidth = std::get (*largestwidth).size (); + + auto longwidth = largestwidth->first.size (); // find the longest example text auto largestexample = std::max_element ( @@ -416,13 +403,10 @@ parser::print_help (const int argc, m_options.cend (), [] (const auto &a, const auto &b) { - const auto &example_a = std::get> (a)->example (); - const auto &example_b = std::get> (b)->example (); - - return example_a.size () > example_b.size (); + return a.handler->example ().size () > b.handler->example ().size (); }); - auto longexample = std::get> (*largestexample)->example ().size (); + auto longexample = largestexample->handler->example ().size (); // field width requires an alignment. we don't care about preserving // state as we're about to bail anyway @@ -431,39 +415,33 @@ parser::print_help (const int argc, // print all the option info std::cout << "usage: " << argv[0] << '\n'; - for (auto &o: m_options) { - auto ptr = std::get> (o).get (); - + for (auto &opt: m_options) { auto s = std::find_if ( std::cbegin (m_short), std::cend (m_short), - [ptr] (auto j) { - return &std::get (j) == ptr; - } + [&] (auto j) { return &j.second.get () == opt.handler.get (); } ); auto l = std::find_if ( std::cbegin (m_long), std::cend (m_long), - [ptr] (auto j) { - return &std::get (j) == ptr; - } + [&] (auto j) { return &j.second.get () == opt.handler.get (); } ); std::cout << '\t'; if (s != std::cend (m_short)) - std::cout << '-' << std::get (*s) << '\t'; + std::cout << '-' << s->first << '\t'; else std::cout << '\t'; std::cout << std::setw (util::cast::lossless (longwidth)); if (l != std::cend (m_long)) - std::cout << std::get (*l) << '\t'; + std::cout << l->first << '\t'; else std::cout << ' ' << '\t'; - std::cout << std::setw (util::cast::lossless (longexample)) << ptr->example () << '\t' - << std::setw (0) << std::get (o) + std::cout << std::setw (util::cast::lossless (longexample)) << opt.handler->example () << '\t' + << std::setw (0) << opt.description << '\n'; } diff --git a/cmdopt.hpp b/cmdopt.hpp index ba3abe8b..5283d095 100644 --- a/cmdopt.hpp +++ b/cmdopt.hpp @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -290,10 +291,10 @@ namespace util::cmdopt { auto handler = std::make_unique (std::forward (args)...); T& ref = *handler; - m_short.emplace_back (shortname, ref); - m_long .emplace_back (std::move (longname), ref); + m_short.insert({ shortname, ref }); + m_long.insert({ std::move (longname), ref }); - m_options.emplace_back (std::move (description), std::move (handler)); + m_options.push_back ({ std::move (description), std::move (handler) }); return ref; } @@ -305,7 +306,7 @@ namespace util::cmdopt { auto handler = std::make_unique (std::forward (args)...); auto &ref = *handler; m_positional.push_back (ref); - m_options.emplace_back (std::move (description), std::move (handler)); + m_options.push_back ({ std::move (description), std::move (handler) }); return ref; } @@ -317,19 +318,17 @@ namespace util::cmdopt { void print_help [[noreturn]] (int argc, const char *const *argv) const; - using short_t = std::tuple; - using long_t = std::tuple; + std::map> m_short; + std::map> m_long; - std::vector m_short; - std::vector m_long; std::vector> m_positional; - std::vector< - std::tuple< - std::string, // description - std::unique_ptr - > - > m_options; + struct entry { + std::string description; + std::unique_ptr handler; + }; + + std::vector m_options; }; }