argparser/src/repeat-opt.h
2023-05-17 10:17:56 +02:00

97 lines
3.3 KiB
C++

#ifndef ARGPARSER_REPEAT_OPT_H
#define ARGPARSER_REPEAT_OPT_H
#include <cassert>
#include <format>
#include <memory>
#include <string>
#include <vector>
#include "errors.h"
#include "option.h"
#include "parse-result.h"
#include "type.h"
namespace argparser {
template<typename T>
class repeatable_option_impl : public option, public std::enable_shared_from_this<repeatable_option_impl<T>> {
public:
repeatable_option_impl(std::string name, type_handle_impl<T> type) : option(std::move(name)), type(std::move(type)) {}
std::shared_ptr<repeatable_option_impl<T>> default_value(std::vector<T> val) {
this->default_value_ = std::make_optional(val);
return this->shared_from_this();
}
std::shared_ptr<repeatable_option_impl<T>> min(unsigned int min) {
this->min_ = min;
return this->shared_from_this();
}
std::shared_ptr<repeatable_option_impl<T>> max(unsigned int max) {
this->max_ = max;
return this->shared_from_this();
}
void validate(const parse_result &pr) const override {
unsigned int count = 0;
if (pr.has_opt(this->name)) {
count = get(pr).size();
}
if ((min_.has_value() && count < min_.value()) ||
(max_.has_value() && count > max_.value())) {
throw errors::wrong_option_count_error(this->name, min_, max_, count);
}
}
[[nodiscard]] bool consumes_value() const override {
return true;
}
[[nodiscard]] std::vector<T> get(const parse_result &pr) const {
auto v = pr.get_opt(name);
if (!v.has_value()) {
if (default_value_.has_value()) {
return default_value_.value();
}
throw std::runtime_error(std::format("option {} was not provided", name));
}
return std::any_cast<std::vector<T>>(v);
}
[[nodiscard]] bool has(const parse_result &pr) const {
return pr.has_opt(name);
}
private:
void do_parse(std::optional<std::string> arg, std::any &val) override {
assert(arg.has_value());
const char *parse_end;
auto begin = &*arg->begin();
auto end = &*arg->end();
auto single_val = this->type->parse(begin, end, parse_end, internal::parser_allow_undelimited::Any);
if (parse_end != end) {
throw errors::type_parsing_error(this->type->get_name(), std::string(begin, end), parse_end - begin, "unexpected input");
}
std::vector<T> val_vec{};
if (val.has_value()) {
val_vec = std::any_cast<std::vector<T>>(val);
}
val_vec.push_back(single_val);
val = std::make_any<std::vector<T>>(val_vec);
}
type_handle_impl<T> type;
std::optional<std::vector<T>> default_value_ = std::nullopt;
std::optional<unsigned int> min_ = std::nullopt;
std::optional<unsigned int> max_ = std::nullopt;
};
template<typename T>
using repeatable_option_handle_impl = std::shared_ptr<repeatable_option_impl<T>>;
}// namespace argparser
#endif//ARGPARSER_REPEAT_OPT_H