1#ifndef CMD_LINE_PARSER_HPP
2#define CMD_LINE_PARSER_HPP
26#include <QCoreApplication>
30#include <boost/program_options.hpp>
40namespace po = boost::program_options;
48 NotEnoughIterations = -2,
51 NegativeTimeStep = -5,
57 UnknownException = -11,
85 case LogLevel::Warning:
86 return os <<
"warning";
87 case LogLevel::Critical:
88 return os <<
"critical";
107 double value,
int precision = 1,
108 bool use_scientific =
true) {
109 std::ostringstream out;
110 out.precision(precision);
111 if (use_scientific) {
112 out << std::scientific;
122 const std::string& option_name,
123 const std::function<QString(
const char*)>& tr_func);
136 if (token ==
"debug")
137 level = LogLevel::Debug;
138 else if (token ==
"info")
139 level = LogLevel::Info;
140 else if (token ==
"warning")
141 level = LogLevel::Warning;
142 else if (token ==
"critical")
143 level = LogLevel::Critical;
144 else if (token ==
"fatal")
145 level = LogLevel::Fatal;
147 is.setstate(std::ios_base::failbit);
273 const std::function<QString(
const char*)>& tr_func)
const {
279 throw po::validation_error(
280 po::validation_error::invalid_option_value,
284 "CmdLine::CmdLineArgs",
285 "The value for option 'dens' must be positive."))
289 throw po::validation_error(
290 po::validation_error::invalid_option_value,
292 tr_func(QT_TRANSLATE_NOOP(
293 "CmdLine::CmdLineArgs",
294 "The value for option 'dt' must be positive."))
298 throw po::validation_error(
299 po::validation_error::invalid_option_value,
301 tr_func(QT_TRANSLATE_NOOP(
"CmdLine::CmdLineArgs",
302 "The value for option "
303 "'universalg' must be positive."))
307 throw po::validation_error(
308 po::validation_error::invalid_option_value,
312 "CmdLine::CmdLineArgs",
313 "The value for option 'epsilon' must be positive."))
317 throw po::validation_error(
318 po::validation_error::invalid_option_value,
320 tr_func(QT_TRANSLATE_NOOP(
321 "CmdLine::CmdLineArgs",
322 "The value for option 'restitution' must be "
327 throw po::validation_error(
328 po::validation_error::invalid_option_value,
330 tr_func(QT_TRANSLATE_NOOP(
"CmdLine::CmdLineArgs",
331 "The value for option 'friction' "
332 "must be non-negative."))
336 throw po::validation_error(
337 po::validation_error::invalid_option_value,
339 tr_func(QT_TRANSLATE_NOOP(
340 "CmdLine::CmdLineArgs",
341 "The value for option 'static-friction' must "
346 throw po::validation_error(
347 po::validation_error::invalid_option_value,
349 tr_func(QT_TRANSLATE_NOOP(
350 "CmdLine::CmdLineArgs",
351 "Damping values must be non-negative."))
355 throw po::validation_error(
356 po::validation_error::invalid_option_value,
358 tr_func(QT_TRANSLATE_NOOP(
359 "CmdLine::CmdLineArgs",
360 "The value for option 'cleanup-mode' must be "
361 "'fast' or 'strict'."))
375 static std::unique_ptr<CmdLineArgs>
parse(
378 const QStringList& q_args,
379 const std::function<QString(
const char*)>& tr_func) {
380 auto args = std::make_unique<CmdLineArgs>();
383 std::vector<std::string> std_args;
384 std_args.reserve(q_args.size());
385 for (
const auto& arg : q_args) {
386 std_args.push_back(arg.toStdString());
389 const std::vector<OptionDefinition> definitions = {
391 tr_func(QT_TRANSLATE_NOOP(
"CmdLine::CmdLineArgs",
392 "Display this help message."))
396 tr_func(QT_TRANSLATE_NOOP(
"CmdLine::CmdLineArgs",
397 "Display program version."))
401 tr_func(QT_TRANSLATE_NOOP(
"CmdLine::CmdLineArgs",
402 "Enable diagnostic output (alias "
403 "for --debugConsole)."))
405 [&] {
return po::bool_switch(); }},
407 tr_func(QT_TRANSLATE_NOOP(
408 "CmdLine::CmdLineArgs",
409 "Enable logs through the standard output."))
412 return po::bool_switch(&args->debug_console_)
413 ->default_value(
false);
416 tr_func(QT_TRANSLATE_NOOP(
"CmdLine::CmdLineArgs",
417 "Enable logs into a file."))
420 return po::value<std::string>(&args->debug_file_)
424 tr_func(QT_TRANSLATE_NOOP(
"CmdLine::CmdLineArgs",
425 "Enable logs through Syslog."))
428 return po::value<std::string>(&args->debug_syslog_)
434 "CmdLine::CmdLineArgs",
435 "Cleanup strategy: 'fast' (deferred destruction, "
436 "best performance) or 'strict' (synchronous "
437 "destruction, conservative)."))
440 return po::value<std::string>(&args->cleanup_mode_)
441 ->default_value(
"fast");
444 tr_func(QT_TRANSLATE_NOOP(
445 "CmdLine::CmdLineArgs",
446 "Log level filter (debug, info, warning, "
447 "critical, fatal)."))
450 return po::value<LogLevel>(&args->log_level_)
451 ->default_value(LogLevel::Critical);
454 tr_func(QT_TRANSLATE_NOOP(
"CmdLine::CmdLineArgs",
455 "Number of iterations."))
458 return po::value<std::size_t>(&args->n_iter_)
459 ->default_value(500);
462 tr_func(QT_TRANSLATE_NOOP(
"CmdLine::CmdLineArgs",
463 "Number of bodies."))
466 return po::value<std::size_t>(&args->n_bodies_)
470 tr_func(QT_TRANSLATE_NOOP(
471 "CmdLine::CmdLineArgs",
472 "Object density (proportionality coefficient "
473 "between mass and radius)."))
476 return po::value<double>(&args->dens_)
481 tr_func(QT_TRANSLATE_NOOP(
"CmdLine::CmdLineArgs",
482 "Model time step (in s)."))
485 return po::value<double>(&args->dt_)
492 "CmdLine::CmdLineArgs",
493 "Universal gravitational constant (in m³ / kg / s²)."))
496 return po::value<double>(&args->G_)->default_value(
500 tr_func(QT_TRANSLATE_NOOP(
501 "CmdLine::CmdLineArgs",
502 "Seed for random number generation. If 0, a "
503 "random seed is used."))
506 return po::value<unsigned int>(&args->seed_)
510 tr_func(QT_TRANSLATE_NOOP(
"CmdLine::CmdLineArgs",
511 "Computing precision."))
514 return po::value<double>(&args->epsilon_)
520 tr_func(QT_TRANSLATE_NOOP(
"CmdLine::CmdLineArgs",
521 "Frequency of energy log output "
522 "(every N iterations)."))
525 return po::value<std::size_t>(&args->log_freq_)
526 ->default_value(Model::DEFAULT_LOG_FREQ);
529 tr_func(QT_TRANSLATE_NOOP(
530 "CmdLine::CmdLineArgs",
531 "Coefficient of restitution for collisions."))
534 return po::value<double>(&args->restitution_)
536 Model::COEFF_RESTITUTION,
541 tr_func(QT_TRANSLATE_NOOP(
542 "CmdLine::CmdLineArgs",
543 "Coefficient of kinetic (sliding) friction."))
546 return po::value<double>(&args->friction_)
547 ->default_value(Model::COEFF_FRICTION,
549 Model::COEFF_FRICTION, 1,
false));
551 {
"static-friction,T",
552 tr_func(QT_TRANSLATE_NOOP(
"CmdLine::CmdLineArgs",
553 "Coefficient of static friction."))
556 return po::value<double>(&args->static_friction_)
558 Model::COEFF_STATIC_FRICTION,
564 QT_TRANSLATE_NOOP(
"CmdLine::CmdLineArgs",
565 "Damping factor for linear velocity."))
568 return po::value<double>(&args->linear_damping_)
569 ->default_value(Model::LINEAR_DAMPING,
571 Model::LINEAR_DAMPING, 3,
false));
573 {
"angular-damping,a",
575 QT_TRANSLATE_NOOP(
"CmdLine::CmdLineArgs",
576 "Damping factor for angular velocity."))
579 return po::value<double>(&args->angular_damping_)
580 ->default_value(Model::ANGULAR_DAMPING,
582 Model::ANGULAR_DAMPING, 3,
false));
584 {
"show-torque-arrow",
585 tr_func(QT_TRANSLATE_NOOP(
586 "CmdLine::CmdLineArgs",
587 "Show torque vectors as arrows in the UI."))
590 return po::bool_switch(&args->show_torque_arrow_)
591 ->default_value(
false);
594 tr_func(QT_TRANSLATE_NOOP(
"CmdLine::CmdLineArgs",
595 "Show angular acceleration vectors "
596 "as arrows in the UI."))
599 return po::bool_switch(&args->show_alpha_arrow_)
600 ->default_value(
false);
604 po::options_description desc(
605 tr_func(QT_TRANSLATE_NOOP(
"CmdLine::CmdLineArgs",
606 "Supported options"))
609 for (
const auto& def : definitions) {
610 if (def.value_factory) {
611 desc.add_options()(def.flags.c_str(), def.value_factory(),
612 def.help_text.c_str());
614 desc.add_options()(def.flags.c_str(),
615 def.help_text.c_str());
619 po::variables_map vm;
621 po::store(po::command_line_parser(std_args).options(desc).run(),
626 if (vm.count(
"diagnostics")) {
627 args->debug_console_ =
true;
631 catch (
const po::error& e) {
634 qCritical().noquote()
635 << tr_func(QT_TRANSLATE_NOOP(
"CmdLine::CmdLineArgs",
636 "Command line error: %1"))
638 std::cout << desc << std::endl;
641 if (vm.count(
"help")) {
642 std::stringstream desc_stream;
647 tr_func(QT_TRANSLATE_NOOP(
"CmdLine::CmdLineArgs",
648 "A benchmark for C++ using Qt "
652 << tr_func(QT_TRANSLATE_NOOP(
"CmdLine::CmdLineArgs",
655 << QCoreApplication::applicationFilePath()
657 << tr_func(QT_TRANSLATE_NOOP(
"CmdLine::CmdLineArgs",
660 << desc_stream.str().c_str();
664 if (vm.count(
"version")) {
666 << QString(
"%1 version %2.%3.%4")
667 .arg(QCoreApplication::applicationName())
668 .arg(Configuration::VERSION_MAJOR)
669 .arg(Configuration::VERSION_MINOR)
670 .arg(Configuration::PATCH_VERSION);
674 args->validate(tr_func);
693 const std::size_t& value,
const std::string& option_name,
694 const std::function<QString(
const char*)>& tr_func) {
699 throw po::validation_error(
700 po::validation_error::invalid_option_value,
703 tr_func(QT_TRANSLATE_NOOP(
704 "CmdLine::CmdLineArgs",
705 "The value for option '%1' must be positive."))
706 .arg(QString::fromStdString(option_name))
Namespace for command-line parsing logic.
void validateIsPositive(const std::size_t &value, const std::string &option_name, const std::function< QString(const char *)> &tr_func)
Validates that an unsigned integer option is greater than zero.
std::ostream & operator<<(std::ostream &os, const LogLevel &level)
Overload of operator<< for LogLevel to enable streaming.
ExitCode
Exit codes for the application.
std::istream & operator>>(std::istream &is, LogLevel &level)
Overload of operator>> for Boost.Program_Options to parse LogLevel.
std::string toStringWithPrecision(double value, int precision=1, bool use_scientific=true)
Converts a double to a string with a specified precision for display.
LogLevel
Log level for the application.
Holds and parses command-line arguments.
double static_friction_
Coefficient of static friction.
bool show_torque_arrow_
Flag to display torque vectors in the UI.
double restitution_
Coefficient of restitution for collisions.
double dt_
The time step for each simulation iteration.
bool show_alpha_arrow_
Flag to display angular acceleration vectors in the UI.
std::string cleanup_mode_
Cleanup strategy: "fast" (deferred) or "strict" (sync).
unsigned int seed_
The seed for the random number generator.
std::size_t n_iter_
The number of iterations to run the simulation.
std::size_t log_freq_
Frequency of energy log output.
double angular_damping_
Damping factor for angular velocity.
Configuration::SimulationConfig toSimulationConfig() const
Creates a SimulationConfig object from the parsed arguments.
double friction_
Coefficient of kinetic (sliding) friction.
double linear_damping_
Damping factor for linear velocity.
bool debug_console_
Flag to enable diagnostic output.
std::string debug_syslog_
Identifier for syslog logging.
double epsilon_
The numerical precision for floating-point comparisons.
LogLevel log_level_
Log level filter.
static std::unique_ptr< CmdLineArgs > parse(const QStringList &q_args, const std::function< QString(const char *)> &tr_func)
Parses and validates command-line arguments.
void validate(const std::function< QString(const char *)> &tr_func) const
Validates the parsed command-line arguments.
std::string debug_file_
File path for logging.
double G_
The universal gravitational constant.
std::size_t n_bodies_
The number of bodies in the simulation.
double dens_
The density of the bodies.
A struct to hold the definition of a single command-line option.
std::string flags
The flags for the option (e.g., "help,h").
std::function< po::value_semantic *()> value_factory
A function that returns the Boost.Program_Options value semantic. This allows us to handle different ...
std::string help_text
The help text for the option.