mutable
A Database System for Research and Fast Prototyping
Loading...
Searching...
No Matches
ArgParser.cpp
Go to the documentation of this file.
2
3#include <cstdlib>
4#include <iomanip>
5#include <limits>
8#include <string>
9#include <string_view>
10
11
12using namespace m;
13
14
15namespace {
16
18void check_next_arg(const char **&argv)
19{
20 if (not *++argv) {
21 std::cerr << "missing argument" << std::endl; //M_LCOV_EXCL_LINE
22 std::exit(EXIT_FAILURE); //M_LCOV_EXCL_LINE
23 }
24}
25
27template<typename T>
28requires integral<T>
29void help_parse(const char **&argv, const std::function<void(T)> &callback)
30{
31 check_next_arg(argv);
32
33 T i;
34 try {
35 /*----- Signed integer types. -----*/
36 if constexpr (std::same_as<T, int>)
37 i = std::stoi(*argv);
38 if constexpr (std::same_as<T, long>)
39 i = std::stol(*argv);
40 if constexpr (std::same_as<T, long long>)
41 i = std::stoll(*argv);
42 /*----- Unsigned integer types. -----*/
43 if constexpr (std::same_as<T, unsigned>) {
44 const unsigned long v = std::stoul(*argv);
45 if (v > std::numeric_limits<unsigned>::max())
46 throw std::out_of_range("input exceeds range of type unsigned int"); //M_LCOV_EXCL_LINE
47 i = unsigned(v);
48 }
49 if constexpr (std::same_as<T, unsigned long>)
50 i = std::stoul(*argv);
51 if constexpr (std::same_as<T, unsigned long long>)
52 i = std::stoull(*argv);
53 }
54
56 catch(std::invalid_argument ex) {
57 std::cerr << "not a valid integer" << std::endl;
58 std::exit(EXIT_FAILURE);
59 } catch (std::out_of_range ex) {
60 std::cerr << "value out of range" << std::endl;
61 std::exit(EXIT_FAILURE);
62 }
64
65 callback(i);
66}
67
69template<typename T>
70requires std::floating_point<T>
71void help_parse(const char **&argv, const std::function<void(T)> &callback)
72{
73 check_next_arg(argv);
74
75 T fp;
76 try {
77 if constexpr (std::same_as<T, float>)
78 fp = std::stof(*argv);
79 if constexpr (std::same_as<T, double>)
80 fp = std::stod(*argv);
81 if constexpr (std::same_as<T, long double>)
82 fp = std::stold(*argv);
83 }
84
86 catch (std::invalid_argument) {
87 std::cerr << "not a valid floating-point number" << std::endl;
88 std::exit(EXIT_FAILURE);
89 } catch (std::out_of_range) {
90 std::cerr << "value out of range" << std::endl;
91 std::exit(EXIT_FAILURE);
92 }
94
95 callback(fp);
96}
97
98}
99
100#define PARSE(TYPE) \
101template<> void ArgParser::OptionImpl<TYPE>::parse(const char **&argv) const { help_parse<TYPE>(argv, callback); }
102
103/*----- Boolean ------------------------------------------------------------------------------------------------------*/
104template<> void ArgParser::OptionImpl<bool>::parse(const char **&) const { callback(true); }
105
106/*----- Integral -----------------------------------------------------------------------------------------------------*/
107PARSE(int);
108PARSE(long);
109PARSE(long long);
110PARSE(unsigned);
111PARSE(unsigned long);
112PARSE(unsigned long long);
113
114/*----- Floating point -----------------------------------------------------------------------------------------------*/
115PARSE(float);
116PARSE(double);
117PARSE(long double);
118
119/*----- String -------------------------------------------------------------------------------------------------------*/
120template<>
121void ArgParser::OptionImpl<const char*>::parse(const char **&argv) const
122{
123 check_next_arg(argv);
124 callback(*argv);
125}
126
127/*----- List of String -----------------------------------------------------------------------------------------------*/
128template<>
129void ArgParser::OptionImpl<std::vector<std::string_view>>::parse(const char **&argv) const
130{
131 check_next_arg(argv);
132
133 std::vector<std::string_view> args;
134 std::string_view sv(*argv);
135
136 if (sv.empty()) {
137 callback(std::move(args));
138 return;
139 }
140
141 std::string_view::size_type begin = 0;
142 for (;;) {
143 auto end = sv.find(',', begin);
144 args.emplace_back(sv.substr(begin, end - begin));
145 if (end == std::string_view::npos)
146 break;
147 begin = end + 1; // skip comma ','
148 }
149
150 callback(std::move(args));
151}
152
153#undef PARSE
154
155//----------------------------------------------------------------------------------------------------------------------
156
158void ArgParser::print_args(std::ostream &out) const
159{
160 auto print = [this, &out](const char *Short, const char *Long, const char *Descr) {
161 out << " "
162 << Short << std::setw(short_len_ - strlen(Short)) << ""
163 << " "
164 << Long << std::setw(long_len_ - strlen(Long)) << ""
165 << " - "
166 << Descr
167 << '\n';
168 };
169
170 out << "General:\n";
171 for (auto &opt : general_options_)
172 print(opt->short_name.has_value() ? *opt->short_name : "",
173 opt->long_name.has_value() ? *opt->long_name : "",
174 opt->description);
175
176 for (auto &grp : grouped_options_) {
177 out << grp.first << ":\n";
178 for (auto &opt : grp.second)
179 print(opt->short_name.has_value() ? *opt->short_name : "",
180 opt->long_name.has_value() ? *opt->long_name : "",
181 opt->description);
182 }
183}
185
186void ArgParser::parse_args(int, const char **argv) {
187 for (++argv; *argv; ++argv) {
188 if (streq(*argv, "--"))
189 goto positional;
190 auto it = key_map_.find(pool_(*argv));
191 if (it != key_map_.end()) {
192 it->second.get().parse(argv); // option
193 } else {
194 if (strneq(*argv, "--", 2))
195 std::cerr << "warning: ignore unknown option " << *argv << std::endl; //M_LCOV_EXCL_LINE
196 else
197 args_.emplace_back(*argv); // positional argument
198 }
199 }
200 return;
201
202 /* Read all following arguments as positional arguments. */
203positional:
204 for (++argv; *argv; ++argv)
205 args_.emplace_back(*argv);
206}
#define PARSE(TYPE)
Definition: ArgParser.cpp:100
struct @5 args
std::unordered_map< PooledString, std::reference_wrapper< const Option > > key_map_
‍maps the option name to the option object
Definition: ArgParser.hpp:65
std::size_t short_len_
‍the deducted maximum length of all short options
Definition: ArgParser.hpp:67
void print_args() const
Prints a list of all options to std::cout.
Definition: ArgParser.hpp:126
StringPool pool_
‍pool of internalized strings
Definition: ArgParser.hpp:55
void parse_args(int argc, const char **argv)
Parses the arguments from argv.
Definition: ArgParser.cpp:186
std::vector< const char * > args_
‍positional arguments
Definition: ArgParser.hpp:63
options_t general_options_
‍general options
Definition: ArgParser.hpp:59
std::size_t long_len_
‍the deducted maximum length of all long options
Definition: ArgParser.hpp:69
std::unordered_map< PooledString, options_t > grouped_options_
‍group options
Definition: ArgParser.hpp:61
‍mutable namespace
Definition: Backend.hpp:10
bool streq(const char *first, const char *second)
Definition: fn.hpp:29
bool strneq(const char *first, const char *second, std::size_t n)
Definition: fn.hpp:30
T(x)
void parse(const char **&argv) const override