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

c++17 concepts with CPP_template for engine/idTable/ files #1746

Merged
merged 11 commits into from
Feb 10, 2025

Conversation

sebastian-wieczorek
Copy link
Contributor

@sebastian-wieczorek sebastian-wieczorek commented Jan 31, 2025

Backport C++20 concepts in the src/engine/idTable directory back to C++17 using macros from range-v3

Signed-off-by: Johannes Kalmbach <[email protected]>
@joka921
Copy link
Member

joka921 commented Feb 3, 2025

Hello @sebastian-wieczorek
Thank you very much for your work. I have just checked out your branch locally and brought it to compilation. In a separate step I will have a detailed look and address possible TODOs from your side.

  1. For the initial declaration, in particular when a template is declared and in the same go defined in a header file, you have to use CPP_template. CPP_template_def is only for other redeclarations, or definitions that apppear after the initial declaration (typically in a .cpp file). The difference is, that the CPP_true parameter is defaulted to CPP_true = true in CPP_template and not in CPP_template_def (because redeclaring defaults is forbidden).

  2. Each occurence of CPP_and must be on the same level as the requires keyword, not inside additional parentheses, so the following works CPP_template(typename T) (requires (3 < 5) CPP_and (4<7)) (parens around individual constraints), but the following does not: CPP_template(typename T) (requires (someThing<T> CPP_and someOtherThing<T>)) (because here the CPP_and is inside parens.

  3. You have to use CPP_NOT, but you were already aware of this. I agree that the casing in the CPP_NOT is somewhat inconsistent and should probably be CPP_not, but that is in fact a macro from inside range-v3, where I want to keep the number of applied patches inside that external library as minimal as possible.

As already said, I have consistently applied points 1-3 and pushed your branch, the rest seems to work, but I will perform a separate review.

Copy link

codecov bot commented Feb 3, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 90.03%. Comparing base (f2562fe) to head (6043ba2).
Report is 18 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1746      +/-   ##
==========================================
+ Coverage   89.95%   90.03%   +0.07%     
==========================================
  Files         395      395              
  Lines       37651    37922     +271     
  Branches     4234     4264      +30     
==========================================
+ Hits        33869    34142     +273     
+ Misses       2487     2484       -3     
- Partials     1295     1296       +1     

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

Signed-off-by: Johannes Kalmbach <[email protected]>
Copy link
Member

@joka921 joka921 left a comment

Choose a reason for hiding this comment

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

Thank you very much, I have addressed two of your TODOs myself (the solution was straightforward) , and left another one + some cleanup suggestions for you.
Please let me know if you have further questions of if I can be of assistance.
Best regards
Johannes

Comment on lines 251 to 252
// TODO: <ccoecontrol> what about these? template cannot be defaulted
// possible solution: implement defaulted ones by hand
Copy link
Member

Choose a reason for hiding this comment

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

Thanks for pointing that out, In fact there seems to be no really simple + good C++-17 solution.
The manual implementation is rather error-prone, especially for the assignment.
I would suggest putting this whole block in its original form behind a #ifndef
So

#ifdef QLEVER_CPP_17
  IdTable(const IdTable&) = default;
  IdTable& operator= (const IdTable&) = default;
#else
  // The original code with the requires
#endif
```
as soon as we compile in C++20 mode we will detect all the illegal copies.
And additionally write a comment tha4t there is no simple way to formulate this in C++17 .
(For completeness: We could add a separate layer of wrapper classes that only handles the viewness, but that would be overkill for now).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

default put behind a macro here

@@ -346,7 +365,8 @@ class IdTable {
// Get a reference to the `i`-th row. The returned proxy objects can be
// implicitly and trivially converted to `row_reference`. For the design
// rationale behind those proxy types see above for their definition.
row_reference_restricted operator[](size_t index) requires(!isView) {
CPP_template(typename = void)(requires(!isView)) row_reference_restricted
Copy link
Member

Choose a reason for hiding this comment

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

This pattern happens very often, maybe wriite two macros at the beginning of this fiile
define REQUIRES_VIEW CPP_template(typename = void) (requires isView)
And the same for REQUIRES_NOT_VIEW, then you can write
REQUIRES_NOT_VIEW row_reference_restricted operator[](size_t index) here (similar in the other places),
whiich is nicer and uses less space.
Don't forget to undefine the macros again at the end of the header file to not clutter the global namespace.

Copy link
Contributor Author

@sebastian-wieczorek sebastian-wieczorek Feb 6, 2025

Choose a reason for hiding this comment

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

my guess is that this will be more common that just this file, what about enhancing concepts.h with some macro like:
CPP_parameterless_template(...) CPP_template(__VA_ARGS__)

Copy link
Member

Choose a reason for hiding this comment

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

Something like that could work, I will look into it, as I have discovered some additional macros to be missing.

Copy link
Member

Choose a reason for hiding this comment

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

For this PR (to get it merged) we will leave the typename = void defaults,
But if I have time I will add some additional macros.

Comment on lines 505 to 507
// TODO: <ccoecontrol> what with this one?
// reimplementing it with CPP_template macro causes template redefinition
// errors
Copy link
Member

Choose a reason for hiding this comment

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

I'll first have a look at the remainder, and then think of something.

Comment on lines 505 to 510
CPP_template(typename = void)(
requires(isCloneable)) auto moveOrClone() const& {
return clone();
}
CPP_template(typename = void)(
requires(isCloneable)) IdTable&& moveOrClone() && {
Copy link
Member

Choose a reason for hiding this comment

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

This could just be rewritten. Probably when trying out you misplaced some of the many &&s here or something else went wrong.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah, I tried this with gcc13 and this was just showing errors from other parts of the code when compiled with backports on

Copy link
Contributor Author

@sebastian-wieczorek sebastian-wieczorek Feb 6, 2025

Choose a reason for hiding this comment

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

here is gcc13 fix related to CPP_template usage for overloads or specializations, please share if you think is is needed.

Copy link
Member

Choose a reason for hiding this comment

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

That fix is definitely needed, I also have it in some open PRs... GCC11 didn't complain about this, but Clang16 (where I treid it) and obviously GCC13 (from what you say) correctly reject that code. It is time that we merge it in.

@sebastian-wieczorek
Copy link
Contributor Author

@joka921 please share what do you think about this.

Copy link
Member

@joka921 joka921 left a comment

Choose a reason for hiding this comment

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

We can leave this as is for now,
We have learned something for the next iteration.

I think for member functions that are constrained on the template arguments of the outer template, the better alternative to CPP_template<typename = void> is
using the CPP_member macro in combination with CPP_ret as it yields the best code for both C++17 and C++20. I have incorporated those into some of the places.

@sparql-conformance
Copy link

@joka921 joka921 merged commit 5caf9f4 into ad-freiburg:master Feb 10, 2025
22 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.

2 participants