@@ -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
0 commit comments