command_line: allow args to depend on more than one args

This commit is contained in:
stoffu 2018-03-04 17:08:42 +09:00
parent 55f8d917fd
commit cc9a0bee04
No known key found for this signature in database
GPG Key ID: 41DAB8343A9EC012
1 changed files with 57 additions and 9 deletions

View File

@ -33,6 +33,7 @@
#include <functional> #include <functional>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <array>
#include <type_traits> #include <type_traits>
#include <boost/program_options/parsers.hpp> #include <boost/program_options/parsers.hpp>
@ -48,7 +49,7 @@ namespace command_line
//! \return True if `str` is `is_iequal("n" || "no" || `tr("no"))`. //! \return True if `str` is `is_iequal("n" || "no" || `tr("no"))`.
bool is_no(const std::string& str); bool is_no(const std::string& str);
template<typename T, bool required = false, bool dependent = false> template<typename T, bool required = false, bool dependent = false, int NUM_DEPS = 1>
struct arg_descriptor; struct arg_descriptor;
template<typename T> template<typename T>
@ -98,6 +99,22 @@ namespace command_line
bool not_use_default; bool not_use_default;
}; };
template<typename T, int NUM_DEPS>
struct arg_descriptor<T, false, true, NUM_DEPS>
{
typedef T value_type;
const char* name;
const char* description;
T default_value;
std::array<const arg_descriptor<bool, false> *, NUM_DEPS> ref;
std::function<T(std::array<bool, NUM_DEPS>, bool, T)> depf;
bool not_use_default;
};
template<typename T> template<typename T>
boost::program_options::typed_value<T, char>* make_semantic(const arg_descriptor<T, true>& /*arg*/) boost::program_options::typed_value<T, char>* make_semantic(const arg_descriptor<T, true>& /*arg*/)
{ {
@ -127,6 +144,28 @@ namespace command_line
return semantic; return semantic;
} }
template<typename T, int NUM_DEPS>
boost::program_options::typed_value<T, char>* make_semantic(const arg_descriptor<T, false, true, NUM_DEPS>& arg)
{
auto semantic = boost::program_options::value<T>();
if (!arg.not_use_default) {
std::array<bool, NUM_DEPS> depval;
depval.fill(false);
std::ostringstream format;
format << arg.depf(depval, true, arg.default_value);
for (size_t i = 0; i < depval.size(); ++i)
{
depval.fill(false);
depval[i] = true;
format << ", " << arg.depf(depval, true, arg.default_value) << " if '" << arg.ref[i]->name << "'";
}
for (size_t i = 0; i < depval.size(); ++i)
depval[i] = arg.ref[i]->default_value;
semantic->default_value(arg.depf(depval, true, arg.default_value), format.str());
}
return semantic;
}
template<typename T> template<typename T>
boost::program_options::typed_value<T, char>* make_semantic(const arg_descriptor<T, false>& arg, const T& def) boost::program_options::typed_value<T, char>* make_semantic(const arg_descriptor<T, false>& arg, const T& def)
{ {
@ -144,8 +183,8 @@ namespace command_line
return semantic; return semantic;
} }
template<typename T, bool required, bool dependent> template<typename T, bool required, bool dependent, int NUM_DEPS>
void add_arg(boost::program_options::options_description& description, const arg_descriptor<T, required, dependent>& arg, bool unique = true) void add_arg(boost::program_options::options_description& description, const arg_descriptor<T, required, dependent, NUM_DEPS>& arg, bool unique = true)
{ {
if (0 != description.find_nothrow(arg.name, false)) if (0 != description.find_nothrow(arg.name, false))
{ {
@ -214,15 +253,15 @@ namespace command_line
} }
} }
template<typename T, bool required, bool dependent> template<typename T, bool required, bool dependent, int NUM_DEPS>
typename std::enable_if<!std::is_same<T, bool>::value, bool>::type has_arg(const boost::program_options::variables_map& vm, const arg_descriptor<T, required, dependent>& arg) typename std::enable_if<!std::is_same<T, bool>::value, bool>::type has_arg(const boost::program_options::variables_map& vm, const arg_descriptor<T, required, dependent, NUM_DEPS>& arg)
{ {
auto value = vm[arg.name]; auto value = vm[arg.name];
return !value.empty(); return !value.empty();
} }
template<typename T, bool required, bool dependent> template<typename T, bool required, bool dependent, int NUM_DEPS>
bool is_arg_defaulted(const boost::program_options::variables_map& vm, const arg_descriptor<T, required, dependent>& arg) bool is_arg_defaulted(const boost::program_options::variables_map& vm, const arg_descriptor<T, required, dependent, NUM_DEPS>& arg)
{ {
return vm[arg.name].defaulted(); return vm[arg.name].defaulted();
} }
@ -233,14 +272,23 @@ namespace command_line
return arg.depf(get_arg(vm, arg.ref), is_arg_defaulted(vm, arg), vm[arg.name].template as<T>()); return arg.depf(get_arg(vm, arg.ref), is_arg_defaulted(vm, arg), vm[arg.name].template as<T>());
} }
template<typename T, int NUM_DEPS>
T get_arg(const boost::program_options::variables_map& vm, const arg_descriptor<T, false, true, NUM_DEPS>& arg)
{
std::array<bool, NUM_DEPS> depval;
for (size_t i = 0; i < depval.size(); ++i)
depval[i] = get_arg(vm, *arg.ref[i]);
return arg.depf(depval, is_arg_defaulted(vm, arg), vm[arg.name].template as<T>());
}
template<typename T, bool required> template<typename T, bool required>
T get_arg(const boost::program_options::variables_map& vm, const arg_descriptor<T, required>& arg) T get_arg(const boost::program_options::variables_map& vm, const arg_descriptor<T, required>& arg)
{ {
return vm[arg.name].template as<T>(); return vm[arg.name].template as<T>();
} }
template<bool dependent> template<bool dependent, int NUM_DEPS>
inline bool has_arg(const boost::program_options::variables_map& vm, const arg_descriptor<bool, false, dependent>& arg) inline bool has_arg(const boost::program_options::variables_map& vm, const arg_descriptor<bool, false, dependent, NUM_DEPS>& arg)
{ {
return get_arg(vm, arg); return get_arg(vm, arg);
} }