FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
arg_parser.hpp
1// FEAT3: Finite Element Analysis Toolbox, Version 3
2// Copyright (C) 2010 by Stefan Turek & the FEAT group
3// FEAT3 is released under the GNU General Public License version 3,
4// see the file 'copyright.txt' in the top level directory for details.
5
6#pragma once
7
8#include <kernel/runtime.hpp>
10#include <kernel/util/property_map.hpp>
11#include <kernel/util/string.hpp>
12
13#include <algorithm>
14#include <any>
15#include <deque>
16#include <functional>
17#include <iostream>
18#include <memory>
19#include <set>
20#include <sstream>
21#include <stdexcept>
22#include <utility>
23
24namespace FEAT
25{
26 // Architecture Notes. Read class documentation of ArgParser first.
27 // The core of this argument parser implementation consists of four classes
28 // - ArgParser is the actual parser
29 // - Parameter is the user-facing interface of a parameter
30 // - ParameterCore is the inner interface of a parameter used by the ArgParser
31 // - ParameterBuilder is a class implementing the builder pattern to define parameters
32 //
33 // The split into Parameter and ParameterCore is a matter of type-erasure.
34 // We want to both present a neat and well-typed interface to the user and
35 // automatically handle the parameters in the parser.
36 // But the parser can not handle the templated Parameters directly, because
37 // they form a non-homogenous collection. To solve this the Parameter class
38 // is just a thin wrapper around a type-erased ParameterCore.
39 // The parser can handle the ParameterCores, and the Parameter presents a
40 // well-typed interface.
41 //
42 // To achieve this type-erasure the ParameterCore stores its parsed values
43 // in a std::any (essentially a void* and a type tag). Any type dependent
44 // logic required by the ParameterCore (parsing and validation, for now)
45 // is handled by supplying functions that accept std::any to the ParameterCore.
46 // These functions are constructed during the parameter definition
47 // (when type information is still available), by wrapping the properly
48 // typed functions into std::any_casts.
49 //
50 // Thus the ArgParser holds a list of shared pointers to ParameterCores and has
51 // the Parameters as members. The parameters hold a shared pointer to their
52 // respective ParameterCore as well. The ArgParser then uses its list of
53 // parameter cores to match arguments to parameters during parsing.
54 //
55 // Start reading at ArgParser::parameter to see how parameters are created and defined.
56 // Start reading at ArgParser::parse to see how parsing is implemented.
57
58 namespace Intern
59 {
61 template<typename>
62 struct is_std_deque : std::false_type
63 {
64 };
65
67 template<typename T, typename A>
68 struct is_std_deque<std::deque<T, A>> : std::true_type
69 {
70 };
71
73 template<typename T>
74 constexpr bool is_std_deque_v = is_std_deque<T>::value;
75
77 template<typename T, typename = void>
78 struct has_input_operator : std::false_type
79 {
80 };
81
83 template<typename T>
84 struct has_input_operator<T, std::void_t<decltype((std::declval<std::istringstream&>() >> std::declval<T&>()))>>
85 : std::true_type
86 {
87 };
88
90 template<typename T>
91 constexpr bool can_default_parse_v = has_input_operator<T>::value;
92
94 template<typename T, typename A>
95 constexpr bool can_default_parse_v<std::deque<T, A>> = has_input_operator<T>::value;
96
98 template<typename T_>
99 static void parse_collection(std::any& any, const String& s)
100 {
101 std::deque<T_> collection;
102 for(const String& value_str : s.split_by_whitespaces())
103 {
104 T_ tmp{};
105 if(!value_str.parse(tmp))
106 {
107 throw std::invalid_argument("Parsing failed for string '" + s + "'");
108 }
109 collection.push_back(tmp);
110 }
111
112 any = collection;
113 }
114
116 template<typename T_>
117 static void parse_single(std::any& any, const String& s)
118 {
119 if(!s.parse(std::any_cast<T_&>(any)))
120 {
121 throw std::invalid_argument("Parsing failed for string '" + s + "'");
122 }
123 }
124
140 template<typename T_>
141 static void (*make_parser())(std::any&, const String&)
142 {
143 // If T_ has no input operator then instantiating a parser function for T_ will fail,
144 // because String::parse depends on that operator.
145 // But we want to give the user a chance to set a custom parser,
146 // so we guard the instantiation of the default parser behind
147 // can_default_parse_v
148
149 if constexpr(!can_default_parse_v<T_>)
150 {
151 return nullptr;
152 }
153 else
154 {
155 if constexpr(is_std_deque_v<T_>)
156 {
157 return parse_collection<typename T_::value_type>;
158 }
159 else
160 {
161 return parse_single<T_>;
162 }
163 }
164 }
165
176 template<typename T_>
177 static void (*make_printer())(std::ostream&, const std::any&)
178 {
179 if constexpr(is_std_deque_v<T_>)
180 {
181 return [](std::ostream& s, const std::any& v)
182 {
183 s << "[";
184 for(const auto& i : std::any_cast<const T_&>(v))
185 {
186 s << i << ", ";
187 }
188 s << "]";
189 };
190 }
191 else
192 {
193 return [](std::ostream& s, const std::any& v) { s << std::any_cast<const T_&>(v); };
194 }
195 }
196
204 enum class ParameterType : std::uint8_t
205 {
206 flag,
207 option,
208 collection_option,
209 };
210
227 {
228 public:
230 using ParserType = std::function<void(std::any&, const String&)>;
232 using ValidatorType = std::function<void(const std::any&)>;
234 using PrinterType = std::function<void(std::ostream&, const std::any&)>;
235
237 using Need = std::pair<std::weak_ptr<ParameterCore>, std::function<bool(const std::any&)>>;
238
239 // Parsing information
240 ParameterType type = ParameterType::flag;
241 String short_flag{""};
242 String long_flag{""};
243 String environment_variable{""};
244 String property_path{""};
245
246 // Strings for usage documentation
247 String custom_name;
248 String placeholder;
249 String help_string;
250
251 // Metadata
252 int priority = 0;
253 bool required = false;
254 bool set_by_user = false;
255 std::deque<Need> needs;
256
257 // Raw and parsed values
258 std::deque<String> arguments;
259 std::any default_value;
260 std::any value;
261
262 // Type-erased functions
263 ParserType parser;
264 ValidatorType validator;
265 PrinterType printer;
266
268 template<typename T_>
269 explicit ParameterCore(T_ def_value) :
270 default_value(def_value),
271 value(default_value),
272 printer(Intern::make_printer<T_>())
273 {
274 if constexpr(std::is_same_v<T_, bool>)
275 {
276 // Boolean flags do not consume any arguments beyond the flag itself
277 type = ParameterType::flag;
278 }
279 else if constexpr(Intern::is_std_deque_v<T_>)
280 {
281 // Collection options append all arguments until the next flag
282 type = ParameterType::collection_option;
283 }
284 else
285 {
286 type = ParameterType::option;
287 }
288 }
289
296 String name() const;
297
299 void add_argument(const String& s, int incoming_priority);
300
306 void validate(std::deque<String>& errors) const;
307
313 void parse(std::deque<String>& errors);
314
316 void reset();
317 };
318
319 } // namespace Intern
320
321 template<typename T_>
322 class ParameterBuilder;
323
329 template<typename T_>
331 {
332 private:
333 std::shared_ptr<Intern::ParameterCore> _core;
334
335 public:
336 template<typename U_>
337 friend class ParameterBuilder;
338
339 explicit Parameter(std::shared_ptr<Intern::ParameterCore>&& core) : _core(std::move(core))
340 {
341 }
342
343 explicit Parameter(std::shared_ptr<Intern::ParameterCore> core) : _core(std::move(core))
344 {
345 }
346
352 operator bool() // NOLINT
353 {
354 return _core->set_by_user;
355 }
356
358 const T_& value() const
359 {
360 return std::any_cast<const T_&>(_core->value);
361 }
362
364 const T_& operator*() const
365 {
366 return std::any_cast<const T_&>(_core->value);
367 }
368
370 const T_* operator->() const
371 {
372 return std::any_cast<const T_>(&(_core->value));
373 }
374 };
375
377 template<typename T_>
379 {
380 private:
381 std::shared_ptr<Intern::ParameterCore> _core;
382
383 public:
384 explicit ParameterBuilder(std::shared_ptr<Intern::ParameterCore> core) : _core(std::move(core))
385 {
386 }
387
394 {
395 XASSERTM(s.size() == 2, "Short flag must have length two");
396 XASSERTM(s[0] == '-', "Short must start with a '-'");
397 XASSERTM(s[1] != '-', "Short must not end with a '-'");
398
399 _core->short_flag = std::move(s);
400 return *this;
401 }
402
410 {
411 _core->long_flag = std::move(s);
412 return *this;
413 }
414
424 {
425 _core->environment_variable = std::move(s);
426 return *this;
427 }
428
439 {
440 _core->property_path = std::move(s);
441 return *this;
442 }
443
463 {
464 s.trim();
465 _core->help_string = std::move(s);
466 return *this;
467 }
468
488 {
489 _core->placeholder = std::move(s);
490 return *this;
491 }
492
504 {
505 _core->custom_name = std::move(s);
506 return *this;
507 }
508
521 ParameterBuilder& parser(T_ (*parser_fn)(const String&))
522 {
523 // SAFETY:
524 // Functions exist for the lifetime of the program.
525 // Thus a valid function pointer will never dangle
526 // and calling this lambda later is always safe
527 const auto lambda = [parser_fn](std::any& any, const String& s) { any = parser_fn(s); };
528 _core->parser = lambda;
529
530 return *this;
531 }
532
549 ParameterBuilder& validator(void (*validator_fn)(const T_&))
550 {
551 XASSERTM(validator_fn != nullptr, "Validator must be valid function pointer!");
552
553 // NOTE:
554 // We accept a function pointer here, because it
555 // forbids the user from passing us a lambda-expression
556 // that captures something from its environment
557
558 // SAFETY:
559 // Functions exist for the lifetime of the program.
560 // Thus a valid function pointer will never dangle
561 // and calling this lambda later is always safe
562 const auto lambda = [validator_fn](const std::any& any) { validator_fn(std::any_cast<const T_&>(any)); };
563 _core->validator = lambda;
564
565 return *this;
566 }
567
586 ParameterBuilder& validator(bool (*validator_fn)(const T_&))
587 {
588 XASSERTM(validator_fn != nullptr, "Validator must be valid function pointer!");
589
590 // NOTE:
591 // We accept a function pointer here, because it
592 // forbids the user from passing us a lambda-expression
593 // that captures something from its environment
594
595 // SAFETY:
596 // Functions exist for the lifetime of the program.
597 // Thus a valid function pointer will never dangle
598 // and calling this lambda later is always safe
599 const auto lambda = [validator_fn](const std::any& any)
600 {
601 if(!validator_fn(std::any_cast<const T_&>(any)))
602 {
603 throw std::invalid_argument("Failed boolean test");
604 }
605 };
606 _core->validator = lambda;
607
608 return *this;
609 }
610
618 {
619 _core->required = true;
620
621 return *this;
622 }
623
643 template<typename U_>
645 {
646 XASSERTM(parameter._core != nullptr, "Needed parameter must be defined already!");
647
648 _core->needs.emplace_back(parameter._core, [](const std::any& /*unused*/) { return true; });
649
650 return *this;
651 }
652
674 template<typename U_>
675 ParameterBuilder& needs_if(const Parameter<U_>& parameter, bool (*condition)(const T_&))
676 {
677 XASSERTM(parameter._core != nullptr, "Needed parameter must be defined already!");
678
679 _core->needs.emplace_back(
680 parameter._core,
681 [condition](const std::any& value) { return condition(std::any_cast<const T_&>(value)); });
682
683 return *this;
684 }
685
686 // NOTE: This conversion operator exists to convert the ParameterBuilder produced by ArgParser::parameter
687 // into a parameter without forcing the user to call an additional function for every parameter.
688 // For that reason it is deliberately implicit
690 operator Parameter<T_>() // NOLINT
691 {
692 if(_core->placeholder.empty())
693 {
694 if(!_core->long_flag.empty())
695 {
696 _core->placeholder = _core->long_flag.substr(2);
697 }
698 else if(!_core->short_flag.empty())
699 {
700 _core->placeholder = _core->short_flag.substr(1);
701 }
702 }
703
704 if(!_core->parser)
705 {
706 _core->parser = Intern::make_parser<T_>();
707 }
708 return Parameter<T_>(_core);
709 }
710 };
711
834 {
835 private:
836 std::deque<std::shared_ptr<Intern::ParameterCore>> _parameters;
837 std::deque<String> _errors;
838
839 String _program{""};
840 String _description{""};
841
842 static constexpr int priority_default = 0;
843 static constexpr int priority_env = 1;
844 static constexpr int priority_property = 2;
845 static constexpr int priority_cli = 3;
846
847 public:
848 const std::deque<String>& errors() const
849 {
850 return _errors;
851 }
852
860 void set_description(String&& description)
861 {
862 _description = std::move(description);
863 }
864
872 [[nodiscard]] String help_text()
873 {
874 // Sort parameters alphabetically
875 std::sort(
876 _parameters.begin(),
877 _parameters.end(),
878 [](auto& a, auto& b) { return a->name().compare_no_case(b->name()) <= 0; });
879
880 std::stringstream stream;
881
882 if(!_description.empty())
883 {
884 stream << _description << "\n\n";
885 }
886 stream << "Usage: " << _program << " [OPTIONS]\n\n";
887 stream << "Options:\n";
888
889 for(const auto& core : _parameters)
890 {
891 parameter_help(*core, stream);
892 }
893
894 return stream.str();
895 }
896
905 [[nodiscard]] String display()
906 {
907 // Sort parameters alphabetically
908 std::sort(
909 _parameters.begin(),
910 _parameters.end(),
911 [](auto& a, auto& b) { return a->name().compare_no_case(b->name()) <= 0; });
912
913 std::stringstream stream;
914
915 // Print header
916 stream << String("Parameter").pad_back(40, ' ');
917 stream << "|";
918 stream << String("Source").pad_back(10, ' ');
919 stream << "|";
920 stream << "Value\n";
921 stream << String("").pad_back(75, '-') << "\n";
922
923 for(const auto& core : _parameters)
924 {
925 XASSERT(core->value.has_value());
926
927 stream << core->name().pad_back(40, '.');
928 stream << "|";
929
930 switch(core->priority)
931 {
932 case priority_default: stream << "default |"; break;
933 case priority_env: stream << "env |"; break;
934 case priority_property: stream << "property |"; break;
935 case priority_cli: stream << "cli |"; break;
936 default: stream << " |";
937 }
938
939 if(core->type == Intern::ParameterType::flag)
940 {
941 stream << (std::any_cast<const bool&>(core->value) ? "true" : "false");
942 }
943 else
944 {
945 XASSERT(bool(core->printer));
946 core->printer(stream, core->value);
947 }
948
949 stream << "\n";
950 }
951
952 return stream.str();
953 }
954
966 [[nodiscard]] bool parse(int argc, const char* const* argv, const PropertyMap* property_map = nullptr)
967 {
968 // Reset errors
969 _errors.clear();
970
972 {
973 return false;
974 }
975
976 // Set default values, reset priorities, clear arguments
977 for(auto& core : _parameters)
978 {
979 core->reset();
980 }
981
982 // Collect values in environment variables
983 _collect_env();
984
985 // Collect values in property map
986 if(property_map != nullptr)
987 {
988 _collect_property_map(property_map);
989 }
990
991 // Collect command line args
992 _collect_args(argc, argv);
993
994 // Parse collected data types into proper data types
995 for(auto& core : _parameters)
996 {
997 core->parse(_errors);
998 }
999
1000 _validate();
1001
1002 return _errors.empty();
1003 }
1004
1012 [[nodiscard]] bool parse(const PropertyMap& property_map)
1013 {
1014 return parse(0, nullptr, &property_map);
1015 }
1016
1028 [[nodiscard]] bool parse(int argc, const char* const* argv, const String& property_map_path)
1029 {
1030 PropertyMap pmap;
1031 pmap.read(property_map_path);
1032 return parse(argc, argv, &pmap);
1033 }
1034
1042 [[nodiscard]] bool parse(const String& property_map_path)
1043 {
1044 PropertyMap pmap;
1045 pmap.read(property_map_path);
1046 return parse(0, nullptr, &pmap);
1047 }
1048
1049 protected:
1057 template<typename T_>
1058 ParameterBuilder<T_> parameter(T_&& default_value = T_{})
1059 {
1060 // Create type-erased parameter core
1061 std::shared_ptr<Intern::ParameterCore> core = std::make_shared<Intern::ParameterCore>(std::forward<T_>(default_value));
1062
1063 // Store type-erased core for parsing purposes.
1064 // This allows the parser to treat all parameters the same,
1065 // irrespective of the types of their values.
1066 _parameters.push_back(core);
1067
1068 // Return builder to user for defining the parameter fully
1069 return ParameterBuilder<T_>(std::move(core));
1070 }
1071
1072 private:
1076 {
1077 std::set<String> short_flags;
1078 std::set<String> long_flags;
1079 std::set<String> environment_variables;
1080 std::set<String> property_paths;
1081
1082 bool result = true;
1083
1084 auto handle_flag = [&](std::set<String>& set, const String& s)
1085 {
1086 if(s.empty())
1087 {
1088 return;
1089 }
1090
1091 if(set.find(s) != set.end())
1092 {
1093 _errors.push_back("Error: Flag " + s + " is used by multiple parameters");
1094 result = false;
1095 }
1096 else
1097 {
1098 set.insert(s);
1099 }
1100 };
1101
1102 for(auto& core : _parameters)
1103 {
1104 handle_flag(short_flags, core->short_flag);
1105 handle_flag(long_flags, core->long_flag);
1106 handle_flag(environment_variables, core->environment_variable);
1107 handle_flag(property_paths, core->property_path);
1108 }
1109
1110 return result;
1111 }
1112
1113 void _collect_env()
1114 {
1115 for(auto& core : _parameters)
1116 {
1117 const char* value = std::getenv(core->environment_variable.c_str());
1118 if(value != nullptr)
1119 {
1120 String s(value);
1121 core->add_argument(s, priority_env);
1122 }
1123 }
1124 }
1125
1126 void _collect_property_map(const PropertyMap* property_map)
1127 {
1128 for(auto& core : _parameters)
1129 {
1130 auto [string, success] = property_map->query(core->property_path);
1131 if(success)
1132 {
1133 core->add_argument(string, priority_property);
1134 }
1135 }
1136 }
1137
1138 void _collect_args(int argc, const char* const* argv)
1139 {
1140 if(argc == 0)
1141 {
1142 return;
1143 }
1144
1145 _program = String(argv[0]);
1146
1147 std::deque<String> args;
1148
1149 for(int i(1); i < argc; i++)
1150 {
1151 args.emplace_back(argv[i]);
1152 }
1153
1154 Index idx(0);
1155 while(idx < args.size())
1156 {
1157 const String& flag = args[idx++];
1158
1159 if(!is_flag(flag))
1160 {
1161 XABORTM("Error: Expected flag in position " + stringify(idx));
1162 }
1163
1164 bool handled = false;
1165 for(auto& core : _parameters)
1166 {
1167 if(flag.compare_no_case(core->short_flag) != 0 && flag.compare_no_case(core->long_flag) != 0)
1168 {
1169 continue;
1170 }
1171
1172 handled = true;
1173
1174 if(core->type == Intern::ParameterType::flag)
1175 {
1176 // Flag was given. Invert its state.
1177 // any_cast is safe because flags must be bool parameters
1178 core->value = !std::any_cast<const bool&>(core->default_value);
1179 core->set_by_user = true;
1180 }
1181 else if(core->type == Intern::ParameterType::option)
1182 {
1183 // Normal option. Consume a single argument
1184 core->add_argument(args[idx++], priority_cli);
1185 }
1186 else if(core->type == Intern::ParameterType::collection_option)
1187 {
1188 // Collect arguments until next flag
1189 while(idx < args.size() && !is_flag(args[idx]))
1190 {
1191 core->add_argument(args[idx++], priority_cli);
1192 }
1193 }
1194 }
1195
1196 if(!handled)
1197 {
1198 // We found no parameter for this flag. Generate error
1199 _errors.push_back("Error: Unknown flag " + flag);
1200
1201 // Then advance to next flag
1202 while(idx < args.size() && !is_flag(args[idx]))
1203 {
1204 idx++;
1205 }
1206 }
1207 }
1208 }
1209
1212 {
1213 for(auto& core : _parameters)
1214 {
1215 core->validate(_errors);
1216 }
1217 }
1218
1220 static void parameter_help(const Intern::ParameterCore& core, std::stringstream& s)
1221 {
1222 if(
1223 core.short_flag.empty() && core.long_flag.empty() && core.property_path.empty() &&
1224 core.environment_variable.empty())
1225 {
1226 return;
1227 }
1228
1229 s << "\t";
1230
1231 auto format_flag = [&s](Intern::ParameterType type, const String& flag, const String& placeholder)
1232 {
1233 if(type == Intern::ParameterType::flag)
1234 {
1235 s << flag;
1236 }
1237 if(type == Intern::ParameterType::option)
1238 {
1239 s << flag << " <" << placeholder << ">";
1240 }
1241 if(type == Intern::ParameterType::collection_option)
1242 {
1243 s << flag << " <" << placeholder << "s...>";
1244 }
1245 };
1246
1247 auto format_other = [&s](const std::string_view prefix, const String& value)
1248 { s << "[" << prefix << ":" << value << "]"; };
1249
1250 // -a, --arg, [property:arg], [env:FEAT_ARG]
1251
1252 bool has_prev = false;
1253 if(!core.short_flag.empty())
1254 {
1255 format_flag(core.type, core.short_flag, core.placeholder);
1256 has_prev = true;
1257 }
1258
1259 if(!core.long_flag.empty())
1260 {
1261 if(has_prev)
1262 {
1263 s << ", ";
1264 }
1265
1266 format_flag(core.type, core.long_flag, core.placeholder);
1267
1268 has_prev = true;
1269 }
1270
1271 if(!core.property_path.empty())
1272 {
1273 if(has_prev)
1274 {
1275 s << ", ";
1276 }
1277
1278 format_other("property", core.property_path);
1279
1280 has_prev = true;
1281 }
1282
1283 if(!core.environment_variable.empty())
1284 {
1285 if(has_prev)
1286 {
1287 s << ", ";
1288 }
1289
1290 format_other("env", core.environment_variable);
1291
1292 has_prev = true;
1293 }
1294
1295 if(has_prev)
1296 {
1297 s << "\n";
1298 }
1299
1300 if(core.required)
1301 {
1302 s << "\t\tRequired argument.\n";
1303 }
1304
1305 for(const String& line : core.help_string.split_by_charset("\n"))
1306 {
1307 s << "\t\t" << line.trim() << "\n";
1308 }
1309
1310 s << "\n";
1311 }
1312
1313 static bool is_flag(const String& s)
1314 {
1315 return !s.empty() && s[0] == '-';
1316 }
1317 };
1318} // namespace FEAT
#define XABORTM(msg)
Abortion macro definition with custom message.
Definition: assertion.hpp:192
#define XASSERT(expr)
Assertion macro definition.
Definition: assertion.hpp:262
#define XASSERTM(expr, msg)
Assertion macro definition with custom message.
Definition: assertion.hpp:263
Argument parser base class.
Definition: arg_parser.hpp:834
String display()
Produce formatted output of all values in this parser.
Definition: arg_parser.hpp:905
ParameterBuilder< T_ > parameter(T_ &&default_value=T_{})
Add a Parameter to this parser.
void _validate()
Validate parameters after parsing.
bool parse(const String &property_map_path)
Populate this parser.
static void parameter_help(const Intern::ParameterCore &core, std::stringstream &s)
Write flags, property path, environment variable and help text for given parameter to stringstream.
bool parse(int argc, const char *const *argv, const PropertyMap *property_map=nullptr)
Populate this parser.
Definition: arg_parser.hpp:966
void set_description(String &&description)
Set program description.
Definition: arg_parser.hpp:860
bool _check_for_unique_parameters()
bool parse(const PropertyMap &property_map)
Populate this parser.
String help_text()
Generate help text for this parser.
Definition: arg_parser.hpp:872
bool parse(int argc, const char *const *argv, const String &property_map_path)
Populate this parser.
Type-erased core of a Parameter.
Definition: arg_parser.hpp:227
String name() const
Tries to create a user-readable name for this parameter.
Definition: arg_parser.cpp:18
std::pair< std::weak_ptr< ParameterCore >, std::function< bool(const std::any &)> > Need
Type of "A needs B" declaration with condition.
Definition: arg_parser.hpp:237
void parse(std::deque< String > &errors)
Parse this parameter.
Definition: arg_parser.cpp:111
std::function< void(std::ostream &, const std::any &)> PrinterType
Type of type-erased printer function.
Definition: arg_parser.hpp:234
std::function< void(std::any &, const String &)> ParserType
Type of type-erased parser function.
Definition: arg_parser.hpp:230
std::function< void(const std::any &)> ValidatorType
Type of type-erased validator function.
Definition: arg_parser.hpp:232
ParameterCore(T_ def_value)
Constructor.
Definition: arg_parser.hpp:269
void validate(std::deque< String > &errors) const
Validate this parameter.
Definition: arg_parser.cpp:66
void reset()
Reset this parameter to default.
Definition: arg_parser.cpp:167
void add_argument(const String &s, int incoming_priority)
Add an argument to this parameter.
Definition: arg_parser.cpp:48
Builder-pattern for defining parameters. See methods for details.
Definition: arg_parser.hpp:379
ParameterBuilder & env(String &&s)
Set the environment variable for a parameter.
Definition: arg_parser.hpp:423
ParameterBuilder & validator(void(*validator_fn)(const T_ &))
Set a validator for this paramater.
Definition: arg_parser.hpp:549
ParameterBuilder & validator(bool(*validator_fn)(const T_ &))
Set a validator for this paramater.
Definition: arg_parser.hpp:586
ParameterBuilder & property(String &&s)
Set the property map path for a parameter.
Definition: arg_parser.hpp:438
ParameterBuilder & required()
Mark this parameter as required.
Definition: arg_parser.hpp:617
ParameterBuilder & needs(const Parameter< U_ > &parameter)
Mark another parameter as needed by this one.
Definition: arg_parser.hpp:644
ParameterBuilder & short_flag(String &&s)
Set the short flag for a parameter.
Definition: arg_parser.hpp:393
ParameterBuilder & name(String &&s)
Set a name for this parameter.
Definition: arg_parser.hpp:503
ParameterBuilder & placeholder(String &&s)
Set a placeholder text for the argument of this parameter.
Definition: arg_parser.hpp:487
ParameterBuilder & needs_if(const Parameter< U_ > &parameter, bool(*condition)(const T_ &))
Conditionally mark another parameter as needed by this one.
Definition: arg_parser.hpp:675
ParameterBuilder & parser(T_(*parser_fn)(const String &))
Set a custom parser for this parameter.
Definition: arg_parser.hpp:521
ParameterBuilder & long_flag(String &&s)
Set the long flag for a parameter.
Definition: arg_parser.hpp:409
ParameterBuilder & help_string(String &&s)
Set help string for this parameter.
Definition: arg_parser.hpp:462
Parameter of an ArgParser.
Definition: arg_parser.hpp:331
const T_ * operator->() const
Accessor for parameter value.
Definition: arg_parser.hpp:370
const T_ & operator*() const
Accessor for parameter value.
Definition: arg_parser.hpp:364
const T_ & value() const
Accessor for parameter value.
Definition: arg_parser.hpp:358
A class organizing a tree of key-value pairs.
void read(String filename, bool replace=true)
Parses a file in INI-format.
String class implementation.
Definition: string.hpp:47
std::deque< String > split_by_whitespaces() const
Splits the string by white-spaces.
Definition: string.hpp:519
String pad_back(size_type len, char c=' ') const
Pads the back of the string up to a desired length.
Definition: string.hpp:416
std::deque< String > split_by_charset(const String &charset) const
Splits the string by a delimiter charset.
Definition: string.hpp:468
@ success
solving successful (convergence criterion fulfilled)
FEAT namespace.
Definition: adjactor.hpp:12
String stringify(const T_ &item)
Converts an item into a String.
Definition: string.hpp:993
@ value
specifies whether the space should supply basis function values
std::uint64_t Index
Index data type.
Check if type has an operator>> implementation, i.e. can be parsed by String::parse.
Definition: arg_parser.hpp:79
Check if type is some instantiation of std::deque.
Definition: arg_parser.hpp:63