diff options
author | Tom Smeding <tom@tomsmeding.com> | 2025-09-03 23:31:40 +0200 |
---|---|---|
committer | Tom Smeding <tom@tomsmeding.com> | 2025-09-03 23:37:53 +0200 |
commit | 7e60437d3c064bca402d486be967c43bf4326067 (patch) | |
tree | 8b4307b90c942861176d9c705cd760b9fe7b6c6b /options.h |
This includes old code too, perhaps from 2021-05-05, judging from the
birth timestamp on the directory. The old code included option parsing
and equation solving for fancy mutually-dependent options, but no actual
rendering (imagine that).
Diffstat (limited to 'options.h')
-rw-r--r-- | options.h | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/options.h b/options.h new file mode 100644 index 0000000..831af3e --- /dev/null +++ b/options.h @@ -0,0 +1,137 @@ +#pragma once + +#include "eqsystem_solve.h" +#include <iostream> +#include <optional> +#include <thread> +#include <cstring> +#include <cstdlib> +#include <cstdint> +#include <cassert> +#include <unistd.h> + + +template <typename T> +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<std::pair<std::string, double>> &assign); + void parse(const char *str, const char *option); + void set(T value); + bool valid() const; +}; + +template <typename T> +Product Param<T>::toProduct() const { + static_assert(std::is_integral_v<T> || std::is_floating_point_v<T>); + if (given || computed) return Product{static_cast<double>(value), {}}; + else return Product{1.0, {name}}; +} + +template <typename T> +void Param<T>::from_computed(const std::vector<std::pair<std::string, double>> &assign) { + if (given || computed) return; + for (const auto &p : assign) { + if (p.first == name) { + computed = true; + if constexpr (std::is_integral_v<T>) { + 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<T, double>); + 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<const char*> parse_int_param(int64_t *dest, const char *str); + +template <typename T> +void Param<T>::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<T, double>) { + 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<T, std::string>) { + value = str; + given = true; + } else { + static_assert(std::is_same_v<T, int> || std::is_same_v<T, int64_t>); + int64_t res; + if (std::optional<const char*> 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 <typename T> +void Param<T>::set(T value) { + computed = true; + this->value = std::move(value); +} + +template <typename T> +bool Param<T>::valid() const { + return given || computed; +} + +struct Options { + // Mutually-inferrable parameters + Param<double> xmin{"xmin"}, xmax{"xmax"}, ymin{"ymin"}, ymax{"ymax"}; + Param<double> cplxwidth{"cplxwidth"}, cplxheight{"cplxheight"}; + Param<double> cx{"cx"}, cy{"cy"}; + Param<int> imgwidth{"imgwidth"}, imgheight{"imgheight"}; + + // Normal parameters + Param<int> maxiter{"maxiter", 1024}; + Param<int64_t> numorbits{"numorbits", 1000000}; + Param<int> num_threads{"num_threads", (int)std::thread::hardware_concurrency()}; + Param<int> orbit_burnin{"orbit_burnin", 4}; + bool debug_paramsolver = false; + Param<std::string> outfname{"outfname"}; + Param<std::string> 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: |