cmdopt: use concrete structs for data holders

Tuples are quite verbose and don't document intention.
This commit is contained in:
Danny Robson 2018-07-17 16:02:04 +10:00
parent 395b5ae557
commit 6f45f9514d
2 changed files with 41 additions and 64 deletions

View File

@ -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<std::unique_ptr<option::base>> (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<std::unique_ptr<option::base>> (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<std::string> (i) == key; });
if (handle_pos == m_long.end ())
throw invalid_key (key);
auto &handler = std::get<option::base&> (*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<char> (j) == letter; });
if (hpos == m_short.end ())
throw invalid_key (std::string (1, letter));
std::get<option::base&> (*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<char> (i) == letter; });
if (hpos == m_short.end ())
throw invalid_key (std::string (1, letter));
std::get<option::base&> (*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<std::string> (a).size () < std::get<std::string> (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<std::string> (*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<std::unique_ptr<option::base>> (a)->example ();
const auto &example_b = std::get<std::unique_ptr<option::base>> (b)->example ();
return example_a.size () > example_b.size ();
return a.handler->example ().size () > b.handler->example ().size ();
});
auto longexample = std::get<std::unique_ptr<option::base>> (*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<std::unique_ptr<option::base>> (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<option::base&> (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<option::base&> (j) == ptr;
}
[&] (auto j) { return &j.second.get () == opt.handler.get (); }
);
std::cout << '\t';
if (s != std::cend (m_short))
std::cout << '-' << std::get<char> (*s) << '\t';
std::cout << '-' << s->first << '\t';
else
std::cout << '\t';
std::cout << std::setw (util::cast::lossless<int> (longwidth));
if (l != std::cend (m_long))
std::cout << std::get<std::string> (*l) << '\t';
std::cout << l->first << '\t';
else
std::cout << ' ' << '\t';
std::cout << std::setw (util::cast::lossless<int> (longexample)) << ptr->example () << '\t'
<< std::setw (0) << std::get<std::string> (o)
std::cout << std::setw (util::cast::lossless<int> (longexample)) << opt.handler->example () << '\t'
<< std::setw (0) << opt.description
<< '\n';
}

View File

@ -27,6 +27,7 @@
#include <string>
#include <tuple>
#include <vector>
#include <map>
#include <sstream>
@ -290,10 +291,10 @@ namespace util::cmdopt {
auto handler = std::make_unique<T> (std::forward<Args> (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<T> (std::forward<Args> (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<char,option::base&>;
using long_t = std::tuple<std::string,option::base&>;
std::map<char,std::reference_wrapper<option::base>> m_short;
std::map<std::string,std::reference_wrapper<option::base>> m_long;
std::vector<short_t> m_short;
std::vector<long_t> m_long;
std::vector<std::reference_wrapper<option::base>> m_positional;
std::vector<
std::tuple<
std::string, // description
std::unique_ptr<option::base>
>
> m_options;
struct entry {
std::string description;
std::unique_ptr<option::base> handler;
};
std::vector<entry> m_options;
};
}