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
|
#endif
|
||||||
// If your compiler supports C++14, you can use that definition instead
|
// 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 {
|
struct Combiner {
|
||||||
int num;
|
int num;
|
||||||
bool positional;
|
bool positional;
|
||||||
@ -366,7 +377,20 @@ bool lexical_cast(std::string input, T& output) {
|
|||||||
|
|
||||||
// String and similar
|
// String and similar
|
||||||
template<typename T,
|
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) {
|
bool lexical_cast(std::string input, T& output) {
|
||||||
logit("Direct lexical cast: " + input);
|
logit("Direct lexical cast: " + input);
|
||||||
output = input;
|
output = input;
|
||||||
@ -483,7 +507,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Add option for string
|
/// 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(
|
Option* add_option(
|
||||||
std::string name, ///< The name, long,short
|
std::string name, ///< The name, long,short
|
||||||
T &variable, ///< The variable to set
|
T &variable, ///< The variable to set
|
||||||
@ -598,13 +622,16 @@ public:
|
|||||||
|
|
||||||
/// Prototype for new output style
|
/// Prototype for new output style
|
||||||
template<typename T = std::string,
|
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(
|
Value<T> make_option(
|
||||||
std::string name, ///< The name, short,long
|
std::string name, ///< The name, short,long
|
||||||
std::string discription="",
|
std::string discription="",
|
||||||
Combiner opts=VALIDATORS
|
Combiner opts=VALIDATORS
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
if(opts.num!=1)
|
||||||
|
throw IncorrectConstruction("Must have ARGS(1).");
|
||||||
|
|
||||||
Value<T> out(name);
|
Value<T> out(name);
|
||||||
std::shared_ptr<std::unique_ptr<T>> ptr = out.value;
|
std::shared_ptr<std::unique_ptr<T>> ptr = out.value;
|
||||||
|
|
||||||
@ -623,8 +650,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Prototype for new output style with default
|
/// Prototype for new output style with default
|
||||||
template<typename T = std::string,
|
template<typename T,
|
||||||
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(
|
Value<T> make_option(
|
||||||
std::string name, ///< The name, short,long
|
std::string name, ///< The name, short,long
|
||||||
const T& default_value,
|
const T& default_value,
|
||||||
@ -632,6 +659,9 @@ public:
|
|||||||
Combiner opts=VALIDATORS
|
Combiner opts=VALIDATORS
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
if(opts.num!=1)
|
||||||
|
throw IncorrectConstruction("Must have ARGS(1).");
|
||||||
|
|
||||||
Value<T> out(name);
|
Value<T> out(name);
|
||||||
std::shared_ptr<std::unique_ptr<T>> ptr = out.value;
|
std::shared_ptr<std::unique_ptr<T>> ptr = out.value;
|
||||||
ptr->reset(new T(default_value)); // resets the internal ptr
|
ptr->reset(new T(default_value)); // resets the internal ptr
|
||||||
@ -650,9 +680,10 @@ public:
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prototype for new output style
|
/// Prototype for new output style, vector
|
||||||
template<typename T>
|
template<typename T,
|
||||||
Value<std::vector<T>> make_option(
|
enable_if_t<is_vector<T>::value, detail::enabler> = dummy>
|
||||||
|
Value<T> make_option(
|
||||||
std::string name, ///< The name, short,long
|
std::string name, ///< The name, short,long
|
||||||
std::string discription="",
|
std::string discription="",
|
||||||
Combiner opts=VALIDATORS
|
Combiner opts=VALIDATORS
|
||||||
@ -661,11 +692,11 @@ public:
|
|||||||
if(opts.num==0)
|
if(opts.num==0)
|
||||||
throw IncorrectConstruction("Must have ARGS or be a vector.");
|
throw IncorrectConstruction("Must have ARGS or be a vector.");
|
||||||
|
|
||||||
Value<std::vector<T>> out(name);
|
Value<T> out(name);
|
||||||
std::shared_ptr<std::unique_ptr<std::vector<T> >> ptr = out.value;
|
std::shared_ptr<std::unique_ptr<T>> ptr = out.value;
|
||||||
|
|
||||||
CLI::callback_t fun = [ptr](CLI::results_t res){
|
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;
|
bool retval = true;
|
||||||
for(const auto &a : res)
|
for(const auto &a : res)
|
||||||
for(const auto &b : a) {
|
for(const auto &b : a) {
|
||||||
@ -841,23 +872,17 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
if(num == -1) {
|
if(num == -1) {
|
||||||
std::string current = args.back();
|
while(args.size()>0 && _recognize(args.back()) == Classifer::NONE) {
|
||||||
while(_recognize(current) == Classifer::NONE) {
|
op->add_result(vnum, args.back());
|
||||||
std::string current = args.back();
|
|
||||||
args.pop_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--;
|
num--;
|
||||||
std::string current = args.back();
|
std::string current = args.back();
|
||||||
logit("Adding: "+current);
|
logit("Adding: "+current);
|
||||||
args.pop_back();
|
args.pop_back();
|
||||||
op->add_result(vnum,current);
|
op->add_result(vnum,current);
|
||||||
if(args.size()==0)
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(rest != "") {
|
if(rest != "") {
|
||||||
@ -916,22 +941,14 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(num == -1) {
|
if(num == -1) {
|
||||||
std::string current = args.back();
|
while(args.size() > 0 && _recognize(args.back()) == Classifer::NONE) {
|
||||||
while(_recognize(current) == Classifer::NONE) {
|
op->add_result(vnum, args.back());
|
||||||
std::string current = args.back();
|
|
||||||
args.pop_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--;
|
num--;
|
||||||
std::string current = args.back();
|
op->add_result(vnum,args.back());
|
||||||
args.pop_back();
|
args.pop_back();
|
||||||
op->add_result(vnum,current);
|
|
||||||
if(args.size()==0)
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
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: Maybe add function to call on subcommand parse? Stashed.
|
||||||
// TODO: Check help output
|
// TODO: Check help output
|
||||||
// TODO: Add default/type info to help
|
// TODO: Add default/type info to help
|
||||||
// TODO: Add set checking
|
// TODO: Add set checking
|
||||||
// TODO: Try all of the options together
|
// 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