Commit 84add337bb66c29f792a6ab75c8aa919ed3ab71b

Authored by Henry Fredrick Schreiner
1 parent e870e264

Remove double vector parse

CHANGELOG.md
1 1 ## Version 0.6
2 2  
  3 +* Simplified parsing to use `vector<string>` only
3 4 * Fixed fallthrough, made it optional as well (default: off): `.fallthrough()`.
4 5 * Added string versions of `->requires()` and `->excludes()` for consistency.
5 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 41 * Ini configuration support is basic (long options only, no vector support), is more needed? Could it be tied to the subcommand system?
42 42 * Evaluate compatibility with [ROOT](https://root.cern.ch)'s TApplication object.
43 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 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 116 required=false)
118 117  
119 118 App* subcom = app.add_subcommand(name, discription);
120   -
121 119 ```
122 120  
123 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 143 * `->check(CLI::NonexistentPath)`: Requires that the path does not exist.
146 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 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 199  
202 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 203 `false` if it failed.
206 204  
207 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 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 213 ## Contributing
217 214  
... ... @@ -221,7 +218,7 @@ To contribute, open an [issue](https://github.com/henryiii/CLI11/issues) or [pul
221 218  
222 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 222 std::atexit([](){std::cout << rang::style::reset;});
226 223 try {
227 224 app.parse(argc, argv);
... ...
include/CLI/App.hpp
... ... @@ -227,13 +227,9 @@ public:
227 227  
228 228  
229 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 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 235 Option* opt = add_option(name, fun, description, defaulted);
... ... @@ -258,11 +254,10 @@ public:
258 254 CLI::callback_t fun = [&variable](CLI::results_t res){
259 255 bool retval = true;
260 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 261 return variable.size() > 0 && retval;
267 262 };
268 263  
... ... @@ -291,7 +286,7 @@ public:
291 286 return opt;
292 287 }
293 288  
294   - /// Add option for flag
  289 + /// Add option for flag integer
295 290 template<typename T,
296 291 enable_if_t<std::is_integral<T>::value && !is_bool<T>::value, detail::enabler> = detail::dummy>
297 292 Option* add_flag(
... ... @@ -350,10 +345,7 @@ public:
350 345 if(res.size()!=1) {
351 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 349 if(!retval)
358 350 return false;
359 351 return std::find(std::begin(options), std::end(options), member) != std::end(options);
... ... @@ -383,10 +375,7 @@ public:
383 375 if(res.size()!=1) {
384 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 379 auto iter = std::find_if(std::begin(options), std::end(options),
391 380 [&member](std::string val){return detail::to_lower(val) == member;});
392 381 if(iter == std::end(options))
... ... @@ -558,7 +547,7 @@ public:
558 547 std::stringstream out;
559 548 for(const Option_p &opt : options_) {
560 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 552 return out.str();
564 553 }
... ... @@ -763,8 +752,7 @@ protected:
763 752 if (opt->count() == 0 && opt->envname_ != "") {
764 753 char *ename = std::getenv(opt->envname_.c_str());
765 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 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 843 args.pop_back();
857 844 return;
858 845 }
... ... @@ -915,29 +902,28 @@ protected:
915 902 // Get a reference to the pointer to make syntax bearable
916 903 Option_p& op = *op_ptr;
917 904  
918   - int vnum = op->get_new();
919 905 int num = op->get_expected();
920 906  
921 907 if(num == 0)
922   - op->add_result(vnum, "");
  908 + op->add_result("");
923 909 else if(rest!="") {
924 910 if (num > 0)
925 911 num--;
926   - op->add_result(vnum, rest);
  912 + op->add_result(rest);
927 913 rest = "";
928 914 }
929 915  
930 916  
931 917 if(num == -1) {
932 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 920 args.pop_back();
935 921 }
936 922 } else while(num>0 && args.size() > 0) {
937 923 num--;
938 924 std::string current_ = args.back();
939 925 args.pop_back();
940   - op->add_result(vnum, current_);
  926 + op->add_result(current_);
941 927 }
942 928  
943 929 if(rest != "") {
... ... @@ -980,25 +966,23 @@ protected:
980 966 if(!overwrite && op->count() > 0)
981 967 return;
982 968  
983   - int vnum = op->get_new();
984 969 int num = op->get_expected();
985 970  
986   -
987 971 if(value != "") {
988 972 if(num!=-1) num--;
989   - op->add_result(vnum, value);
  973 + op->add_result(value);
990 974 } else if (num == 0) {
991   - op->add_result(vnum, "");
  975 + op->add_result("");
992 976 }
993 977  
994 978 if(num == -1) {
995 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 981 args.pop_back();
998 982 }
999 983 } else while(num>0 && args.size()>0) {
1000 984 num--;
1001   - op->add_result(vnum,args.back());
  985 + op->add_result(args.back());
1002 986 args.pop_back();
1003 987 }
1004 988 return;
... ...
include/CLI/Option.hpp
... ... @@ -17,7 +17,7 @@
17 17  
18 18 namespace CLI {
19 19  
20   -typedef std::vector<std::vector<std::string>> results_t;
  20 +typedef std::vector<std::string> results_t;
21 21 typedef std::function<bool(results_t)> callback_t;
22 22  
23 23 class Option;
... ... @@ -121,16 +121,13 @@ public:
121 121  
122 122 /// Count the total number of times an option was passed
123 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 128 /// This class is true if option is passed.
132 129 operator bool() const {
133   - return results_.size() > 0;
  130 + return count() > 0;
134 131 }
135 132  
136 133 /// Clear the parsed results (mostly for testing)
... ... @@ -372,9 +369,9 @@ public:
372 369 /// Process the callback
373 370 void run_callback() const {
374 371 if(!callback_(results_))
375   - throw ConversionError(get_name() + "=" + detail::join(flatten_results()));
  372 + throw ConversionError(get_name() + "=" + detail::join(results_));
376 373 if(validators_.size()>0) {
377   - for(const std::string & result : flatten_results())
  374 + for(const std::string & result : results_)
378 375 for(const std::function<bool(std::string)> &vali : validators_)
379 376 if(!vali(result))
380 377 throw ValidationError(get_name() + "=" + result);
... ... @@ -440,23 +437,14 @@ public:
440 437  
441 438  
442 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 ///@}
... ...