#pragma once #include "eqsystem_solve.h" #include #include #include #include #include #include #include #include template struct Param { bool given = false, computed = false; T value; // valid if given || computed std::string name; Param(std::string name) : name{name} {} Param(std::string name, T value) : computed{true}, value{std::move(value)}, name{name} {} Product toProduct() const; void from_computed(const std::vector> &assign); void parse(const char *str, const char *option); void set(T value); bool valid() const; }; template Product Param::toProduct() const { static_assert(std::is_integral_v || std::is_floating_point_v); if (given || computed) return Product{static_cast(value), {}}; else return Product{1.0, {name}}; } template void Param::from_computed(const std::vector> &assign) { if (given || computed) return; for (const auto &p : assign) { if (p.first == name) { computed = true; if constexpr (std::is_integral_v) { value = p.second; if (p.second != value) { std::cerr << "Non-integral value computed for integral option " << name << ": " << p.second << std::endl; exit(1); } } else { static_assert(std::is_same_v); value = p.second; } value = p.second; return; } } if (!computed) { std::cerr << "Value for option " << name << " ambiguous! Was a dimension zero?" << std::endl; exit(1); } } std::optional parse_int_param(int64_t *dest, const char *str); template void Param::parse(const char *str, const char *option) { if (str == nullptr) { std::cerr << "Missing argument for option '" << option << "'" << std::endl; exit(1); } if constexpr (std::is_same_v) { char *endp; value = strtod(str, &endp); if (!*str || *endp) { std::cerr << "Could not parse floating-point value from argument '" << str << "'" << std::endl; exit(1); } given = true; } else if constexpr (std::is_same_v) { value = str; given = true; } else { static_assert(std::is_same_v || std::is_same_v); int64_t res; if (std::optional err = parse_int_param(&res, str)) { std::cerr << "Could not parse integer from argument '" << str << "': " << *err << std::endl; exit(1); } else { value = (T)res; given = true; } } } template void Param::set(T value) { computed = true; this->value = std::move(value); } template bool Param::valid() const { return given || computed; } struct Options { // Mutually-inferrable parameters Param xmin{"xmin"}, xmax{"xmax"}, ymin{"ymin"}, ymax{"ymax"}; Param cplxwidth{"cplxwidth"}, cplxheight{"cplxheight"}; Param cx{"cx"}, cy{"cy"}; Param imgwidth{"imgwidth"}, imgheight{"imgheight"}; // Normal parameters Param maxiter{"maxiter", 1024}; Param numorbits{"numorbits", 1000000}; Param num_threads{"num_threads", (int)std::thread::hardware_concurrency()}; Param orbit_burnin{"orbit_burnin", 4}; bool debug_paramsolver = false; Param outfname{"outfname"}; Param algorithm{"algorithm", "vectorised"}; // Infer the mutually-inferrable parameters void fill_dimensions(); // Check presence of normal parameters and consistency of all parameters void validate(); }; std::ostream& operator<<(std::ostream &os, const Options &opts); void usage(const char *argv0); Options parse_options(int argc, char **argv); // vim: set sw=4 ts=4 noet: