tcbrindle / flux

A C++20 library for sequence-orientated programming
https://tristanbrindle.com/flux/
Boost Software License 1.0
513 stars 30 forks source link

Remove projections (!) #45

Closed tcbrindle closed 1 year ago

tcbrindle commented 1 year ago

I like projections in std::ranges. But they come don't come for free: there is a (small?) overhead in terms of compile times, and an added burden in terms of specification, concept formulation and documentation.

What this PR does is add two new function adaptors/combinators which provide the equivalent functionality to projection arguments to algorithms, but in an opt-in basis. So instead of saying, for example

flux::sort(vec, std::less{}, &T::member);

you now say

flux::sort(vec, flux::proj(std::less{}, &T::member));

This arguably makes it more clear what's actually happening -- that we're modifying the comparator function object.

The proj adaptor takes an n-ary callable F and a unary projection P and returns a new n-ary callable which, when invoked with arguments args..., calls F(P(args)...) -- that is, it applies the projection to each argument before calling F.

This covers most uses of projections in the library. The exceptions are algorithms which take two sequences and two (different) projections -- equal() and compare() for example. For this case we have another adaptor proj2 (which should really be called binary_project or something like that, but it's a bit too long). This takes a binary callable F and two unary projections L and R, and constructs a binary callable which, when invokes with arguments a and b calls F(L(a), R(b)) -- that is, it applies the left and right projection functions to the left and right arguments. (Theoretically we could make it all variadic and have N projections for an n-ary callable, but we only ever need two in Flux.)

Both proj and proj2 are actually aggregate classes used via CTAD, meaning you can use designated initialisers to say, for example

flux::equal(seq1, seq2, flux::proj2{.fn = std::equal_to{}, .lhs = &T::member, .rhs = &U::member});

which I actually think reads quite well.

codecov[bot] commented 1 year ago

Codecov Report

Patch coverage: 95.83% and project coverage change: +0.04 :tada:

Comparison is base (4b20127) 98.33% compared to head (79bfe39) 98.37%.

Additional details and impacted files ```diff @@ Coverage Diff @@ ## main #45 +/- ## ========================================== + Coverage 98.33% 98.37% +0.04% ========================================== Files 63 63 Lines 2280 2279 -1 ========================================== Hits 2242 2242 + Misses 38 37 -1 ``` | [Impacted Files](https://codecov.io/gh/tcbrindle/flux/pull/45?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tristan+Brindle) | Coverage Δ | | |---|---|---| | [include/flux/core/inline\_sequence\_base.hpp](https://codecov.io/gh/tcbrindle/flux/pull/45?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tristan+Brindle#diff-aW5jbHVkZS9mbHV4L2NvcmUvaW5saW5lX3NlcXVlbmNlX2Jhc2UuaHBw) | `92.30% <ø> (ø)` | | | [include/flux/op/chunk\_by.hpp](https://codecov.io/gh/tcbrindle/flux/pull/45?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tristan+Brindle#diff-aW5jbHVkZS9mbHV4L29wL2NodW5rX2J5LmhwcA==) | `100.00% <ø> (ø)` | | | [include/flux/op/count.hpp](https://codecov.io/gh/tcbrindle/flux/pull/45?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tristan+Brindle#diff-aW5jbHVkZS9mbHV4L29wL2NvdW50LmhwcA==) | `100.00% <ø> (ø)` | | | [include/flux/op/drop\_while.hpp](https://codecov.io/gh/tcbrindle/flux/pull/45?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tristan+Brindle#diff-aW5jbHVkZS9mbHV4L29wL2Ryb3Bfd2hpbGUuaHBw) | `100.00% <ø> (ø)` | | | [include/flux/op/filter.hpp](https://codecov.io/gh/tcbrindle/flux/pull/45?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tristan+Brindle#diff-aW5jbHVkZS9mbHV4L29wL2ZpbHRlci5ocHA=) | `100.00% <ø> (ø)` | | | [include/flux/op/take\_while.hpp](https://codecov.io/gh/tcbrindle/flux/pull/45?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tristan+Brindle#diff-aW5jbHVkZS9mbHV4L29wL3Rha2Vfd2hpbGUuaHBw) | `100.00% <ø> (ø)` | | | [include/flux/op/detail/pdqsort.hpp](https://codecov.io/gh/tcbrindle/flux/pull/45?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tristan+Brindle#diff-aW5jbHVkZS9mbHV4L29wL2RldGFpbC9wZHFzb3J0LmhwcA==) | `96.25% <33.33%> (-0.06%)` | :arrow_down: | | [include/flux/core/predicates.hpp](https://codecov.io/gh/tcbrindle/flux/pull/45?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tristan+Brindle#diff-aW5jbHVkZS9mbHV4L2NvcmUvcHJlZGljYXRlcy5ocHA=) | `100.00% <100.00%> (ø)` | | | [include/flux/op/all\_any\_none.hpp](https://codecov.io/gh/tcbrindle/flux/pull/45?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tristan+Brindle#diff-aW5jbHVkZS9mbHV4L29wL2FsbF9hbnlfbm9uZS5ocHA=) | `100.00% <100.00%> (ø)` | | | [include/flux/op/compare.hpp](https://codecov.io/gh/tcbrindle/flux/pull/45?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tristan+Brindle#diff-aW5jbHVkZS9mbHV4L29wL2NvbXBhcmUuaHBw) | `100.00% <100.00%> (ø)` | | | ... and [7 more](https://codecov.io/gh/tcbrindle/flux/pull/45?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tristan+Brindle) | | Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tristan+Brindle). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tristan+Brindle)

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Do you have feedback about the report comment? Let us know in this issue.

tcbrindle commented 1 year ago

CodeCov isn't happy, but I think that's because we've removed some lines that were hit in pqdsort.hpp, so the few that we miss now count for a greater percentage of the total