Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Options that take an index + value argument. #296

Closed
mathiaswagner opened this issue Jun 27, 2019 · 6 comments
Closed

Options that take an index + value argument. #296

mathiaswagner opened this issue Jun 27, 2019 · 6 comments

Comments

@mathiaswagner
Copy link

While I think it is possible to hack things with the function passed to add_options I was wondering whether there is a cleaner solution to handle options that take a pair of values.
There is #128 but what I need are options like

--something 1 "double" --something 2 "single" --other 1 16.0 --other 3 0.0.

Basically you can think of the --something option being a vector but instead of specifying
--something "double" "single" the 1 and 2 as the first argument to the option specify the index in that vector. For the 2nd argument I still want to be able to use the transform / check options.

The most fancy use case is when you have a vector of vectors, like:
--vectorsomething 1 12 8 6 4 --vectorsomething 2 4 4 4 4
Here the first number again gives the position in a vector but the components are itself a vector (here: 12 8 6 4 and 2 2 2 2).

The vector of vector thing is optional, but I am still looking for clean way to achieve the first thing.
Current hack looks like:

std::vector<int> mgpre(3);
  auto entry_option{
      app.add_option("--entry",
                     [&mgpre](CLI::results_t vals) {size_t l; int j;// results_t is just a vector of strings
                      bool worked = true;
                      
                      std::map<std::string,int> prec_map({{"double", 8}, {"single", 4}, {"half", 2}});
                      CLI::Range validlevel(0,2);
                      CLI::CheckedTransformer prec_transform(prec_map);
                      for (size_t i{0}; i < vals.size() / 2; ++i){ // will always be a multiple of 2
                        validlevel(vals.at(2*i));
                        prec_transform(vals.at(2*i+1));
                        worked = worked and CLI::detail::lexical_cast(vals.at(2*i),l);
                        worked = worked and CLI::detail::lexical_cast(vals.at(2*i+1),j);

                      
                        if (worked) mgpre[l] = j;
                      }
                       return worked;
                     },
                     "level & value")};
  entry_option->type_name("level VALUE")->type_size(-2);
  entry_option->expected(-1);

but that is not very portable and errors also are not handled properly. If you have some pointer to where I could find useful components I am happy to work on that.

@phlptp
Copy link
Collaborator

phlptp commented Jul 7, 2019

I was playing around a bit with support for a pair(possibly generalized to a tuple) but will start with pair, i think that would allow your use case. Then for the first case at least it would look like

std::pair<size_t, int> index;
app.add_option("--entry",index," pair option");  

just like any other single variable.

Might also be able to support complex directly without the extra function for that currently.

@phlptp
Copy link
Collaborator

phlptp commented Aug 17, 2019

After pr #310 the first part of the issue can be handled with

std::map<std::string,int> prec_map({{"double", 8}, {"single", 4}, {"half", 2}});
                      CLI::Range validlevel(0,2);
                      CLI::CheckedTransformer prec_transform(prec_map);
std::pair<int,int>index
auto opt=app.add_option("--something",index);
opt->check(validlevel.application_index(0));
opt->transform(prec_transform.application_index(1));

though as I read through this some more, #310 only makes a few steps toward what you need. and probably what is needed is vector of tuples/pairs and way to validate appropriately only parts of tuples.

@mathiaswagner
Copy link
Author

This looks useful. However, as I currently understand it, the option now takes an index but I can only specify one index, value pair, e.g. in your example above I could do --something 1 half (and this works) but --something 1 half --something 2 double does not.

Not sure how this can be worked around. What I want is to use the std::pair to insert these values in. a std::vector.

Like (not a working code).

std::vector<int> somevalues{2,2,2};

std::pair<int,int>index
auto opt=app.add_option("--something",index);
opt->check(validlevel.application_index(0));
opt->transform(prec_transform.application_index(1));

// now insert in vector
somevalues[index.first] = index.second

I think the validation/transform part is sufficient as it is. The first thing is always an index (the check can probably be deduced from the vector (here: somevalues) and the 2nd argument is always a value.

That is of course ignoring the part with the index + vector I would also need.

So, I think apart from the insertion in a vector this is what I need to fix my first half.

Thanks!

@phlptp
Copy link
Collaborator

phlptp commented Aug 21, 2019

You are right this only addresses part of your issue. I thought about different ways of making the index periodic, but none were clean or intuitive with the way type_sizes are handled internally currently. So reworking that a little is the next step.

What I want to get to eventually is support for std::vector<std::pair<X,Y>> then the index would apply to each subcomponent of the vector. That might be a few steps down the road yet. A little more tinkering with the type size and expected values is required before that step can be taken in a reasonable fashion. I have a few ideas on how eventually we might get to support std::vector<std::vector> as well and things like std::pair<int, std::vector. We will see how soon we get to them.

@phlptp
Copy link
Collaborator

phlptp commented Nov 10, 2019

@mathiaswagner I think #325 actually gets at what you wanted.
allow add_option with std::pair or std::vector<std:pair<X,Y>> or even std::vector<std::vector>

and in the second case the validators are indexed on the element of the vector, so index 0 would apply the first of the std::pair and the index 1 applies to the second element of the pair or inner vector.

@phlptp
Copy link
Collaborator

phlptp commented Nov 23, 2019

@mathiaswagner I think is is working completely now in master so I am going to close the issue, but if you try it and doesn't work yet let me know.

@phlptp phlptp closed this as completed Nov 23, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants