Skip to content

[libc++][functional] P2944R3 (partial): Comparisons for reference_wrapper (reference_wrapper operators only) #88384

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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
d402314
[libc++][functional] P2944R3 (partial): Comparisons for ``reference_w…
H-G-Hristov Apr 11, 2024
1f22a33
Tests: operator== WIP
H-G-Hristov Apr 11, 2024
ca199a8
Test: operator<=?> WIP
H-G-Hristov Apr 17, 2024
24dc20b
Implemented https://wg21.link/LWG4071
H-G-Hristov Apr 21, 2024
f100fa2
Fixed includes
H-G-Hristov Apr 21, 2024
6254165
Tests: WIP SFINAE `operator==`
H-G-Hristov Apr 21, 2024
fc10604
Tests: WIP SFINAE `operator<=>`
H-G-Hristov Apr 21, 2024
288bbc0
Fixed formatting
H-G-Hristov Apr 21, 2024
a76111b
Tests: WIP `operator<=>`
H-G-Hristov Apr 21, 2024
6ced2a0
Tests: WIP `operator<=>`
H-G-Hristov Apr 21, 2024
a611205
Tests: `operator==`
H-G-Hristov Apr 21, 2024
60a4631
Tests: SFINAE `operator==`
H-G-Hristov Apr 21, 2024
096e8ac
Merge branch 'main' into hgh/libcxx/P2944R2-Comparisons-for-reference…
H-G-Hristov Apr 21, 2024
eb0e7a9
Tests: `operator<=>`
H-G-Hristov Apr 21, 2024
13c345d
Addressed some review comments
H-G-Hristov Apr 26, 2024
f910534
Merge branch 'main' into hgh/libcxx/P2944R2-Comparisons-for-reference…
H-G-Hristov Apr 28, 2024
532c6d6
Split tests: one test per overload
H-G-Hristov Apr 30, 2024
9f88c1f
Merge branch 'main' into hgh/libcxx/P2944R2-Comparisons-for-reference…
H-G-Hristov Apr 30, 2024
780c0f9
Merge branch 'main' into hgh/libcxx/P2944R2-Comparisons-for-reference…
H-G-Hristov May 4, 2024
3f2d3f7
Addressed some review comments
H-G-Hristov May 4, 2024
9c72dab
Addressed review comments
H-G-Hristov May 4, 2024
38eed6d
Merge branch 'main' into hgh/libcxx/P2944R2-Comparisons-for-reference…
H-G-Hristov May 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion libcxx/docs/FeatureTestMacroTable.rst
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ Status
---------------------------------------------------------- -----------------
``__cpp_lib_rcu`` *unimplemented*
---------------------------------------------------------- -----------------
``__cpp_lib_reference_wrapper`` *unimplemented*
``__cpp_lib_reference_wrapper`` ``202403L``
---------------------------------------------------------- -----------------
``__cpp_lib_saturation_arithmetic`` ``202311L``
---------------------------------------------------------- -----------------
Expand Down
1 change: 1 addition & 0 deletions libcxx/docs/ReleaseNotes/19.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ Implemented Papers
- P2869R4 - Remove Deprecated ``shared_ptr`` Atomic Access APIs from C++26
- P2872R3 - Remove ``wstring_convert`` From C++26
- P3142R0 - Printing Blank Lines with ``println`` (as DR against C++23)
- P2944R3 - Comparisons for ``reference_wrapper`` (comparison operators for ``reference_wrapper`` only)
- 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 @@ -41,6 +41,7 @@ Paper Status

