61 lines
1.5 KiB
C++
61 lines
1.5 KiB
C++
#pragma once
|
|
|
|
#include <algorithm>
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace iue::po {
|
|
|
|
inline std::vector<std::string> init(int argc, char* argv[]) {
|
|
return {argv + 1, argv + argc};
|
|
}
|
|
|
|
enum struct option { optional, required };
|
|
|
|
template <typename T>
|
|
inline T get(std::vector<std::string> args, std::string option, T default_value, enum option op = option::optional) {
|
|
auto find_option = [&option](const std::string& arg) -> bool {
|
|
return arg.starts_with("-" + option) || arg.starts_with("--" + option);
|
|
};
|
|
const auto count = std::ranges::count_if(args, find_option);
|
|
|
|
if (count == 0) {
|
|
if (op == option::required) {
|
|
throw std::runtime_error("required option not provided: -/--" + option);
|
|
}
|
|
|
|
return default_value;
|
|
}
|
|
|
|
if (count > 1) {
|
|
throw std::runtime_error("option not unique: -/--" + option + " (count = " + std::to_string(count) + ")");
|
|
}
|
|
|
|
auto it = std::ranges::find_if(args, find_option);
|
|
auto value = std::next(it);
|
|
|
|
if (value == args.end()) {
|
|
throw std::runtime_error("option not followed by value: -/--" + option);
|
|
}
|
|
|
|
if (value->starts_with('-')) {
|
|
throw std::runtime_error("option -/--" + option + " not followed by value but another option -/--" + *value);
|
|
}
|
|
|
|
std::istringstream ss(*value);
|
|
ss.exceptions(std::ios::failbit);
|
|
|
|
T num;
|
|
|
|
try {
|
|
ss >> num;
|
|
} catch (std::exception& e) {
|
|
throw std::runtime_error("value for option -/--" + option + " could not be converted");
|
|
}
|
|
|
|
return num;
|
|
}
|
|
|
|
} // namespace iue::po
|