Skip to content

Commit 4d8386e

Browse files
committed
Simplify argument_parser; define arguments in partdiff.cpp
1 parent 8b0a96c commit 4d8386e

4 files changed

Lines changed: 161 additions & 173 deletions

File tree

argument_parser.cpp

Lines changed: 25 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -13,159 +13,45 @@ namespace partdiff {
1313
return static_cast<U>(v);
1414
}
1515

16-
static constexpr bounds_t<uint64_t> num_bounds{1, 1024};
17-
static constexpr bounds_t<calculation_method> method_bounds{calculation_method::gauss_seidel,
18-
calculation_method::jacobi};
19-
static constexpr bounds_t<uint64_t> lines_bounds{0, 10240};
20-
static constexpr bounds_t<perturbation_function> func_bounds{perturbation_function::f0,
21-
perturbation_function::fpisin};
22-
static constexpr bounds_t<termination_condition> term_bounds{termination_condition::accuracy,
23-
termination_condition::iterations};
24-
static constexpr bounds_t<uint64_t> iteration_bounds{1, 200000};
25-
static constexpr bounds_t<double> accuracy_bounds{1e-20, 1e-4};
26-
27-
argument_parser::argument_parser(const int argc, char const *argv[])
28-
: app_name(argv[0]),
29-
args(argv + 1, argv + argc) {
30-
this->fill_argument_descriptions();
31-
this->ask_params();
32-
}
33-
34-
calculation_options argument_parser::get_options() {
35-
return this->options;
36-
}
37-
38-
argument_parser::argument_description argument_parser::get_description(std::size_t index) const {
39-
return this->argument_descriptions[index];
40-
}
41-
42-
argument_parser::argument_description argument_parser::get_description(argument_index index) const {
43-
return this->get_description(to_underlying(index));
44-
}
16+
argument_parser::argument_parser(const std::optional<std::string> app_name, const std::optional<std::string> epilog)
17+
: app_name(app_name),
18+
epilog(epilog) {}
4519

