arguments.h 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. #pragma once
  2. #include <map>
  3. #include <set>
  4. #include <string>
  5. #include <vector>
  6. namespace program {
  7. template <typename Impl> class Arguments {
  8. private:
  9. using option_id = std::string;
  10. struct Argument;
  11. struct Flag;
  12. struct Option;
  13. template <typename, typename> struct WithDefault;
  14. public:
  15. Arguments() = default;
  16. Arguments(int argc, char const * const * const argv);
  17. std::vector<std::string> args() const {
  18. return {arguments.begin() + argument_names.size(), arguments.end()};
  19. }
  20. protected:
  21. auto argument(size_t index, std::string const & name,
  22. std::string const & description = "");
  23. auto flag(std::string const & name, std::string const & description = "");
  24. auto flag(std::string const & name, char abbrev,
  25. std::string const & description = "");
  26. auto option(std::string const & name, std::string const & description = "");
  27. auto option(std::string const & name, char abbrev,
  28. std::string const & description = "");
  29. private:
  30. void usage() const;
  31. void add_options(std::string const & name, char abbrev,
  32. std::string const & description,
  33. std::vector<std::string> aliases = {});
  34. option_id id(std::string const & arg) const;
  35. option_id id(char arg) const { return id({'-', arg}); }
  36. bool is_option(std::string const & arg) const;
  37. bool is_option(char arg) const { return is_option({'-', arg}); }
  38. bool is_flag(std::string const & arg) const;
  39. bool is_flag(char arg) const { return is_flag({'-', arg}); }
  40. private:
  41. // Metadata variables
  42. bool primed_{false};
  43. std::map<option_id, std::string> argument_descriptions;
  44. std::map<size_t, option_id> argument_names;
  45. std::map<option_id, std::string> option_descriptions;
  46. std::map<std::string, option_id> option_names;
  47. std::set<option_id> flag_names;
  48. // Data/Output variables
  49. std::string program;
  50. constexpr static size_t const no_optional_args{~0ul};
  51. size_t optional_from{no_optional_args};
  52. std::vector<std::string> arguments;
  53. std::map<std::string, std::vector<std::string>> options;
  54. std::map<std::string, int> flags;
  55. };
  56. template <typename Impl> struct Arguments<Impl>::Argument {
  57. Arguments<Impl> * self;
  58. size_t index;
  59. bool is_optional;
  60. std::string name;
  61. std::string description;
  62. template <typename T> auto operator=(T && value);
  63. template <typename T> operator T() const;
  64. bool primed() const;
  65. explicit operator bool() const;
  66. };
  67. template <typename Impl> struct Arguments<Impl>::Flag {
  68. Arguments<Impl> * self;
  69. std::string name;
  70. char abbrev;
  71. std::string description;
  72. bool default_value;
  73. auto operator=(bool && value);
  74. operator bool() const;
  75. template <typename T> operator T() const;
  76. bool primed(bool inv) const;
  77. };
  78. template <typename Impl> struct Arguments<Impl>::Option {
  79. Arguments<Impl> * self;
  80. std::string name;
  81. char abbrev;
  82. std::string description;
  83. template <typename T> auto operator=(T && value);
  84. template <typename T> operator T() const;
  85. bool primed() const;
  86. explicit operator bool() const;
  87. };
  88. template <typename Impl>
  89. template <typename B, typename V>
  90. struct Arguments<Impl>::WithDefault {
  91. B impl;
  92. V default_value;
  93. template <typename T> operator T() const { return impl ?: T(default_value); }
  94. };
  95. }
  96. #include "arguments_impl.hpp"
  97. #define TYPED_MAIN(tname) \
  98. int typed_main(tname const & args); \
  99. int main(int argc, char const * const * const argv) try { \
  100. return typed_main(tname(argc, argv)); \
  101. } catch (program::ProgramArgumentsError const & pae) { \
  102. std::cerr << "Error in program argument handling: " << pae.what() << "\n"; \
  103. } \
  104. int typed_main(tname const & args)