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

Updated PR for the printer design proposal #3259

Merged
merged 1 commit into from
Aug 2, 2024
Merged

Conversation

rrahn
Copy link
Contributor

@rrahn rrahn commented Jun 12, 2024

This PR builds upon the original proposal of @marehr (#3227).

I changed from the print static member function to overloading the function call operator of the printer classes.
Using this idea, we can now test wether a printer is invocable for a given output stream and the streamable argument.
I also refactored some of the original default_printer code to simplify it.
Among others, the is_printer is not needed anymore as we can use the invocable concept.
For investigating errors I kept the concept printable_with which is basically just an alias for the invocable concept.
In addition, I added documentation.
Once this is done, we can look for more debug_stream instances that can be replaced with the printer mechanism.

Copy link

vercel bot commented Jun 12, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated (UTC)
seqan3 ✅ Ready (Inspect) Visit Preview Jun 13, 2024 3:03pm

@rrahn rrahn requested a review from eseiler June 12, 2024 13:06
@seqan-actions seqan-actions added lint [INTERNAL] signal for linting and removed lint [INTERNAL] signal for linting labels Jun 12, 2024
@seqan-actions seqan-actions added lint [INTERNAL] signal for linting and removed lint [INTERNAL] signal for linting labels Jun 12, 2024
@rrahn rrahn changed the title Initial complete PR for the printer design proposal Updated PR for the printer design proposal Jun 12, 2024
@seqan-actions seqan-actions added lint [INTERNAL] signal for linting and removed lint [INTERNAL] signal for linting labels Jun 12, 2024
@seqan-actions seqan-actions added lint [INTERNAL] signal for linting and removed lint [INTERNAL] signal for linting labels Jun 13, 2024
@seqan-actions seqan-actions added lint [INTERNAL] signal for linting and removed lint [INTERNAL] signal for linting labels Jun 13, 2024
include/seqan3/alignment/matrix/detail/debug_matrix.hpp Outdated Show resolved Hide resolved
include/seqan3/alignment/matrix/detail/debug_matrix.hpp Outdated Show resolved Hide resolved
include/seqan3/alphabet/cigar/cigar.hpp Outdated Show resolved Hide resolved
include/seqan3/alphabet/detail/debug_stream_alphabet.hpp Outdated Show resolved Hide resolved
include/seqan3/core/debug_stream/default_printer.hpp Outdated Show resolved Hide resolved
include/seqan3/core/debug_stream/range.hpp Outdated Show resolved Hide resolved
include/seqan3/core/debug_stream/range.hpp Outdated Show resolved Hide resolved
@seqan-actions seqan-actions added the lint [INTERNAL] signal for linting label Jul 25, 2024
@eseiler eseiler removed the lint [INTERNAL] signal for linting label Jul 25, 2024
@seqan-actions
Copy link
Member

Documentation preview available at https://docs.seqan.de/preview/seqan/seqan3/3259

Copy link

codecov bot commented Jul 25, 2024

Codecov Report

Attention: Patch coverage is 98.10127% with 3 lines in your changes missing coverage. Please review.

Project coverage is 98.14%. Comparing base (4a0b3fe) to head (bb9edea).

Current head bb9edea differs from pull request most recent head 4c65dda

Please upload reports for the commit 4c65dda to get more accurate results.

Files Patch % Lines
...ude/seqan3/core/debug_stream/debug_stream_type.hpp 89.47% 2 Missing ⚠️
include/seqan3/core/debug_stream/variant.hpp 85.71% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3259      +/-   ##
==========================================
+ Coverage   98.12%   98.14%   +0.02%     
==========================================
  Files         270      271       +1     
  Lines       11926    11955      +29     
  Branches      105      104       -1     
==========================================
+ Hits        11702    11733      +31     
+ Misses        224      222       -2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@seqan-actions seqan-actions added the lint [INTERNAL] signal for linting label Jul 26, 2024
@rrahn rrahn requested a review from eseiler July 26, 2024 14:26
@eseiler eseiler removed the lint [INTERNAL] signal for linting label Jul 26, 2024
@seqan-actions seqan-actions added lint [INTERNAL] signal for linting and removed lint [INTERNAL] signal for linting labels Jul 26, 2024
@seqan-actions seqan-actions added lint [INTERNAL] signal for linting and removed lint [INTERNAL] signal for linting labels Jul 26, 2024
@seqan-actions seqan-actions added lint [INTERNAL] signal for linting and removed lint [INTERNAL] signal for linting labels Jul 26, 2024
FEATURE: add seqan3::default_printer

This PR will resolve seqan/product_backlog#63.

This issue is a long-standing open to-do of mine. I hope that you can take it over and push it over the finishing line.
The state of the current PR is just a draft of an idea.

I'll comment on multiple code locations to point out the advantages of the new design.

The major idea of the design is due to the following observation:

> We use overload resolution and in particular overload ordering via concepts to determine the order in which we should print

Just to give a small example (the more down, the more specialized):

```cpp
  std::cout //-printable [1]
< seqan3::tuple_like // [4]
< std::ranges::input_range // [2]
< std::vector<uint8_t> // [3]
< seqan3::sequence // [3]
< char * // [2]

  std::cout //-printable [1]
< char // [5]
< seqan3::tuple_like // [4]
< seqan3::alphabet // [5]
< seqan3::mask // [6]
```

NOTE: that using concepts as overload resolution always uses a partially ordered set, which can be depicted by as a [Hasse Diagram](https://en.wikipedia.org/wiki/Hasse_diagram), and by using the except clauses via `requires` we give it a total order.

The idea is simple:
* Have a list of printers.
* The order of the printers dictates in which order an object should be printed.
* We allow that multiple printers might be viable to print a type.
* Each `printer<type>` either has a function object / lambda `print` or not;
  depending on whether the `printer` can print that `type` or not (implemented by
  [template specialization](https://en.cppreference.com/w/cpp/language/template_specialization))
* We can explicitly use `printer` in other printer's, if we know that
  only that overload should be used,

So put together: For a given type, ask every printer in order whether it can print that type and the first one to answer yes, is the selected printer.

----

[1] If all overloads do not work, use `std::ostream`
https://github.com/seqan/seqan3/blob/6b681fb2eae5ab2997d293e99fc6a7f869a20316/include/seqan3/core/debug_stream/debug_stream_type.hpp#L242-L247
[2] Use this for all `std::ranges::input_range`s except if type is something like `std::filesystem` (type == range_value_t) or `char *`
https://github.com/seqan/seqan3/blob/6b681fb2eae5ab2997d293e99fc6a7f869a20316/include/seqan3/core/debug_stream/range.hpp#L96-L98
https://github.com/seqan/seqan3/blob/6b681fb2eae5ab2997d293e99fc6a7f869a20316/include/seqan3/core/debug_stream/range.hpp#L38-L45
[3] Same as [2] where value_type is an alphabet but only if the alphabet is not an `unsigned int` (this condition has no test case?!)
https://github.com/seqan/seqan3/blob/6b681fb2eae5ab2997d293e99fc6a7f869a20316/include/seqan3/core/debug_stream/range.hpp#L138-L141
[4] Use this for all `std::tuple`-like types except if it is a `std::ranges::input_range` (what is a tuple and ranges at the same time?!) and an `seqan3::alphabet` (basically `seqan3::alphabet_tuple_base` derived types)
https://github.com/seqan/seqan3/blob/6b681fb2eae5ab2997d293e99fc6a7f869a20316/include/seqan3/core/debug_stream/tuple.hpp#L53-L56
[5] Use this for all `seqan3::alphabet`s except if it can be printed by `std::cout` (like `char`)
https://github.com/seqan/seqan3/blob/6b681fb2eae5ab2997d293e99fc6a7f869a20316/include/seqan3/alphabet/detail/debug_stream_alphabet.hpp#L30-L32
[6] Type must be `seqan3::semialphabet` and `seqan3::mask`
https://github.com/seqan/seqan3/blob/6b681fb2eae5ab2997d293e99fc6a7f869a20316/include/seqan3/alphabet/detail/debug_stream_alphabet.hpp#L46-L48

Co-authored-by: seqan-actions[bot] <[email protected]>
Co-authored-by: rrahn <[email protected]>
Co-authored-by: Enrico Seiler <[email protected]>
@seqan-actions seqan-actions added the lint [INTERNAL] signal for linting label Aug 2, 2024
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.

I changed the style:

  • Always forward
  • Except for PODs
  • Do the remove_cvref_t when looking for a suitable printer

Instantiates exactly one printer struct for each distinct type.
Instantiates at most 4 operator()s.

The forwarding reference template argument arg_t is can only be called
through a instance of the printer with the correct type. So arg_t should
usually be the correct type.

I found the old approach harder to understand (more differences amongst
printers). Also the cvref handling by inheritance causes more
structs/operators to be instantiated than needed.

@seqan-actions seqan-actions removed the lint [INTERNAL] signal for linting label Aug 2, 2024
@eseiler eseiler merged commit 5c917af into seqan:main Aug 2, 2024
38 checks passed
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.

4 participants