4620
void argument_parser::usage() const {
4721
const auto get_name = [](const std::string &input) { return std::format(" - {:11}", input + ":"); };
48-
49-
std::print("Usage: {}", this->app_name);
50-
for (std::size_t i = 0; i <= to_underlying(argument_index::term_dummy); i++) {
51-
std::print(" [{}]", get_description(i).name);
22+
const std::size_t num_args = this->argument_descriptions.size();
23+
std::print("Usage: {}", this->app_name.value_or("<app>"));
24+
for (std::size_t i = 0; i < num_args; i++) {
25+
std::print(" [{}]", argument_descriptions[i].name);
5226
}
5327
std::println("");
5428
std::println("");
55-
for (std::size_t i = 0; i <= to_underlying(argument_index::term_dummy); i++) {
56-
const std::string description = this->get_description(i).description.value_or("<invalid>");
57-
std::println("{}{}", get_name(this->get_description(i).name), description);
58-
}
59-
std::println("Example: {} 1 2 100 1 2 100", app_name);
60-
}
61-
62-
void argument_parser::ask_params() {
63-
if (this->args.size() < 6) {
64-
usage();
65-
exit(EXIT_SUCCESS);
29+
for (std::size_t i = 0; i < num_args; i++) {
30+
const std::string description = this->argument_descriptions[i].description.value_or("<invalid>");
31+
std::println("{}{}", get_name(this->argument_descriptions[i].name), description);
6632
}
67-
for (std::size_t i = 0; i <= to_underlying(argument_index::term_dummy); i++) {
68-
parse_param(i, args[i]);
33+
if (epilog.has_value()) {
34+
std::println("");
35+
std::println("{}", epilog.value());
6936
}
70-
if (this->options.termination == termination_condition::accuracy) {
71-
parse_param(argument_index::term_accuracy, options.acc_iter);
72-
this->options.term_iteration = iteration_bounds.upper;
73-
} else {
74-
parse_param(argument_index::term_iteration, options.acc_iter);
75-
this->options.term_accuracy = 0.0;
76-
}
77-
}
78-
79-
void argument_parser::parse_param(argument_index index, std::string &input) {
80-
this->parse_param(to_underlying(index), input);
8137
}
8238

83-
void argument_parser::parse_param(std::size_t index, std::string &input) {
84-
if (!this->get_description(index).read_from_string(input)) {
85-
this->usage();
86-
exit(EXIT_FAILURE);
39+
bool argument_parser::parse_args(const std::vector<std::string> args) {
40+
const std::size_t num_args_expected = this->argument_descriptions.size();
41+
const std::size_t num_args_given = args.size();
42+
if (num_args_given < num_args_expected) {
43+
return false;
8744
}
88-
}
89-
90-
void argument_parser::fill_argument_descriptions() {
91-
92-
constexpr int indent_width = 17;
93-
const std::string indent = std::format("{:{}s}", "", indent_width);
94-
95-
auto display_enum = [indent]<typename T>(bounds_t<T> bounds) -> std::string {
96-
std::string result = "";
97-
auto lower = to_underlying(bounds.lower);
98-
auto upper = to_underlying(bounds.upper);
99-
for (auto i = lower; i <= upper; i++) {
100-
if (i != lower) {
101-
result += "\n";
102-
}
103-
result += std::format("{0}{1:d}: {1:s}", indent, T(i));
45+
for (std::size_t i = 0; i < num_args_expected; i++) {
46+
if (!parse_arg(i, args[i])) {
47+
return false;
10448
}
105-
return result;
106-
};
107-
108-
auto &number = this->options.number;
109-
this->add_argument("num", number, std::make_optional(num_bounds),
110-
std::format("number of threads ({:d})", num_bounds));
111-
112-
auto &method = this->options.method;
113-
this->add_argument("method", method, std::make_optional(method_bounds),
114-
std::format("calculation method ({:d})\n{}", method_bounds, display_enum(method_bounds)));
115-
116-
auto &interlines = this->options.interlines;
117-
this->add_argument("lines", interlines, std::make_optional(lines_bounds),
118-
std::format("number of interlines ({1:d})\n"
119-
"{0}matrixsize = (interlines * 8) + 9",
120-
indent, lines_bounds));
121-
122-
auto &pert_func = this->options.pert_func;
123-
this->add_argument("func", pert_func, std::make_optional(func_bounds),
124-
std::format("perturbation function ({:d})\n{}", func_bounds, display_enum(func_bounds)));
125-
126-
auto &termination = this->options.termination;
127-
this->add_argument("term", termination, std::make_optional(term_bounds),
128-
std::format("termination condition ({:d})\n{}", term_bounds, display_enum(term_bounds)));
129-
130-
auto &acc_iter = this->options.acc_iter;
131-
this->add_argument("acc/iter", acc_iter, std::optional<bounds_t<std::string>>{std::nullopt},
132-
std::format("depending on term:\n"
133-
"{0}accuracy: {1:.0e}\n"
134-
"{0}iterations: {2:d}\n",
135-
indent, accuracy_bounds, iteration_bounds));
136-
137-
auto &term_accuracy = this->options.term_accuracy;
138-
this->add_argument("acc", term_accuracy, std::make_optional(accuracy_bounds), std::nullopt);
139-
140-
auto &term_iteration = this->options.term_iteration;
141-
this->add_argument("iter", term_iteration, std::make_optional(iteration_bounds), std::nullopt);
49+
}
50+
return true;
14251
}
14352

144-
template <class T>
145-
void argument_parser::add_argument(std::string name, T &target, std::optional<bounds_t<T>> bounds,
146-
std::optional<std::string> description) {
147-
argument_description arg_desc;
148-
arg_desc.name = name;
149-
arg_desc.target = std::reference_wrapper<T>(target);
150-
arg_desc.read_from_string = [target_ref_any = arg_desc.target, bounds](const std::string &input) {
151-
auto &target_ref = std::any_cast<std::reference_wrapper<T>>(target_ref_any).get();
152-
bool valid_input = false;
153-
std::istringstream iss(input);
154-
if constexpr (std::is_enum_v<T>) {
155-
std::underlying_type_t<T> temp;
156-
valid_input = static_cast<bool>(iss >> temp);
157-
target_ref = static_cast<T>(temp);
158-
} else {
159-
valid_input = static_cast<bool>(iss >> target_ref);
160-
}
161-
if (bounds.has_value()) {
162-
valid_input &= bounds.value().contains(target_ref);
163-
}
164-
165-
return valid_input;
166-
};
167-
arg_desc.description = description;
168-
this->argument_descriptions.push_back(arg_desc);
53+
bool argument_parser::parse_arg(const std::size_t index, const std::string &input) {
54+
return this->argument_descriptions[index].read_from_string(input);
16955
}
17056

17157
} // namespace partdiff

argument_parser.hpp

Lines changed: 36 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,13 @@ namespace partdiff {
4343

4444
class argument_parser {
4545
public:
46-
argument_parser(const int argc, char const *argv[]);
47-
calculation_options get_options();
46+
argument_parser(const std::optional<std::string> app_name, const std::optional<std::string> epilog);
47+
bool parse_args(const std::vector<std::string> args);
48+
bool parse_arg(const std::size_t index, const std::string &input);
49+
void usage() const;
50+
template <class T>
51+
void add_arg(std::string name, T &target, std::optional<bounds_t<T>> bounds,
52+
std::optional<std::string> description);
4853

4954
private:
5055
struct argument_description {
@@ -54,33 +59,36 @@ namespace partdiff {
5459
std::function<bool(const std::string &input)> read_from_string = [](auto) { return false; };
5560
};
5661

57-
enum class argument_index : std::size_t {
58-
number = 0,
59-
method = 1,
60-
interlines = 2,
61-
pert_func = 3,
62-
termination = 4,
63-
term_dummy = 5,
64-
term_accuracy = 6,
65-
term_iteration = 7
66-
};
67-
68-
calculation_options options;
69-
std::string app_name;
70-
std::vector<std::string> args;
62+
const std::optional<std::string> app_name;
63+
const std::optional<std::string> epilog;
7164
std::vector<argument_description> argument_descriptions;
72-
argument_description get_description(std::size_t index) const;
73-
argument_description get_description(argument_index index) const;
74-
void usage() const;
75-
void ask_params();
76-
void parse_param(std::size_t index, std::string &input);
77-
void parse_param(argument_index index, std::string &input);
78-
void ask_param(std::size_t index);
79-
void ask_param(argument_index index);
80-
void fill_argument_descriptions();
81-
template <class T>
82-
void add_argument(std::string name, T &target, std::optional<bounds_t<T>> bounds,
83-
std::optional<std::string> description);
8465
};
8566

67+
template <class T>
68+
void argument_parser::add_arg(std::string name, T &target, std::optional<bounds_t<T>> bounds,
69+
std::optional<std::string> description) {
70+
argument_description arg_desc;
71+
arg_desc.name = name;
72+
arg_desc.target = std::reference_wrapper<T>(target);
73+
arg_desc.read_from_string = [target_ref_any = arg_desc.target, bounds](const std::string &input) {
74+
auto &target_ref = std::any_cast<std::reference_wrapper<T>>(target_ref_any).get();
75+
bool valid_input = false;
76+
std::istringstream iss(input);
77+
if constexpr (std::is_enum_v<T>) {
78+
std::underlying_type_t<T> temp;
79+
valid_input = static_cast<bool>(iss >> temp);
80+
target_ref = static_cast<T>(temp);
81+
} else {
82+
valid_input = static_cast<bool>(iss >> target_ref);
83+
}
84+
if (bounds.has_value()) {
85+
valid_input &= bounds.value().contains(target_ref);
86+
}
87+
88+
return valid_input;
89+
};
90+
arg_desc.description = description;
91+
this->argument_descriptions.push_back(arg_desc);
92+
}
93+
8694
} // namespace partdiff

calculation_options.hpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ namespace partdiff {
1111
calculation_method method;
1212
perturbation_function pert_func;
1313
termination_condition termination;
14-
std::string acc_iter;
1514
uint64_t term_iteration;
1615
double term_accuracy;
1716
};

0 commit comments

Comments
 (0)