3#include <boost/program_options.hpp>
7#include <unordered_map>
12 namespace po = boost::program_options;
25 template <
typename T,
typename =
void>
31 struct IsString<T, std::void_t<decltype(std::string_view{ std::declval<T>() })>> : std::true_type
39 template <
typename Type>
42 template <
typename Type>
54 template <
typename OptionType>
56 const std::string& option_desc,
57 std::optional<OptionType> defaultValue = {}) ->
decltype(
auto)
59 if (
auto search = registries_.find(optionName); search != registries_.end())
61 std::cerr <<
"ERROR: option has been already defined!" << std::endl;
64 auto option = std::make_unique<Option<OptionType>>(optionName, defaultValue.value_or(OptionType{}),
this);
65 option->add(option_desc, not defaultValue.has_value());
66 registries_.emplace(optionName, option.get());
67 return OptionHandle{ std::move(option) };
70 auto verify(
int argc,
char** argv) -> bool;
71 void delete_option(
const std::string& optionName) { registries_.erase(optionName); }
76 std::unordered_map<std::string, OptionConcept*> registries_;
77 po::positional_options_description pos_desc_;
78 po::options_description desc_;
79 po::variables_map varMap_;
91 virtual void retrieve(
const po::variables_map& varMap) = 0;
94 template <
typename Type>
104 : name_{ std::move(name) }
105 , value_{ std::move(defaultValue) }
106 , program_{ program }
108 if (
auto end = name_.find(
','))
110 key_ = name_.substr(0, end);
117 ~Option()
override { program_->delete_option(name_); }
119 void add(
const std::string& desc,
bool is_requried =
false)
121 auto& po_desc = program_->get_desc_ref();
122 is_required_ = is_requried;
124 auto desc_full = fmt::format(
"{} [ required ]", desc);
125 if (not is_required_)
127 desc_full = fmt::format(
"{} [ = {} ]", desc, value_);
130 desc_full = fmt::format(
"{} [ = {:?} ]", desc, value_);
136 po_desc.add_options()(name_.c_str(), desc_full.c_str());
140 po_desc.add_options()(name_.c_str(), po::value<Type>(), desc_full.c_str());
146 program_->get_posDescRef().add(key_.c_str(), option);
147 is_positional_ =
true;
150 void retrieve(
const po::variables_map& varMap)
override
152 if (varMap.count(key_) != 0U)
161 value_ = varMap[key_].template as<Type>();
164 else if (is_required_)
166 const auto error_msg = fmt::format(R
"(Program option "--{}" is required! )", name_);
167 throw std::runtime_error(error_msg);
173 [[nodiscard]]
auto value()
const {
return value_; }
174 [[nodiscard]]
auto is_required() const ->
bool {
return is_required_; }
178 bool is_positional_ =
false;
179 bool is_required_ =
false;
184 ProgramOptions* program_;
187 template <
typename Type>
192 : option_{ std::move(option) }
196 auto value()
const {
return option_->value(); }
200 option_->as_positional(pos);
201 return std::move(*
this);
206 std::unique_ptr<Option<Type>> option_ =
nullptr;
auto operator=(const OptionConcept &) -> OptionConcept &=delete
virtual ~OptionConcept()=default
OptionConcept(OptionConcept &&)=delete
OptionConcept(const OptionConcept &)=delete
virtual void retrieve(const po::variables_map &varMap)=0
auto operator=(OptionConcept &&) -> OptionConcept &=delete
auto operator->() -> Option< Type > *
auto make_positional(int pos) -> OptionHandle< Type > &&
OptionHandle(std::unique_ptr< Option< Type > > option)
void add(const std::string &desc, bool is_requried=false)
Option(const Option &)=delete
auto is_positional() const -> bool
auto operator=(Option &&) -> Option &=delete
void set_required(bool p_rq=true)
auto operator=(const Option &) -> Option &=delete
auto is_required() const -> bool
void retrieve(const po::variables_map &varMap) override
void as_positional(int option)
Option(std::string name, Type defaultValue, ProgramOptions *program)
auto get_desc_ref() -> auto &
ProgramOptions(const std::string &desc)
auto get_posDescRef() -> auto &
auto verify(int argc, char **argv) -> bool
void delete_option(const std::string &optionName)
auto create_option(const std::string &optionName, const std::string &option_desc, std::optional< OptionType > defaultValue={}) -> decltype(auto)
constexpr bool IsString_v