Commit 84add337bb66c29f792a6ab75c8aa919ed3ab71b

Authored by Henry Fredrick Schreiner
1 parent e870e264

Remove double vector parse

CHANGELOG.md
1 ## Version 0.6 1 ## Version 0.6
2 2
  3 +* Simplified parsing to use `vector<string>` only
3 * Fixed fallthrough, made it optional as well (default: off): `.fallthrough()`. 4 * Fixed fallthrough, made it optional as well (default: off): `.fallthrough()`.
4 * Added string versions of `->requires()` and `->excludes()` for consistency. 5 * Added string versions of `->requires()` and `->excludes()` for consistency.
5 * Renamed protected members for internal consistency, grouped docs. 6 * Renamed protected members for internal consistency, grouped docs.
README.md
@@ -41,7 +41,6 @@ This library was built to supply the Application object for the GooFit CUDA/OMP @@ -41,7 +41,6 @@ This library was built to supply the Application object for the GooFit CUDA/OMP
41 * Ini configuration support is basic (long options only, no vector support), is more needed? Could it be tied to the subcommand system? 41 * Ini configuration support is basic (long options only, no vector support), is more needed? Could it be tied to the subcommand system?
42 * Evaluate compatibility with [ROOT](https://root.cern.ch)'s TApplication object. 42 * Evaluate compatibility with [ROOT](https://root.cern.ch)'s TApplication object.
43 * Test "adding to cmake" method 43 * Test "adding to cmake" method
44 -* Maybe simplify the `vector<vector>` structure of options, it is more powerful but unlikely to be needed.  
45 44
46 See the [changelog](./CHANGELOG.md) or [GitHub releases](https://github.com/henryiii/CLI11/releases) for details. 45 See the [changelog](./CHANGELOG.md) or [GitHub releases](https://github.com/henryiii/CLI11/releases) for details.
47 46
@@ -117,7 +116,6 @@ app.add_config(option_name, @@ -117,7 +116,6 @@ app.add_config(option_name,
117 required=false) 116 required=false)
118 117
119 App* subcom = app.add_subcommand(name, discription); 118 App* subcom = app.add_subcommand(name, discription);
120 -  
121 ``` 119 ```
122 120
123 An option name must start with a alphabetic character or underscore. For long options, anything but an equals sign or a comma is valid after that. Names are given as a comma separated string, with the dash or dashes. An option or flag can have as many names as you want, and afterward, using `count`, you can use any of the names, with dashes as needed, to count the options. One of the names is allowed to be given without proceeding dash(es); if present the option is a positional option, and that name will be used on help line for its positional form. If you want the default value to print in the help description, pass in `true` for the final parameter for `add_option` or `add_set`. 121 An option name must start with a alphabetic character or underscore. For long options, anything but an equals sign or a comma is valid after that. Names are given as a comma separated string, with the dash or dashes. An option or flag can have as many names as you want, and afterward, using `count`, you can use any of the names, with dashes as needed, to count the options. One of the names is allowed to be given without proceeding dash(es); if present the option is a positional option, and that name will be used on help line for its positional form. If you want the default value to print in the help description, pass in `true` for the final parameter for `add_option` or `add_set`.
@@ -145,7 +143,7 @@ The add commands return a pointer to an internally stored `Option`. If you set t @@ -145,7 +143,7 @@ The add commands return a pointer to an internally stored `Option`. If you set t
145 * `->check(CLI::NonexistentPath)`: Requires that the path does not exist. 143 * `->check(CLI::NonexistentPath)`: Requires that the path does not exist.
146 * `->check(CLI::Range(min,max))`: Requires that the option be between min and max (make sure to use floating point if needed). Min defaults to 0. 144 * `->check(CLI::Range(min,max))`: Requires that the option be between min and max (make sure to use floating point if needed). Min defaults to 0.
147 145
148 -These options return the `Option` pointer, so you can chain them together, and even skip storing the pointer entirely. Check takes any function that has the signature `bool(std::string)`. If you want to change the default help option, it is available through `get_help_ptr`. 146 +These options return the `Option` pointer, so you can chain them together, and even skip storing the pointer entirely. Check takes any function that has the signature `bool(std::string)`. If you want to change the default help option, it is available through `get_help_ptr`. If you just want to see the unconverted values, use `.results()` to get the `std::vector<std::string>` of results.
149 147
150 148
151 On the command line, options can be given as: 149 On the command line, options can be given as:
@@ -201,17 +199,16 @@ Also, in a related note, the `App` you get a pointer to is stored in the parent @@ -201,17 +199,16 @@ Also, in a related note, the `App` you get a pointer to is stored in the parent
201 199
202 ## How it works 200 ## How it works
203 201
204 -Every `add_` option you have seen so far depends on one method that takes a lambda function. Each of these methods is just making a different lambda function with capture to populate the option. The function has full access to the vector of vector of strings, so it knows how many times an option was passed, and how many arguments each passing received (flags add empty strings to keep the counts correct). The lambda returns `true` if it could validate the option strings, and 202 +Every `add_` option you have seen so far depends on one method that takes a lambda function. Each of these methods is just making a different lambda function with capture to populate the option. The function has full access to the vector of strings, so it knows how many times an option was passed or how many arguments it recieved (flags add empty strings to keep the counts correct). The lambda returns `true` if it could validate the option strings, and
205 `false` if it failed. 203 `false` if it failed.
206 204
207 ### Example 205 ### Example
208 206
209 -~~~python  
210 -app.add_option("--fancy-count", [](std::vector<std::vector<std::string>> val){ 207 +```cpp
  208 +app.add_option("--fancy-count", [](std::vector<std::string> val){
211 std::cout << "This option was given " << val.size() << " times." << std::endl 209 std::cout << "This option was given " << val.size() << " times." << std::endl
212 - << "The first time, it received " << val.at(0).size() << " items" << std::endl;  
213 }); 210 });
214 -~~~ 211 +```
215 212
216 ## Contributing 213 ## Contributing
217 214
@@ -221,7 +218,7 @@ To contribute, open an [issue](https://github.com/henryiii/CLI11/issues) or [pul @@ -221,7 +218,7 @@ To contribute, open an [issue](https://github.com/henryiii/CLI11/issues) or [pul
221 218
222 If you use the [`rang`](https://github.com/agauniyal/rang/wiki) library to add color to your terminal in a safe, multi-platform way, you can combine it with CLI11 nicely: 219 If you use the [`rang`](https://github.com/agauniyal/rang/wiki) library to add color to your terminal in a safe, multi-platform way, you can combine it with CLI11 nicely:
223 220
224 -``` 221 +```cpp
225 std::atexit([](){std::cout << rang::style::reset;}); 222 std::atexit([](){std::cout << rang::style::reset;});
226 try { 223 try {
227 app.parse(argc, argv); 224 app.parse(argc, argv);
include/CLI/App.hpp
@@ -227,13 +227,9 @@ public: @@ -227,13 +227,9 @@ public:
227 227
228 228
229 CLI::callback_t fun = [&variable](CLI::results_t res){ 229 CLI::callback_t fun = [&variable](CLI::results_t res){
230 - if(res.size()!=1) {  
231 - return false;  
232 - }  
233 - if(res[0].size()!=1) { 230 + if(res.size()!=1)
234 return false; 231 return false;
235 - }  
236 - return detail::lexical_cast(res[0][0], variable); 232 + return detail::lexical_cast(res[0], variable);
237 }; 233 };
238 234
239 Option* opt = add_option(name, fun, description, defaulted); 235 Option* opt = add_option(name, fun, description, defaulted);
@@ -258,11 +254,10 @@ public: @@ -258,11 +254,10 @@ public:
258 CLI::callback_t fun = [&variable](CLI::results_t res){ 254 CLI::callback_t fun = [&variable](CLI::results_t res){
259 bool retval = true; 255 bool retval = true;
260 variable.clear(); 256 variable.clear();
261 - for(const auto &a : res)  
262 - for(const auto &b : a) {  
263 - variable.emplace_back();  
264 - retval &= detail::lexical_cast(b, variable.back());  
265 - } 257 + for(const auto &a : res) {
  258 + variable.emplace_back();
  259 + retval &= detail::lexical_cast(a, variable.back());
  260 + }
266 return variable.size() > 0 && retval; 261 return variable.size() > 0 && retval;
267 }; 262 };
268 263
@@ -291,7 +286,7 @@ public: @@ -291,7 +286,7 @@ public:
291 return opt; 286 return opt;
292 } 287 }
293 288
294 - /// Add option for flag 289 + /// Add option for flag integer
295 template<typename T, 290 template<typename T,
296 enable_if_t<std::is_integral<T>::value && !is_bool<T>::value, detail::enabler> = detail::dummy> 291 enable_if_t<std::is_integral<T>::value && !is_bool<T>::value, detail::enabler> = detail::dummy>
297 Option* add_flag( 292 Option* add_flag(
@@ -350,10 +345,7 @@ public: @@ -350,10 +345,7 @@ public:
350 if(res.size()!=1) { 345 if(res.size()!=1) {
351 return false; 346 return false;
352 } 347 }
353 - if(res[0].size()!=1) {  
354 - return false;  
355 - }  
356 - bool retval = detail::lexical_cast(res[0][0], member); 348 + bool retval = detail::lexical_cast(res[0], member);
357 if(!retval) 349 if(!retval)
358 return false; 350 return false;
359 return std::find(std::begin(options), std::end(options), member) != std::end(options); 351 return std::find(std::begin(options), std::end(options), member) != std::end(options);
@@ -383,10 +375,7 @@ public: @@ -383,10 +375,7 @@ public:
383 if(res.size()!=1) { 375 if(res.size()!=1) {
384 return false; 376 return false;
385 } 377 }
386 - if(res[0].size()!=1) {  
387 - return false;  
388 - }  
389 - member = detail::to_lower(res.at(0).at(0)); 378 + member = detail::to_lower(res[0]);
390 auto iter = std::find_if(std::begin(options), std::end(options), 379 auto iter = std::find_if(std::begin(options), std::end(options),
391 [&member](std::string val){return detail::to_lower(val) == member;}); 380 [&member](std::string val){return detail::to_lower(val) == member;});
392 if(iter == std::end(options)) 381 if(iter == std::end(options))
@@ -558,7 +547,7 @@ public: @@ -558,7 +547,7 @@ public:
558 std::stringstream out; 547 std::stringstream out;
559 for(const Option_p &opt : options_) { 548 for(const Option_p &opt : options_) {
560 if(opt->lnames_.size() > 0 && opt->count() > 0 && opt->get_expected() > 0) 549 if(opt->lnames_.size() > 0 && opt->count() > 0 && opt->get_expected() > 0)
561 - out << opt->lnames_[0] << "=" << detail::join(opt->flatten_results()) << std::endl; 550 + out << opt->lnames_[0] << "=" << detail::join(opt->results()) << std::endl;
562 } 551 }
563 return out.str(); 552 return out.str();
564 } 553 }
@@ -763,8 +752,7 @@ protected: @@ -763,8 +752,7 @@ protected:
763 if (opt->count() == 0 && opt->envname_ != "") { 752 if (opt->count() == 0 && opt->envname_ != "") {
764 char *ename = std::getenv(opt->envname_.c_str()); 753 char *ename = std::getenv(opt->envname_.c_str());
765 if(ename != nullptr) { 754 if(ename != nullptr) {
766 - opt->get_new();  
767 - opt->add_result(0, std::string(ename)); 755 + opt->add_result(std::string(ename));
768 } 756 }
769 } 757 }
770 } 758 }
@@ -851,8 +839,7 @@ protected: @@ -851,8 +839,7 @@ protected:
851 && opt->count() < opt->get_expected() 839 && opt->count() < opt->get_expected()
852 ) { 840 ) {
853 841
854 - opt->get_new();  
855 - opt->add_result(0, positional); 842 + opt->add_result(positional);
856 args.pop_back(); 843 args.pop_back();
857 return; 844 return;
858 } 845 }
@@ -915,29 +902,28 @@ protected: @@ -915,29 +902,28 @@ protected:
915 // Get a reference to the pointer to make syntax bearable 902 // Get a reference to the pointer to make syntax bearable
916 Option_p& op = *op_ptr; 903 Option_p& op = *op_ptr;
917 904
918 - int vnum = op->get_new();  
919 int num = op->get_expected(); 905 int num = op->get_expected();
920 906
921 if(num == 0) 907 if(num == 0)
922 - op->add_result(vnum, ""); 908 + op->add_result("");
923 else if(rest!="") { 909 else if(rest!="") {
924 if (num > 0) 910 if (num > 0)
925 num--; 911 num--;
926 - op->add_result(vnum, rest); 912 + op->add_result(rest);
927 rest = ""; 913 rest = "";
928 } 914 }
929 915
930 916
931 if(num == -1) { 917 if(num == -1) {
932 while(args.size()>0 && _recognize(args.back()) == detail::Classifer::NONE) { 918 while(args.size()>0 && _recognize(args.back()) == detail::Classifer::NONE) {
933 - op->add_result(vnum, args.back()); 919 + op->add_result(args.back());
934 args.pop_back(); 920 args.pop_back();
935 } 921 }
936 } else while(num>0 && args.size() > 0) { 922 } else while(num>0 && args.size() > 0) {
937 num--; 923 num--;
938 std::string current_ = args.back(); 924 std::string current_ = args.back();
939 args.pop_back(); 925 args.pop_back();
940 - op->add_result(vnum, current_); 926 + op->add_result(current_);
941 } 927 }
942 928
943 if(rest != "") { 929 if(rest != "") {
@@ -980,25 +966,23 @@ protected: @@ -980,25 +966,23 @@ protected:
980 if(!overwrite && op->count() > 0) 966 if(!overwrite && op->count() > 0)
981 return; 967 return;
982 968
983 - int vnum = op->get_new();  
984 int num = op->get_expected(); 969 int num = op->get_expected();
985 970
986 -  
987 if(value != "") { 971 if(value != "") {
988 if(num!=-1) num--; 972 if(num!=-1) num--;
989 - op->add_result(vnum, value); 973 + op->add_result(value);
990 } else if (num == 0) { 974 } else if (num == 0) {
991 - op->add_result(vnum, ""); 975 + op->add_result("");
992 } 976 }
993 977
994 if(num == -1) { 978 if(num == -1) {
995 while(args.size() > 0 && _recognize(args.back()) == detail::Classifer::NONE) { 979 while(args.size() > 0 && _recognize(args.back()) == detail::Classifer::NONE) {
996 - op->add_result(vnum, args.back()); 980 + op->add_result(args.back());
997 args.pop_back(); 981 args.pop_back();
998 } 982 }
999 } else while(num>0 && args.size()>0) { 983 } else while(num>0 && args.size()>0) {
1000 num--; 984 num--;
1001 - op->add_result(vnum,args.back()); 985 + op->add_result(args.back());
1002 args.pop_back(); 986 args.pop_back();
1003 } 987 }
1004 return; 988 return;
include/CLI/Option.hpp
@@ -17,7 +17,7 @@ @@ -17,7 +17,7 @@
17 17
18 namespace CLI { 18 namespace CLI {
19 19
20 -typedef std::vector<std::vector<std::string>> results_t; 20 +typedef std::vector<std::string> results_t;
21 typedef std::function<bool(results_t)> callback_t; 21 typedef std::function<bool(results_t)> callback_t;
22 22
23 class Option; 23 class Option;
@@ -121,16 +121,13 @@ public: @@ -121,16 +121,13 @@ public:
121 121
122 /// Count the total number of times an option was passed 122 /// Count the total number of times an option was passed
123 int count() const { 123 int count() const {
124 - int out = 0;  
125 - for(const std::vector<std::string>& vec : results_)  
126 - out += vec.size();  
127 - return out; 124 + return results_.size();
128 } 125 }
129 126
130 127
131 /// This class is true if option is passed. 128 /// This class is true if option is passed.
132 operator bool() const { 129 operator bool() const {
133 - return results_.size() > 0; 130 + return count() > 0;
134 } 131 }
135 132
136 /// Clear the parsed results (mostly for testing) 133 /// Clear the parsed results (mostly for testing)
@@ -372,9 +369,9 @@ public: @@ -372,9 +369,9 @@ public:
372 /// Process the callback 369 /// Process the callback
373 void run_callback() const { 370 void run_callback() const {
374 if(!callback_(results_)) 371 if(!callback_(results_))
375 - throw ConversionError(get_name() + "=" + detail::join(flatten_results())); 372 + throw ConversionError(get_name() + "=" + detail::join(results_));
376 if(validators_.size()>0) { 373 if(validators_.size()>0) {
377 - for(const std::string & result : flatten_results()) 374 + for(const std::string & result : results_)
378 for(const std::function<bool(std::string)> &vali : validators_) 375 for(const std::function<bool(std::string)> &vali : validators_)
379 if(!vali(result)) 376 if(!vali(result))
380 throw ValidationError(get_name() + "=" + result); 377 throw ValidationError(get_name() + "=" + result);
@@ -440,23 +437,14 @@ public: @@ -440,23 +437,14 @@ public:
440 437
441 438
442 /// Puts a result at position r 439 /// Puts a result at position r
443 - void add_result(int r, std::string s) {  
444 - results_.at(r).push_back(s);  
445 - }  
446 -  
447 - /// Starts a new results vector (used for r in add_result)  
448 - int get_new() {  
449 - results_.emplace_back();  
450 - return results_.size() - 1; 440 + void add_result(std::string s) {
  441 + results_.push_back(s);
451 } 442 }
452 443
453 444
454 - /// Produce a flattened vector of results, vs. a vector of vectors.  
455 - std::vector<std::string> flatten_results() const {  
456 - std::vector<std::string> output;  
457 - for(const std::vector<std::string> result : results_)  
458 - output.insert(std::end(output), std::begin(result), std::end(result));  
459 - return output; 445 + /// Get a copy of the results
  446 + std::vector<std::string> results() const {
  447 + return results_;
460 } 448 }
461 449
462 ///@} 450 ///@}