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

Enum support for the argument parser #1196

Merged
merged 1 commit into from
Nov 29, 2019

Conversation

smehringer
Copy link
Member

@smehringer smehringer commented Jul 26, 2019

No description provided.

@smehringer smehringer requested a review from h-2 July 26, 2019 10:37
@h-2
Copy link
Member

h-2 commented Jul 29, 2019

In general we can do it this way. Some notes:

  • if it's a customisation point, it needs to be a CPO
  • I wouldn't use get_, because "get" usually means "access a member or element"
  • You can use a regular map instead of of an unordered_map to get the order. Performance is not relevant here as it's the arg parser and usually the lists are small.
  • The current implementation is entirely independent of enums. I think that's actually quite nice and we should document it as such.

@h-2 h-2 removed their request for review August 2, 2019 12:02
@smehringer
Copy link
Member Author

if it's a customisation point, it needs to be a CPO

But doesn't this work through ADL automatically?
Let's say the enum Foo of the user will be in the namespace Bar. Then the user will also define the function get_argument_conversion_table(Foo) in Bar and thus when I call the function within seqan3 code on the enum Bar::Foo then ADL will look whether Bar has this function implemented...
Where do I need a CPO and which class should be a CPO?

I wouldn't use get_, because "get" usually means "access a member or element"

Agreed. The name is ugly anyway but I am bad in naming. Suggestions? This also refers to naming it to something non-enum-specific.

@h-2
Copy link
Member

h-2 commented Aug 20, 2019

But doesn't this work through ADL automatically?

The same rules apply as anywhere else, or how is this different from to_char()?

Agreed. The name is ugly anyway but I am bad in naming. Suggestions? This also refers to naming it to something non-enum-specific.

They are name-value-pairs so I would name them something like that. I would probably make a name_value_table and implement it as a variable.

@smehringer
Copy link
Member Author

The same rules apply as anywhere else, or how is this different from to_char()?

The difference is that we do not supply a global seqan3::get_argument_conversion_table.
Either there is this function in the bar namespace or not.

@codecov
Copy link

codecov bot commented Sep 6, 2019

Codecov Report

Merging #1196 into master will increase coverage by <.01%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1196      +/-   ##
==========================================
+ Coverage   97.52%   97.52%   +<.01%     
==========================================
  Files         226      226              
  Lines        8760     8778      +18     
==========================================
+ Hits         8543     8561      +18     
  Misses        217      217
