| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- #pragma once
- #include <map>
- #include <set>
- #include <string>
- #include <vector>
- namespace program {
- struct LongArg {
- template <size_t N> constexpr LongArg(char const (&str)[N]) : str(str) {
- static_assert(N > 1, "cannot create longargs with 0 or 1 character");
- }
- operator std::string const &() const { return str; }
- std::string str;
- };
- template <typename Impl> class Arguments {
- private:
- using option_id = std::string;
- struct Action;
- struct Argument;
- struct Flag;
- struct Option;
- template <typename, typename> struct WithDefault;
- public:
- Arguments() = default;
- Arguments(int argc, char const * const * const argv);
- std::vector<std::string> args() const {
- return {arguments.begin() + argument_names.size(), arguments.end()};
- }
- protected:
- auto action(LongArg name, std::string const &description = "");
- auto argument(size_t index, LongArg name,
- std::string const & description = "");
- std::vector<std::string> rest(LongArg name = "args") {
- rest_name_ = name;
- size_t const i = std::min(arguments.size(), argument_names.size());
- return {arguments.begin() + i, arguments.end()};
- }
- auto flag(LongArg name, std::string const & description = "");
- auto flag(LongArg name, char abbrev, std::string const & description = "");
- auto flag(char abbrev, std::string const & description = "");
- auto option(LongArg name, std::string const & description = "");
- auto option(LongArg name, char abbrev,
- std::string const & description = "");
- auto option(char abbrev, std::string const & description = "");
- private:
- void usage() const;
- void add_options(std::string const & name, char abbrev,
- std::string const & description,
- std::vector<std::string> aliases = {});
- option_id id(std::string const & arg) const;
- option_id id(char arg) const { return id({'-', arg}); }
- bool is_option(std::string const & arg) const;
- bool is_option(char arg) const { return is_option({'-', arg}); }
- bool is_flag(std::string const & arg) const;
- bool is_flag(char arg) const { return is_flag({'-', arg}); }
- private:
- friend struct ArgumentTestHelper;
- friend int main(int, char const * const *);
-
- private:
- using main_callback_t = std::function<int(Arguments const &)>;
- using make_hook_t = std::function<main_callback_t(size_t, char const * const *)>;
- // Metadata variables
- bool primed_{false};
- std::string rest_name_;
- std::map<option_id, std::string> argument_descriptions;
- std::map<size_t, option_id> argument_names;
- std::map<option_id, std::string> option_descriptions;
- std::map<std::string, option_id> option_names;
- std::set<option_id> flag_names;
- std::map<std::string, make_hook_t> actions;
- std::map<std::string, std::string> action_descriptions;
- // Data/Output variables
- std::string program;
- main_callback_t main_callback{nullptr};
- constexpr static size_t const no_optional_args{~0ul};
- size_t optional_from{no_optional_args};
- std::vector<std::string> arguments;
- std::map<std::string, std::vector<std::string>> options;
- std::map<std::string, int> flags;
- };
- template <typename Impl> struct Arguments<Impl>::Action {
- Arguments<Impl> * self;
- std::string name;
- std::string description;
- template <typename T> operator T() const;
- bool primed() const;
- explicit operator bool() const;
- };
- template <typename Impl> struct Arguments<Impl>::Argument {
- Arguments<Impl> * self;
- size_t index;
- bool is_optional;
- std::string name;
- std::string description;
- template <typename T> auto operator=(T && value);
- template <typename T> operator T() const;
- bool primed() const;
- explicit operator bool() const;
- };
- template <typename Impl> struct Arguments<Impl>::Flag {
- Arguments<Impl> * self;
- std::string name;
- char abbrev;
- std::string description;
- bool default_value;
- auto operator=(bool && value);
- operator bool() const;
- template <typename T> operator T() const;
- bool primed(bool inv) const;
- };
- template <typename Impl> struct Arguments<Impl>::Option {
- Arguments<Impl> * self;
- std::string name;
- char abbrev;
- std::string description;
- template <typename T> auto operator=(std::initializer_list<T> value);
- template <typename T> auto operator=(T && value);
- template <typename T> operator T() const;
- bool primed() const;
- explicit operator bool() const;
- };
- template <typename Impl>
- template <typename B, typename V>
- struct Arguments<Impl>::WithDefault {
- B impl;
- V default_value;
- template <typename T> operator T() const {
- if (impl) { return impl; }
- if constexpr (std::is_invocable_r<T, V>{}) {
- return T(default_value());
- } else {
- return T{default_value};
- }
- }
- };
- }
- #include "arguments_impl.hpp"
- template <typename Args, typename Action>
- int typed_main(Args const &, Action const &);
- #define TYPED_MAIN(tname) \
- int typed_main(tname const & args); \
- int main(int argc, char const * const * const argv) try { \
- tname args(argc, argv); \
- return (args.main_callback) ? args.main_callback(args) : typed_main(args); \
- } catch (program::ProgramArgumentsError const & pae) { \
- std::cerr << "Error in program argument handling: " << pae.what() << "\n"; \
- } \
- int typed_main(tname const & args)
- #define PROGRAM_DEFER(...) [this]() { return __VA_ARGS__; }
|