mirror of
https://github.com/CLIUtils/CLI11.git
synced 2025-04-30 04:33:53 +00:00
Adding better vector check
This commit is contained in:
parent
324a9c738d
commit
68e86a8085
@ -63,6 +63,17 @@ using std::enable_if_t;
|
||||
#endif
|
||||
// If your compiler supports C++14, you can use that definition instead
|
||||
|
||||
template <typename T>
|
||||
struct is_vector {
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
|
||||
template<class T, class A>
|
||||
struct is_vector<std::vector<T, A> > {
|
||||
static bool const value = true;
|
||||
};
|
||||
|
||||
struct Combiner {
|
||||
int num;
|
||||
bool positional;
|
||||
@ -366,7 +377,20 @@ bool lexical_cast(std::string input, T& output) {
|
||||
|
||||
// String and similar
|
||||
template<typename T,
|
||||
enable_if_t<!std::is_floating_point<T>::value && !std::is_integral<T>::value, detail::enabler> = dummy>
|
||||
enable_if_t<is_vector<T>::value, detail::enabler> = dummy>
|
||||
bool lexical_cast(std::string input, T& output) {
|
||||
logit("vector lexical cast: " + input);
|
||||
if(output.size() == input.size())
|
||||
output.resize(input.size());
|
||||
for(size_t i=0; i<input.size(); i++)
|
||||
output[i] = input[i];
|
||||
return true;
|
||||
}
|
||||
|
||||
// String and similar
|
||||
template<typename T,
|
||||
enable_if_t<!std::is_floating_point<T>::value && !std::is_integral<T>::value && !is_vector<T>::value
|
||||
, detail::enabler> = dummy>
|
||||
bool lexical_cast(std::string input, T& output) {
|
||||
logit("Direct lexical cast: " + input);
|
||||
output = input;
|
||||
@ -483,7 +507,7 @@ public:
|
||||
}
|
||||
|
||||
/// Add option for string
|
||||
template<typename T, enable_if_t<!std::is_array<T>::value, detail::enabler> = dummy>
|
||||
template<typename T, enable_if_t<!is_vector<T>::value, detail::enabler> = dummy>
|
||||
Option* add_option(
|
||||
std::string name, ///< The name, long,short
|
||||
T &variable, ///< The variable to set
|
||||
@ -598,13 +622,16 @@ public:
|
||||
|
||||
/// Prototype for new output style
|
||||
template<typename T = std::string,
|
||||
enable_if_t<!std::is_array<T>::value, detail::enabler> = dummy>
|
||||
enable_if_t<!is_vector<T>::value, detail::enabler> = dummy>
|
||||
Value<T> make_option(
|
||||
std::string name, ///< The name, short,long
|
||||
std::string discription="",
|
||||
Combiner opts=VALIDATORS
|
||||
) {
|
||||
|
||||
if(opts.num!=1)
|
||||
throw IncorrectConstruction("Must have ARGS(1).");
|
||||
|
||||
Value<T> out(name);
|
||||
std::shared_ptr<std::unique_ptr<T>> ptr = out.value;
|
||||
|
||||
@ -623,8 +650,8 @@ public:
|
||||
}
|
||||
|
||||
/// Prototype for new output style with default
|
||||
template<typename T = std::string,
|
||||
enable_if_t<!std::is_array<T>::value, detail::enabler> = dummy>
|
||||
template<typename T,
|
||||
enable_if_t<!is_vector<T>::value, detail::enabler> = dummy>
|
||||
Value<T> make_option(
|
||||
std::string name, ///< The name, short,long
|
||||
const T& default_value,
|
||||
@ -632,6 +659,9 @@ public:
|
||||
Combiner opts=VALIDATORS
|
||||
) {
|
||||
|
||||
if(opts.num!=1)
|
||||
throw IncorrectConstruction("Must have ARGS(1).");
|
||||
|
||||
Value<T> out(name);
|
||||
std::shared_ptr<std::unique_ptr<T>> ptr = out.value;
|
||||
ptr->reset(new T(default_value)); // resets the internal ptr
|
||||
@ -650,9 +680,10 @@ public:
|
||||
return out;
|
||||
}
|
||||
|
||||
/// Prototype for new output style
|
||||
template<typename T>
|
||||
Value<std::vector<T>> make_option(
|
||||
/// Prototype for new output style, vector
|
||||
template<typename T,
|
||||
enable_if_t<is_vector<T>::value, detail::enabler> = dummy>
|
||||
Value<T> make_option(
|
||||
std::string name, ///< The name, short,long
|
||||
std::string discription="",
|
||||
Combiner opts=VALIDATORS
|
||||
@ -661,11 +692,11 @@ public:
|
||||
if(opts.num==0)
|
||||
throw IncorrectConstruction("Must have ARGS or be a vector.");
|
||||
|
||||
Value<std::vector<T>> out(name);
|
||||
std::shared_ptr<std::unique_ptr<std::vector<T> >> ptr = out.value;
|
||||
Value<T> out(name);
|
||||
std::shared_ptr<std::unique_ptr<T>> ptr = out.value;
|
||||
|
||||
CLI::callback_t fun = [ptr](CLI::results_t res){
|
||||
ptr->reset(new std::vector<T>()); // resets the internal ptr
|
||||
ptr->reset(new T()); // resets the internal ptr
|
||||
bool retval = true;
|
||||
for(const auto &a : res)
|
||||
for(const auto &b : a) {
|
||||
@ -841,23 +872,17 @@ public:
|
||||
|
||||
|
||||
if(num == -1) {
|
||||
std::string current = args.back();
|
||||
while(_recognize(current) == Classifer::NONE) {
|
||||
std::string current = args.back();
|
||||
while(args.size()>0 && _recognize(args.back()) == Classifer::NONE) {
|
||||
op->add_result(vnum, args.back());
|
||||
args.pop_back();
|
||||
op->add_result(vnum,current);
|
||||
if(args.size()==0)
|
||||
return;
|
||||
|
||||
}
|
||||
} else while(num>0) {
|
||||
} else while(num>0 && args.size() > 0) {
|
||||
num--;
|
||||
std::string current = args.back();
|
||||
logit("Adding: "+current);
|
||||
args.pop_back();
|
||||
op->add_result(vnum,current);
|
||||
if(args.size()==0)
|
||||
return;
|
||||
}
|
||||
|
||||
if(rest != "") {
|
||||
@ -916,22 +941,14 @@ public:
|
||||
}
|
||||
|
||||
if(num == -1) {
|
||||
std::string current = args.back();
|
||||
while(_recognize(current) == Classifer::NONE) {
|
||||
std::string current = args.back();
|
||||
while(args.size() > 0 && _recognize(args.back()) == Classifer::NONE) {
|
||||
op->add_result(vnum, args.back());
|
||||
args.pop_back();
|
||||
op->add_result(vnum,current);
|
||||
if(args.size()==0)
|
||||
return;
|
||||
|
||||
}
|
||||
} else while(num>0) {
|
||||
} else while(num>0 && args.size()>0) {
|
||||
num--;
|
||||
std::string current = args.back();
|
||||
op->add_result(vnum,args.back());
|
||||
args.pop_back();
|
||||
op->add_result(vnum,current);
|
||||
if(args.size()==0)
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -382,9 +382,64 @@ TEST_F(TAppValue, OneString) {
|
||||
|
||||
}
|
||||
|
||||
TEST_F(TAppValue, SeveralInts) {
|
||||
auto value = app.make_option<int>("first");
|
||||
CLI::Value<int> value2 = app.make_option<int>("s");
|
||||
int v;
|
||||
args = {"--first", "12", "-s", "19"};
|
||||
EXPECT_FALSE((bool) value);
|
||||
EXPECT_FALSE((bool) value2);
|
||||
|
||||
EXPECT_THROW(v = *value, CLI::EmptyError);
|
||||
//EXPECT_THROW(v = str, CLI::EmptyError);
|
||||
EXPECT_NO_THROW(run());
|
||||
EXPECT_TRUE((bool) value);
|
||||
EXPECT_NO_THROW(v = *value);
|
||||
EXPECT_NO_THROW(v = value);
|
||||
|
||||
EXPECT_EQ(1, app.count("s"));
|
||||
EXPECT_EQ(1, app.count("first"));
|
||||
EXPECT_EQ(*value, 12);
|
||||
EXPECT_EQ(*value2, 19);
|
||||
|
||||
}
|
||||
|
||||
TEST_F(TAppValue, Vector) {
|
||||
auto value = app.make_option<std::vector<int>>("first", "", CLI::ARGS);
|
||||
auto value2 = app.make_option<std::vector<std::string>>("second", "", CLI::ARGS);
|
||||
|
||||
std::vector<int> i;
|
||||
std::vector<std::string> s;
|
||||
|
||||
args = {"--first", "12", "3", "9", "--second", "thing", "try"};
|
||||
|
||||
EXPECT_FALSE((bool) value);
|
||||
EXPECT_FALSE((bool) value2);
|
||||
|
||||
EXPECT_THROW(i = *value, CLI::EmptyError);
|
||||
EXPECT_THROW(s = *value2, CLI::EmptyError);
|
||||
|
||||
EXPECT_NO_THROW(run());
|
||||
|
||||
EXPECT_TRUE((bool) value);
|
||||
EXPECT_TRUE((bool) value2);
|
||||
|
||||
EXPECT_NO_THROW(i = *value);
|
||||
//EXPECT_NO_THROW(i = value);
|
||||
|
||||
EXPECT_NO_THROW(s = *value2);
|
||||
//EXPECT_NO_THROW(s = value2);
|
||||
|
||||
EXPECT_EQ(3, app.count("first"));
|
||||
EXPECT_EQ(2, app.count("second"));
|
||||
|
||||
EXPECT_EQ(*value, std::vector<int>({12,3,9}));
|
||||
EXPECT_EQ(*value2, std::vector<std::string>({"thing", "try"}));
|
||||
|
||||
}
|
||||
|
||||
// TODO: Maybe add function to call on subcommand parse? Stashed.
|
||||
// TODO: Check help output
|
||||
// TODO: Add default/type info to help
|
||||
// TODO: Add set checking
|
||||
// TODO: Try all of the options together
|
||||
// TODO: Add make_option alternative with type? Cancelled for now
|
||||
|
Loading…
x
Reference in New Issue
Block a user