Impacted Files Coverage Δ
include/seqan3/argument_parser/argument_parser.hpp 98.54% <ø> (ø) ⬆️
include/seqan3/argument_parser/auxiliary.hpp 100% <100%> (ø) ⬆️
...ude/seqan3/argument_parser/detail/format_parse.hpp 94.27% <100%> (+0.15%) ⬆️
...lude/seqan3/argument_parser/detail/format_base.hpp 89.31% <100%> (+0.25%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update b234996...9bd13c3. Read the comment docs.

@smehringer smehringer force-pushed the argument_parser_fix branch 2 times, most recently from dbca685 to 6201278 Compare September 9, 2019 07:13
@smehringer smehringer requested review from marehr and eseiler and removed request for marehr September 9, 2019 19:26
include/seqan3/argument_parser/argument_parser.hpp Outdated Show resolved Hide resolved
include/seqan3/argument_parser/argument_parser.hpp Outdated Show resolved Hide resolved
include/seqan3/argument_parser/argument_parser.hpp Outdated Show resolved Hide resolved
include/seqan3/argument_parser/argument_parser.hpp Outdated Show resolved Hide resolved
include/seqan3/argument_parser/argument_parser.hpp Outdated Show resolved Hide resolved
test/snippet/argument_parser/string_convertible.cpp Outdated Show resolved Hide resolved
test/snippet/argument_parser/string_convertible.cpp Outdated Show resolved Hide resolved
test/snippet/argument_parser/string_convertible.cpp Outdated Show resolved Hide resolved
test/unit/argument_parser/format_parse_test.cpp Outdated Show resolved Hide resolved
test/unit/core/debug_stream_test.cpp Outdated Show resolved Hide resolved
include/seqan3/argument_parser/auxiliary.hpp Outdated Show resolved Hide resolved
include/seqan3/argument_parser/auxiliary.hpp Outdated Show resolved Hide resolved
include/seqan3/argument_parser/auxiliary.hpp Outdated Show resolved Hide resolved
include/seqan3/argument_parser/auxiliary.hpp Outdated Show resolved Hide resolved
include/seqan3/argument_parser/auxiliary.hpp Outdated Show resolved Hide resolved
include/seqan3/argument_parser/detail/format_parse.hpp Outdated Show resolved Hide resolved
include/seqan3/argument_parser/detail/format_parse.hpp Outdated Show resolved Hide resolved
test/snippet/argument_parser/string_convertible.cpp Outdated Show resolved Hide resolved
@smehringer smehringer force-pushed the argument_parser_fix branch 4 times, most recently from eda8ad3 to 1556454 Compare September 11, 2019 14:49
Copy link
Member

@eseiler eseiler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing, otherwise LGTM

include/seqan3/argument_parser/detail/format_parse.hpp Outdated Show resolved Hide resolved
Copy link
Member

@h-2 h-2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The general structure and everything looks good, but some things should be changed I think:

  • if you call it a map, you should make it a variable and not a function. See for example alphabet_size for how that works with CPOs
  • "string conversion" is a very broad term, are you sure that's good? Maybe call it named_values? Name-value-pair and attribute-value-pair are popular names for this, I think... it also depends on the order of key/value... maybe also value_to_name_map.
  • enforce in the CPO that stuff actually has the right type
  • use ordered_map so that you have an order in the arg parser
  • make the name type a string_view instead of a string.

include/seqan3/argument_parser/auxiliary.hpp Outdated Show resolved Hide resolved
include/seqan3/argument_parser/auxiliary.hpp Outdated Show resolved Hide resolved
include/seqan3/argument_parser/auxiliary.hpp Outdated Show resolved Hide resolved
include/seqan3/argument_parser/detail/format_base.hpp Outdated Show resolved Hide resolved
include/seqan3/argument_parser/detail/format_parse.hpp Outdated Show resolved Hide resolved
@smehringer smehringer force-pushed the argument_parser_fix branch 3 times, most recently from 2ca02ec to 67bbeb0 Compare October 9, 2019 12:10
@smehringer
Copy link
Member Author

@h-2 Can you take a look?
I am not sure if I got it completely right (although the tests pass..). I am unsure about when (or if) to remove cvref qualifiers?

@smehringer smehringer requested a review from h-2 October 9, 2019 12:12
@smehringer smehringer force-pushed the argument_parser_fix branch 4 times, most recently from 4c6fe75 to 7055baf Compare October 11, 2019 11:49
Copy link
Member

@h-2 h-2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a a general design question: you seem to be added documentation to the man-page on which values are valid for the enum and you are using the value_list_validator for this. But then I don't see you actually using the value_list_validator as the validator!

And how does this relate to a (different) validator supplied by the user?

I would design it differently:

  • don't automatically assume anything about affected types.
  • provide an "enum_validator" that is a valid_values_validator with the extracted strings.

This adds less hacky-special-case code and allows people to e.g. select a subset of values that they want to accept.

include/seqan3/argument_parser/auxiliary.hpp Show resolved Hide resolved
include/seqan3/argument_parser/auxiliary.hpp Outdated Show resolved Hide resolved
include/seqan3/argument_parser/detail/format_base.hpp Outdated Show resolved Hide resolved
include/seqan3/argument_parser/detail/format_base.hpp Outdated Show resolved Hide resolved
include/seqan3/argument_parser/detail/format_parse.hpp Outdated Show resolved Hide resolved
include/seqan3/argument_parser/detail/format_parse.hpp Outdated Show resolved Hide resolved
include/seqan3/argument_parser/detail/format_parse.hpp Outdated Show resolved Hide resolved
include/seqan3/argument_parser/detail/format_base.hpp Outdated Show resolved Hide resolved
@smehringer
Copy link
Member Author

I would design it differently:

  • don't automatically assume anything about affected types.
  • provide an "enum_validator" that is a valid_values_validator with the extracted strings.

This adds less hacky-special-case code and allows people to e.g. select a subset of values that they want to accept.

As discussed eprsonally I remove the automativ valid values but did not add a special enum_validator. The user can simply use map | views::get<1> for the value_list_validator as can be seen in the snippet example.

@smehringer smehringer requested a review from h-2 October 29, 2019 14:26
include/seqan3/argument_parser/auxiliary.hpp Outdated Show resolved Hide resolved
include/seqan3/argument_parser/auxiliary.hpp Outdated Show resolved Hide resolved
include/seqan3/argument_parser/auxiliary.hpp Outdated Show resolved Hide resolved
include/seqan3/argument_parser/auxiliary.hpp Outdated Show resolved Hide resolved
include/seqan3/argument_parser/auxiliary.hpp Outdated Show resolved Hide resolved
test/unit/argument_parser/format_parse_test.cpp Outdated Show resolved Hide resolved
include/seqan3/argument_parser/auxiliary.hpp Outdated Show resolved Hide resolved
test/snippet/argument_parser/custom_enumeration.cpp Outdated Show resolved Hide resolved
@smehringer smehringer force-pushed the argument_parser_fix branch 2 times, most recently from d450b8a to 969fa64 Compare November 11, 2019 15:09
Copy link
Member

@h-2 h-2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is all just minor stuff, feel free to merge this once these things have been fixed!

include/seqan3/argument_parser/auxiliary.hpp Outdated Show resolved Hide resolved
include/seqan3/argument_parser/auxiliary.hpp Outdated Show resolved Hide resolved
include/seqan3/argument_parser/detail/format_parse.hpp Outdated Show resolved Hide resolved
include/seqan3/argument_parser/detail/format_parse.hpp Outdated Show resolved Hide resolved
* It acts as a wrapper and looks for two possible implementations (in this order):
*
* 1. A static member `enumeration_names` in `seqan3::custom::argument_parsing<your_type>` that is of type
* `std::unordered_map<std::string_view, your_type>>`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should relax these constraints to just be an "associative range", but that can be done later.

// the static member function enumeration_names
// you can now add an option that takes a value of type std::errc:
parser.add_option(value, 'e', "errc", "Give me a std::errc value.", seqan3::option_spec::DEFAULT,
seqan3::value_list_validator{(seqan3::enumeration_names<std::errc> | seqan3::views::get<1>)});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the mechanism of using seqan3::views::get documented anywhere?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean? This is a snippet that appears in the documentation of "how to specialise this". Is that documentation enough?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just think that most users will be surprised that you can iterate over values/keys of an associative container using views::get<>.
If this is not explained anywhere, I think it would be good to add a sentence as explanation. But this can also be done later if you add a card.

test/unit/argument_parser/format_parse_test.cpp Outdated Show resolved Hide resolved
{
return impl(priority_tag<1>{}, s_option_t{});
}
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This stuff could be much simpler, but it doesn't have to block this PR. We can fix it later.

Copy link
Member

@h-2 h-2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these should work, too. If you do update this, please check. If not, it's not important.

Fell free to merge.

// Specialise a mapping from an identifying string to the respective value of your type bar.
auto enumeration_names(bar)
{
return std::unordered_map<std::string_view, bar>{{{"one", bar::one}, {"two", bar::two}, {"three", bar::three}}};;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return std::unordered_map<std::string_view, bar>{{{"one", bar::one}, {"two", bar::two}, {"three", bar::three}}};;
return std::unordered_map<std::string_view, bar>{{"one", bar::one}, {"two", bar::two}, {"three", bar::three}};;

?


auto enumeration_names(foo)
{
return std::unordered_map<std::string_view, foo>{{{"one", foo::one}, {"two", foo::two}, {"three", foo::three}}};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return std::unordered_map<std::string_view, foo>{{{"one", foo::one}, {"two", foo::two}, {"three", foo::three}}};
return std::unordered_map<std::string_view, foo>{{"one", foo::one}, {"two", foo::two}, {"three", foo::three}};

{
static inline std::unordered_map<std::string_view, Other::bar> const enumeration_names
{
{{"one", Other::bar::one}, {"two", Other::bar::two}}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
{{"one", Other::bar::one}, {"two", Other::bar::two}}
{"one", Other::bar::one}, {"two", Other::bar::two}


auto enumeration_names(Foo)
{
return std::unordered_map<std::string_view, Foo>{{{"one", Foo::one}, {"two", Foo::two}}};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return std::unordered_map<std::string_view, Foo>{{{"one", Foo::one}, {"two", Foo::two}}};
return std::unordered_map<std::string_view, Foo>{{"one", Foo::one}, {"two", Foo::two}};

@smehringer
Copy link
Member Author

Fell free to merge.

Can you approve the PR then 😁 ?
I you don't and CI is through I'll merge it anyway

@h-2 h-2 merged commit 91211b1 into seqan:master Nov 29, 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

Successfully merging this pull request may close these issues.

3 participants