Skip to content

Commit

Permalink
[libc++][iterator][ranges] P2997R1: Removing the common reference req…
Browse files Browse the repository at this point in the history
…uirement from the indirectly invocable concepts (#98817)

Implements as DR against C++20: https://wg21.link/P2997R1

References:
- https://eel.is/c++draft/indirectcallable.indirectinvocable
- https://eel.is/c++draft/version.syn#header:%3cversion%3e

---------

Co-authored-by: Hristo Hristov <[email protected]>
  • Loading branch information
H-G-Hristov and Zingam authored Jul 18, 2024
1 parent 38f1dd2 commit cb3de24
Show file tree
Hide file tree
Showing 11 changed files with 47 additions and 41 deletions.
1 change: 1 addition & 0 deletions libcxx/docs/ReleaseNotes/19.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ Implemented Papers
- P2944R3 - Comparisons for ``reference_wrapper`` (comparison operators for ``reference_wrapper`` only)
- P2591R5 - Concatenation of strings and string views
- P2968R2 - Make ``std::ignore`` a first-class object
- P2997R1 - Removing the common reference requirement from the indirectly invocable concepts (as DR against C++20)
- P2302R4 - ``std::ranges::contains``
- P1659R3 - ``std::ranges::starts_with`` and ``std::ranges::ends_with``
- P3029R1 - Better ``mdspan``'s CTAD
Expand Down
1 change: 1 addition & 0 deletions libcxx/docs/Status/Cxx2c.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ Paper Status
.. [#note-P3142R0] This paper is applied as DR against C++23. (MSVC STL and libstdc++ will do the same.)
.. [#note-P2944R3] Implemented comparisons for ``reference_wrapper`` only.
.. [#note-P2422R1] Libc++ keeps the ``nodiscard`` attributes as a conforming extension.
.. [#note-P2997R1] This paper is applied as DR against C++20. (MSVC STL and libstdc++ will do the same.)
.. _issues-status-cxx2c:

Expand Down
2 changes: 1 addition & 1 deletion libcxx/docs/Status/Cxx2cPapers.csv
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
"`P3029R1 <https://wg21.link/P3029R1>`__","LWG","Better ``mdspan``'s CTAD","Tokyo March 2024","|Complete|","19.0",""
"","","","","","",""
"`P2747R2 <https://wg21.link/P2747R2>`__","CWG","``constexpr`` placement new","St. Louis June 2024","","",""
"`P2997R1 <https://wg21.link/P2997R1>`__","LWG","Removing the common reference requirement from the indirectly invocable concepts","St. Louis June 2024","","",""
"`P2997R1 <https://wg21.link/P2997R1>`__","LWG","Removing the common reference requirement from the indirectly invocable concepts","St. Louis June 2024","|Complete| [#note-P2997R1]_","19.0",""
"`P2389R2 <https://wg21.link/P2389R2>`__","LWG","``dextents`` Index Type Parameter","St. Louis June 2024","|Complete|","19.0",""
"`P3168R2 <https://wg21.link/P3168R2>`__","LWG","Give ``std::optional`` Range Support","St. Louis June 2024","","","|ranges|"
"`P3217R0 <https://wg21.link/P3217R0>`__","LWG","Adjoints to 'Enabling list-initialization for algorithms': find_last","St. Louis June 2024","","",""
Expand Down
15 changes: 6 additions & 9 deletions libcxx/include/__iterator/concepts.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,46 +177,43 @@ concept __has_arrow = input_iterator<_Ip> && (is_pointer_v<_Ip> || requires(_Ip
template <class _Fp, class _It>
concept indirectly_unary_invocable =
indirectly_readable<_It> && copy_constructible<_Fp> && invocable<_Fp&, iter_value_t<_It>&> &&
invocable<_Fp&, iter_reference_t<_It>> && invocable<_Fp&, iter_common_reference_t<_It>> &&
invocable<_Fp&, iter_reference_t<_It>> &&
common_reference_with< invoke_result_t<_Fp&, iter_value_t<_It>&>, invoke_result_t<_Fp&, iter_reference_t<_It>>>;

template <class _Fp, class _It>
concept indirectly_regular_unary_invocable =
indirectly_readable<_It> && copy_constructible<_Fp> && regular_invocable<_Fp&, iter_value_t<_It>&> &&
regular_invocable<_Fp&, iter_reference_t<_It>> && regular_invocable<_Fp&, iter_common_reference_t<_It>> &&
regular_invocable<_Fp&, iter_reference_t<_It>> &&
common_reference_with< invoke_result_t<_Fp&, iter_value_t<_It>&>, invoke_result_t<_Fp&, iter_reference_t<_It>>>;

template <class _Fp, class _It>
concept indirect_unary_predicate =
indirectly_readable<_It> && copy_constructible<_Fp> && predicate<_Fp&, iter_value_t<_It>&> &&
predicate<_Fp&, iter_reference_t<_It>> && predicate<_Fp&, iter_common_reference_t<_It>>;
predicate<_Fp&, iter_reference_t<_It>>;

template <class _Fp, class _It1, class _It2>
concept indirect_binary_predicate =
indirectly_readable<_It1> && indirectly_readable<_It2> && copy_constructible<_Fp> &&
predicate<_Fp&, iter_value_t<_It1>&, iter_value_t<_It2>&> &&
predicate<_Fp&, iter_value_t<_It1>&, iter_reference_t<_It2>> &&
predicate<_Fp&, iter_reference_t<_It1>, iter_value_t<_It2>&> &&
predicate<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>> &&
predicate<_Fp&, iter_common_reference_t<_It1>, iter_common_reference_t<_It2>>;
predicate<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>>;

template <class _Fp, class _It1, class _It2 = _It1>
concept indirect_equivalence_relation =
indirectly_readable<_It1> && indirectly_readable<_It2> && copy_constructible<_Fp> &&
equivalence_relation<_Fp&, iter_value_t<_It1>&, iter_value_t<_It2>&> &&
equivalence_relation<_Fp&, iter_value_t<_It1>&, iter_reference_t<_It2>> &&
equivalence_relation<_Fp&, iter_reference_t<_It1>, iter_value_t<_It2>&> &&
equivalence_relation<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>> &&
equivalence_relation<_Fp&, iter_common_reference_t<_It1>, iter_common_reference_t<_It2>>;
equivalence_relation<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>>;

template <class _Fp, class _It1, class _It2 = _It1>
concept indirect_strict_weak_order =
indirectly_readable<_It1> && indirectly_readable<_It2> && copy_constructible<_Fp> &&
strict_weak_order<_Fp&, iter_value_t<_It1>&, iter_value_t<_It2>&> &&
strict_weak_order<_Fp&, iter_value_t<_It1>&, iter_reference_t<_It2>> &&
strict_weak_order<_Fp&, iter_reference_t<_It1>, iter_value_t<_It2>&> &&
strict_weak_order<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>> &&
strict_weak_order<_Fp&, iter_common_reference_t<_It1>, iter_common_reference_t<_It2>>;
strict_weak_order<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>>;

template <class _Fp, class... _Its>
requires(indirectly_readable<_Its> && ...) && invocable<_Fp, iter_reference_t<_Its>...>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,13 @@ struct BadPredicate5 {
};
static_assert(!std::indirect_binary_predicate<BadPredicate5, It1, It2>);

// Should fail when the predicate can't be called with (iter_common_reference_t, iter_common_reference_t)
struct BadPredicate6 {
template <class T, class U> bool operator()(T const&, U const&) const;
bool operator()(std::iter_common_reference_t<It1>, std::iter_common_reference_t<It2>) const = delete;
// This case was made valid by P2997R1.
struct GoodPredicate6 {
template <class T, class U>
bool operator()(T const&, U const&) const;
bool operator()(std::iter_common_reference_t<It1>, std::iter_common_reference_t<It2>) const = delete;
};
static_assert(!std::indirect_binary_predicate<BadPredicate6, It1, It2>);
static_assert(std::indirect_binary_predicate<GoodPredicate6, It1, It2>);

// Test ADL-proofing (P2538R1)
#if TEST_STD_VER >= 26 || defined(_LIBCPP_VERSION)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,13 @@ struct BadRelation5 {
};
static_assert(!std::indirect_equivalence_relation<BadRelation5, It1, It2>);

// Should fail when the function can't be called with (iter_common_reference_t, iter_common_reference_t)
struct BadRelation6 {
template <class T, class U> bool operator()(T const&, U const&) const;
bool operator()(std::iter_common_reference_t<It1>, std::iter_common_reference_t<It2>) const = delete;
// This case was made valid by P2997R1.
struct GoodRelation6 {
template <class T, class U>
bool operator()(T const&, U const&) const;
bool operator()(std::iter_common_reference_t<It1>, std::iter_common_reference_t<It2>) const = delete;
};
static_assert(!std::indirect_equivalence_relation<BadRelation6, It1, It2>);
static_assert(std::indirect_equivalence_relation<GoodRelation6, It1, It2>);

// Test ADL-proofing (P2538R1)
#if TEST_STD_VER >= 26 || defined(_LIBCPP_VERSION)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,13 @@ struct BadOrder5 {
};
static_assert(!std::indirect_strict_weak_order<BadOrder5, It1, It2>);

// Should fail when the function can't be called with (iter_common_reference_t, iter_common_reference_t)
struct BadOrder6 {
template <class T, class U> bool operator()(T const&, U const&) const;
bool operator()(std::iter_common_reference_t<It1>, std::iter_common_reference_t<It2>) const = delete;
// This case was made valid by P2997R1.
struct GoodOrder6 {
template <class T, class U>
bool operator()(T const&, U const&) const;
bool operator()(std::iter_common_reference_t<It1>, std::iter_common_reference_t<It2>) const = delete;
};
static_assert(!std::indirect_strict_weak_order<BadOrder6, It1, It2>);
static_assert(std::indirect_strict_weak_order<GoodOrder6, It1, It2>);

// Test ADL-proofing (P2538R1)
#if TEST_STD_VER >= 26 || defined(_LIBCPP_VERSION)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,13 @@ struct BadPredicate3 {
};
static_assert(!std::indirect_unary_predicate<BadPredicate3, It>);

// Should fail when the predicate can't be called with std::iter_common_reference_t<It>
struct BadPredicate4 {
template <class T> bool operator()(T const&) const;
bool operator()(std::iter_common_reference_t<It>) const = delete;
// This case was made valid by P2997R1.
struct GoodPredicate4 {
template <class T>
bool operator()(T const&) const;
bool operator()(std::iter_common_reference_t<It>) const = delete;
};
static_assert(!std::indirect_unary_predicate<BadPredicate4, It>);
static_assert(std::indirect_unary_predicate<GoodPredicate4, It>);

// Test ADL-proofing (P2538R1)
#if TEST_STD_VER >= 26 || defined(_LIBCPP_VERSION)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,13 @@ struct BadInvocable3 {
};
static_assert(!std::indirectly_regular_unary_invocable<BadInvocable3, It>);

// Should fail when the invocable can't be called with (iter_common_reference_t)
struct BadInvocable4 {
template <class T> R1 operator()(T const&) const;
R1 operator()(std::iter_common_reference_t<It>) const = delete;
// This case was made valid by P2997R1.
struct GoodInvocable4 {
template <class T>
R1 operator()(T const&) const;
R1 operator()(std::iter_common_reference_t<It>) const = delete;
};
static_assert(!std::indirectly_regular_unary_invocable<BadInvocable4, It>);
static_assert(std::indirectly_regular_unary_invocable<GoodInvocable4, It>);

// Should fail when the invocable doesn't have a common reference between its return types
struct BadInvocable5 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,13 @@ struct BadInvocable3 {
};
static_assert(!std::indirectly_unary_invocable<BadInvocable3, It>);

// Should fail when the invocable can't be called with (iter_common_reference_t)
struct BadInvocable4 {
template <class T> R1 operator()(T const&) const;
R1 operator()(std::iter_common_reference_t<It>) const = delete;
// This case was made valid by P2997R1.
struct GoodInvocable4 {
template <class T>
R1 operator()(T const&) const;
R1 operator()(std::iter_common_reference_t<It>) const = delete;
};
static_assert(!std::indirectly_unary_invocable<BadInvocable4, It>);
static_assert(std::indirectly_unary_invocable<GoodInvocable4, It>);

// Should fail when the invocable doesn't have a common reference between its return types
struct BadInvocable5 {
Expand Down
3 changes: 2 additions & 1 deletion libcxx/utils/generate_feature_test_macro_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -993,7 +993,8 @@ def add_version_header(tc):
"name": "__cpp_lib_ranges",
"values": {
"c++20": 202207,
# "c++26": 202406, # P2997R1 Removing the common reference requirement from the indirectly invocable concepts
# "c++23": 202302, # Relaxing Ranges Just A Smidge
# "c++26": 202406, # P2997R1 Removing the common reference requirement from the indirectly invocable concepts (already implemented as a DR)
},
"headers": ["algorithm", "functional", "iterator", "memory", "ranges"],
},
Expand Down

0 comments on commit cb3de24

Please sign in to comment.