.. [#note-P2510R3] This paper is applied as DR against C++20. (MSVC STL and libstdc++ will do the same.)
.. [#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.

.. _issues-status-cxx2c:

Expand Down
1 change: 1 addition & 0 deletions libcxx/docs/Status/Cxx2cIssues.csv
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,5 @@
"","","","","",""
"`3343 <https://wg21.link/LWG3343>`__","Ordering of calls to ``unlock()`` and ``notify_all()`` in Effects element of ``notify_all_at_thread_exit()`` should be reversed","Not Yet Adopted","|Complete|","16.0",""
"XXXX","","The sys_info range should be affected by save","Not Yet Adopted","|Complete|","19.0"
"`4071 <https://wg21.link/LWG4071>`__","","``reference_wrapper`` comparisons are not SFINAE-friendly","Not Yet Adopted","|Complete|","19.0"
"","","","","",""
2 changes: 1 addition & 1 deletion libcxx/docs/Status/Cxx2cPapers.csv
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
"`P2248R8 <https://wg21.link/P2248R8>`__","LWG","Enabling list-initialization for algorithms","Tokyo March 2024","","",""
"`P2810R4 <https://wg21.link/P2810R4>`__","LWG","``is_debugger_present`` ``is_replaceable``","Tokyo March 2024","","",""
"`P1068R11 <https://wg21.link/P1068R11>`__","LWG","Vector API for random number generation","Tokyo March 2024","","",""
"`P2944R3 <https://wg21.link/P2944R3>`__","LWG","Comparisons for ``reference_wrapper``","Tokyo March 2024","","",""
"`P2944R3 <https://wg21.link/P2944R3>`__","LWG","Comparisons for ``reference_wrapper``","Tokyo March 2024","|Partial| [#note-P2944R3]_","19.0",""
"`P2642R6 <https://wg21.link/P2642R6>`__","LWG","Padded ``mdspan`` layouts","Tokyo March 2024","","",""
"`P3029R1 <https://wg21.link/P3029R1>`__","LWG","Better ``mdspan``'s CTAD","Tokyo March 2024","|Complete|","19.0",""
"","","","","","",""
51 changes: 51 additions & 0 deletions libcxx/include/__functional/reference_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@
#ifndef _LIBCPP___FUNCTIONAL_REFERENCE_WRAPPER_H
#define _LIBCPP___FUNCTIONAL_REFERENCE_WRAPPER_H

#include <__compare/synth_three_way.h>
#include <__concepts/boolean_testable.h>
#include <__config>
#include <__functional/invoke.h>
#include <__functional/weak_result_type.h>
#include <__memory/addressof.h>
#include <__type_traits/enable_if.h>
#include <__type_traits/is_const.h>
#include <__type_traits/remove_cvref.h>
#include <__type_traits/void_t.h>
#include <__utility/declval.h>
Expand Down Expand Up @@ -64,6 +67,54 @@ class _LIBCPP_TEMPLATE_VIS reference_wrapper : public __weak_result_type<_Tp> {
{
return std::__invoke(get(), std::forward<_ArgTypes>(__args)...);
}

#if _LIBCPP_STD_VER >= 26

// [refwrap.comparisons], comparisons

_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(reference_wrapper __x, reference_wrapper __y)
requires requires {
{ __x.get() == __y.get() } -> __boolean_testable;
}
{
return __x.get() == __y.get();
}

_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(reference_wrapper __x, const _Tp& __y)
requires requires {
{ __x.get() == __y } -> __boolean_testable;
}
{
return __x.get() == __y;
}

_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(reference_wrapper __x, reference_wrapper<const _Tp> __y)
requires(!is_const_v<_Tp>) && requires {
{ __x.get() == __y.get() } -> __boolean_testable;
}
{
return __x.get() == __y.get();
}

_LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=>(reference_wrapper __x, reference_wrapper __y)
requires requires { std::__synth_three_way(__x.get(), __y.get()); }
{
return std::__synth_three_way(__x.get(), __y.get());
}

_LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=>(reference_wrapper __x, const _Tp& __y)
requires requires { std::__synth_three_way(__x.get(), __y); }
{
return std::__synth_three_way(__x.get(), __y);
}

_LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=>(reference_wrapper __x, reference_wrapper<const _Tp> __y)
requires(!is_const_v<_Tp>) && requires { std::__synth_three_way(__x.get(), __y.get()); }
{
return std::__synth_three_way(__x.get(), __y.get());
}

#endif // _LIBCPP_STD_VER >= 26
};

#if _LIBCPP_STD_VER >= 17
Expand Down
9 changes: 9 additions & 0 deletions libcxx/include/functional
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,15 @@ template <class T> struct unwrap_ref_decay : unwrap_reference<decay_t<T>> { };
template <class T> using unwrap_reference_t = typename unwrap_reference<T>::type; // since C++20
template <class T> using unwrap_ref_decay_t = typename unwrap_ref_decay<T>::type; // since C++20

// [refwrap.comparisons], comparisons
friend constexpr bool operator==(reference_wrapper, reference_wrapper); // Since C++26
friend constexpr bool operator==(reference_wrapper, const T&); // Since C++26
friend constexpr bool operator==(reference_wrapper, reference_wrapper<const T>); // Since C++26

friend constexpr auto operator<=>(reference_wrapper, reference_wrapper); // Since C++26
friend constexpr auto operator<=>(reference_wrapper, const T&); // Since C++26
friend constexpr auto operator<=>(reference_wrapper, reference_wrapper<const T>); // Since C++26

template <class T> // <class T=void> in C++14
struct plus {
T operator()(const T& x, const T& y) const;
Expand Down
2 changes: 1 addition & 1 deletion libcxx/include/version
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ __cpp_lib_within_lifetime 202306L <type_traits>
// # define __cpp_lib_ranges_concat 202403L
# define __cpp_lib_ratio 202306L
// # define __cpp_lib_rcu 202306L
// # define __cpp_lib_reference_wrapper 202403L
# define __cpp_lib_reference_wrapper 202403L
# define __cpp_lib_saturation_arithmetic 202311L
// # define __cpp_lib_smart_ptr_owner_equality 202306L
# define __cpp_lib_span_at 202311L
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -535,17 +535,11 @@
# error "__cpp_lib_ranges should have the value 202207L in c++26"
# endif

# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_reference_wrapper
# error "__cpp_lib_reference_wrapper should be defined in c++26"
# endif
# if __cpp_lib_reference_wrapper != 202403L
# error "__cpp_lib_reference_wrapper should have the value 202403L in c++26"
# endif
# else // _LIBCPP_VERSION
# ifdef __cpp_lib_reference_wrapper
# error "__cpp_lib_reference_wrapper should not be defined because it is unimplemented in libc++!"
# endif
# ifndef __cpp_lib_reference_wrapper
# error "__cpp_lib_reference_wrapper should be defined in c++26"
# endif
# if __cpp_lib_reference_wrapper != 202403L
# error "__cpp_lib_reference_wrapper should have the value 202403L in c++26"
# endif

# ifndef __cpp_lib_result_of_sfinae
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7464,17 +7464,11 @@
# endif
# endif

# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_reference_wrapper
# error "__cpp_lib_reference_wrapper should be defined in c++26"
# endif
# if __cpp_lib_reference_wrapper != 202403L
# error "__cpp_lib_reference_wrapper should have the value 202403L in c++26"
# endif
# else // _LIBCPP_VERSION
# ifdef __cpp_lib_reference_wrapper
# error "__cpp_lib_reference_wrapper should not be defined because it is unimplemented in libc++!"
# endif
# ifndef __cpp_lib_reference_wrapper
# error "__cpp_lib_reference_wrapper should be defined in c++26"
# endif
# if __cpp_lib_reference_wrapper != 202403L
# error "__cpp_lib_reference_wrapper should have the value 202403L in c++26"
# endif

# ifndef __cpp_lib_remove_cvref
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23

// <functional>

// class reference_wrapper

// [refwrap.comparisons], comparisons

// friend constexpr auto operator<=>(reference_wrapper, const T&); // Since C++26

#include <cassert>
#include <concepts>
#include <functional>

#include "test_comparisons.h"
#include "test_macros.h"

#include "helper_concepts.h"
#include "helper_types.h"

// Test SFINAE.

static_assert(HasSpaceshipOperatorWithInt<std::reference_wrapper<StrongOrder>>);
static_assert(HasSpaceshipOperatorWithInt<std::reference_wrapper<WeakOrder>>);
static_assert(HasSpaceshipOperatorWithInt<std::reference_wrapper<PartialOrder>>);

static_assert(!HasSpaceshipOperatorWithInt<std::reference_wrapper<NonComparable>>);

// Test comparisons.

template <typename T, typename Order>
constexpr void test() {
T t{47};

T bigger{94};
T smaller{82};

T unordered{std::numeric_limits<int>::min()};

// Identical contents
{
std::reference_wrapper<T> rw1{t};
assert(testOrder(rw1, t, Order::equivalent));
}
// Less
{
std::reference_wrapper<T> rw1{smaller};
assert(testOrder(rw1, bigger, Order::less));
}
// Greater
{
std::reference_wrapper<T> rw1{bigger};
assert(testOrder(rw1, smaller, Order::greater));
}
// Unordered
if constexpr (std::same_as<T, PartialOrder>) {
std::reference_wrapper<T> rw1{bigger};
assert(testOrder(rw1, unordered, Order::unordered));
}
}

constexpr bool test() {
test<int, std::strong_ordering>();
test<StrongOrder, std::strong_ordering>();
test<int, std::weak_ordering>();
test<WeakOrder, std::weak_ordering>();
test<int, std::partial_ordering>();
test<PartialOrder, std::partial_ordering>();

// `LessAndEqComp` does not have `operator<=>`. Ordering is synthesized based on `operator<`
test<LessAndEqComp, std::weak_ordering>();

return true;
}

int main(int, char**) {
test();
static_assert(test());

return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23

// <functional>

// class reference_wrapper

// [refwrap.comparisons], comparisons

// friend constexpr auto operator<=>(reference_wrapper, reference_wrapper); // Since C++26

#include <cassert>
#include <concepts>
#include <functional>

#include "test_comparisons.h"
#include "test_macros.h"

#include "helper_concepts.h"
#include "helper_types.h"

// Test SFINAE.

static_assert(std::three_way_comparable<std::reference_wrapper<StrongOrder>>);
static_assert(std::three_way_comparable<std::reference_wrapper<WeakOrder>>);
static_assert(std::three_way_comparable<std::reference_wrapper<PartialOrder>>);

static_assert(!std::three_way_comparable<std::reference_wrapper<NonComparable>>);

// Test comparisons.

template <typename T, typename Order>
constexpr void test() {
T t{47};

T bigger{94};
T smaller{82};

T unordered{std::numeric_limits<int>::min()};

// Identical contents
{
std::reference_wrapper<T> rw1{t};
std::reference_wrapper<T> rw2{t};
assert(testOrder(rw1, rw2, Order::equivalent));
}
// Less
{
std::reference_wrapper<T> rw1{smaller};
std::reference_wrapper<T> rw2{bigger};
assert(testOrder(rw1, rw2, Order::less));
}
// Greater
{
std::reference_wrapper<T> rw1{bigger};
std::reference_wrapper<T> rw2{smaller};
assert(testOrder(rw1, rw2, Order::greater));
}
// Unordered
if constexpr (std::same_as<T, PartialOrder>) {
std::reference_wrapper<T> rw1{bigger};
std::reference_wrapper<T> rw2{unordered};
assert(testOrder(rw1, rw2, Order::unordered));
}
}

constexpr bool test() {
test<int, std::strong_ordering>();
test<StrongOrder, std::strong_ordering>();
test<int, std::weak_ordering>();
test<WeakOrder, std::weak_ordering>();
test<int, std::partial_ordering>();
test<PartialOrder, std::partial_ordering>();

// `LessAndEqComp` does not have `operator<=>`. Ordering is synthesized based on `operator<`
test<LessAndEqComp, std::weak_ordering>();

return true;
}

int main(int, char**) {
test();
static_assert(test());

return 0;
}
Loading
Loading