[libc++][ranges] Add range.cmp: equal_to, not_equal_to, less, etc.

Adds the six new concept constrained comparisons.

Differential Revision: https://reviews.llvm.org/D100429
This commit is contained in:
zoecarver 2021-04-22 17:33:04 -07:00
parent 15be0c41d2
commit 879cbac08b
18 changed files with 618 additions and 178 deletions

View File

@ -507,6 +507,7 @@ POLICY: For non-variadic implementations, the number of arguments is limited
*/
#include <__config>
#include <concepts>
#include <type_traits>
#include <typeinfo>
#include <exception>
@ -3222,6 +3223,80 @@ struct identity {
};
#endif // _LIBCPP_STD_VER > 17
#if !defined(_LIBCPP_HAS_NO_RANGES)
namespace ranges {
struct equal_to {
template <class _Tp, class _Up>
requires equality_comparable_with<_Tp, _Up>
[[nodiscard]] constexpr bool operator()(_Tp &&__t, _Up &&__u) const
noexcept(noexcept(bool(_VSTD::forward<_Tp>(__t) == _VSTD::forward<_Up>(__u)))) {
return _VSTD::forward<_Tp>(__t) == _VSTD::forward<_Up>(__u);
}
using is_transparent = void;
};
struct not_equal_to {
template <class _Tp, class _Up>
requires equality_comparable_with<_Tp, _Up>
[[nodiscard]] constexpr bool operator()(_Tp &&__t, _Up &&__u) const
noexcept(noexcept(bool(!(_VSTD::forward<_Tp>(__t) == _VSTD::forward<_Up>(__u))))) {
return !(_VSTD::forward<_Tp>(__t) == _VSTD::forward<_Up>(__u));
}
using is_transparent = void;
};
struct greater {
template <class _Tp, class _Up>
requires totally_ordered_with<_Tp, _Up>
[[nodiscard]] constexpr bool operator()(_Tp &&__t, _Up &&__u) const
noexcept(noexcept(bool(_VSTD::forward<_Up>(__u) < _VSTD::forward<_Tp>(__t)))) {
return _VSTD::forward<_Up>(__u) < _VSTD::forward<_Tp>(__t);
}
using is_transparent = void;
};
struct less {
template <class _Tp, class _Up>
requires totally_ordered_with<_Tp, _Up>
[[nodiscard]] constexpr bool operator()(_Tp &&__t, _Up &&__u) const
noexcept(noexcept(bool(_VSTD::forward<_Tp>(__t) < _VSTD::forward<_Up>(__u)))) {
return _VSTD::forward<_Tp>(__t) < _VSTD::forward<_Up>(__u);
}
using is_transparent = void;
};
struct greater_equal {
template <class _Tp, class _Up>
requires totally_ordered_with<_Tp, _Up>
[[nodiscard]] constexpr bool operator()(_Tp &&__t, _Up &&__u) const
noexcept(noexcept(bool(!(_VSTD::forward<_Tp>(__t) < _VSTD::forward<_Up>(__u))))) {
return !(_VSTD::forward<_Tp>(__t) < _VSTD::forward<_Up>(__u));
}
using is_transparent = void;
};
struct less_equal {
template <class _Tp, class _Up>
requires totally_ordered_with<_Tp, _Up>
[[nodiscard]] constexpr bool operator()(_Tp &&__t, _Up &&__u) const
noexcept(noexcept(bool(!(_VSTD::forward<_Up>(__u) < _VSTD::forward<_Tp>(__t))))) {
return !(_VSTD::forward<_Up>(__u) < _VSTD::forward<_Tp>(__t));
}
using is_transparent = void;
};
} // namespace ranges
#endif // !defined(_LIBCPP_HAS_NO_RANGES)
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP_FUNCTIONAL

View File

@ -27,7 +27,7 @@
#include <unordered_set>
#include <vector>
#include "../types.h"
#include "compare_types.h"
namespace fundamentals {
static_assert(std::equality_comparable<int>);

View File

@ -27,7 +27,7 @@
#include <unordered_set>
#include <vector>
#include "../types.h"
#include "compare_types.h"
template <class T, class U>
constexpr bool check_equality_comparable_with() {

View File

@ -26,7 +26,7 @@
#include <unordered_set>
#include <vector>
#include "../types.h"
#include "compare_types.h"
#include "test_macros.h"
// `models_totally_ordered` checks that `std::totally_ordered` subsumes

View File

@ -26,7 +26,7 @@
#include <unordered_set>
#include <vector>
#include "../types.h"
#include "compare_types.h"
#include "test_macros.h"
template <class T, class U>

View File

@ -30,7 +30,7 @@ int main(int, char**)
{
// test total ordering of int* for greater<int*> and
// greater<void>.
do_pointer_comparison_test<int, std::greater>();
do_pointer_comparison_test<std::greater>();
}
#if TEST_STD_VER > 11
typedef std::greater<> F2;

View File

@ -30,7 +30,7 @@ int main(int, char**)
{
// test total ordering of int* for greater_equal<int*> and
// greater_equal<void>.
do_pointer_comparison_test<int, std::greater_equal>();
do_pointer_comparison_test<std::greater_equal>();
}
#if TEST_STD_VER > 11
typedef std::greater_equal<> F2;

View File

@ -29,7 +29,7 @@ int main(int, char**)
assert(f(6, 36));
{
// test total ordering of int* for less<int*> and less<void>.
do_pointer_comparison_test<int, std::less>();
do_pointer_comparison_test<std::less>();
}
#if TEST_STD_VER > 11
typedef std::less<> F2;

View File

@ -30,7 +30,7 @@ int main(int, char**)
{
// test total ordering of int* for less_equal<int*> and
// less_equal<void>.
do_pointer_comparison_test<int, std::less_equal>();
do_pointer_comparison_test<std::less_equal>();
}
#if TEST_STD_VER > 11
typedef std::less_equal<> F2;

View File

@ -1,39 +0,0 @@
#ifndef POINTER_COMPARISON_TEST_HELPER_H
#define POINTER_COMPARISON_TEST_HELPER_H
#include <vector>
#include <memory>
#include <cstdint>
#include <cassert>
#include "test_macros.h"
template <class T, template<class> class CompareTemplate>
void do_pointer_comparison_test() {
typedef CompareTemplate<T*> Compare;
typedef CompareTemplate<std::uintptr_t> UIntCompare;
#if TEST_STD_VER > 11
typedef CompareTemplate<void> VoidCompare;
#else
typedef Compare VoidCompare;
#endif
std::vector<std::shared_ptr<T> > pointers;
const std::size_t test_size = 100;
for (size_t i=0; i < test_size; ++i)
pointers.push_back(std::shared_ptr<T>(new T()));
Compare comp;
UIntCompare ucomp;
VoidCompare vcomp;
for (size_t i=0; i < test_size; ++i) {
for (size_t j=0; j < test_size; ++j) {
T* lhs = pointers[i].get();
T* rhs = pointers[j].get();
std::uintptr_t lhs_uint = reinterpret_cast<std::uintptr_t>(lhs);
std::uintptr_t rhs_uint = reinterpret_cast<std::uintptr_t>(rhs);
assert(comp(lhs, rhs) == ucomp(lhs_uint, rhs_uint));
assert(vcomp(lhs, rhs) == ucomp(lhs_uint, rhs_uint));
}
}
}
#endif // POINTER_COMPARISON_TEST_HELPER_H

View File

@ -0,0 +1,64 @@
//===----------------------------------------------------------------------===//
//
// 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
// UNSUPPORTED: libcpp-no-concepts
// <functional>
// ranges::equal_to
#include <functional>
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "compare_types.h"
#include "MoveOnly.h"
#include "pointer_comparison_test_helper.h"
struct NotEqualityComparable {
friend bool operator==(const NotEqualityComparable&, const NotEqualityComparable&);
friend bool operator!=(const NotEqualityComparable&, const NotEqualityComparable&) = delete;
};
static_assert(!std::is_invocable_v<std::ranges::equal_to, NotEqualityComparable, NotEqualityComparable>);
static_assert(!std::is_invocable_v<std::ranges::equal_to, int, MoveOnly>);
static_assert(std::is_invocable_v<std::ranges::equal_to, explicit_operators, explicit_operators>);
static_assert(requires { typename std::ranges::equal_to::is_transparent; });
constexpr bool test() {
auto fn = std::ranges::equal_to();
assert(fn(MoveOnly(42), MoveOnly(42)));
ForwardingTestObject a;
ForwardingTestObject b;
assert(!fn(a, b));
assert(fn(std::move(a), std::move(b)));
assert(!fn(1, 2));
assert(!fn(2, 1));
assert(fn(2, 2));
assert(!fn(2, 1L));
return true;
}
int main(int, char**) {
test();
static_assert(test());
// test total ordering of int* for equal_to<int*> and equal_to<void>.
do_pointer_comparison_test(std::ranges::equal_to());
return 0;
}

View File

@ -0,0 +1,63 @@
//===----------------------------------------------------------------------===//
//
// 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
// UNSUPPORTED: libcpp-no-concepts
// <functional>
// ranges::greater
#include <functional>
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "compare_types.h"
#include "MoveOnly.h"
#include "pointer_comparison_test_helper.h"
struct NotTotallyOrdered {
friend bool operator<(const NotTotallyOrdered&, const NotTotallyOrdered&);
};
static_assert(!std::is_invocable_v<std::ranges::greater, NotTotallyOrdered, NotTotallyOrdered>);
static_assert(!std::is_invocable_v<std::ranges::greater, int, MoveOnly>);
static_assert(std::is_invocable_v<std::ranges::greater, explicit_operators, explicit_operators>);
static_assert(requires { typename std::ranges::greater::is_transparent; });
constexpr bool test() {
auto fn = std::ranges::greater();
assert(fn(MoveOnly(42), MoveOnly(41)));
ForwardingTestObject a;
ForwardingTestObject b;
assert(!fn(a, b));
assert(fn(std::move(a), std::move(b)));
assert(!fn(2, 2));
assert(!fn(1, 2));
assert(fn(2, 1));
assert(fn(2, 1L));
return true;
}
int main(int, char**) {
test();
static_assert(test());
// test total ordering of int* for greater<int*> and greater<void>.
do_pointer_comparison_test(std::ranges::greater());
return 0;
}

View File

@ -0,0 +1,63 @@
//===----------------------------------------------------------------------===//
//
// 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
// UNSUPPORTED: libcpp-no-concepts
// <functional>
// ranges::greater_equal
#include <functional>
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "compare_types.h"
#include "MoveOnly.h"
#include "pointer_comparison_test_helper.h"
struct NotTotallyOrdered {
friend bool operator<(const NotTotallyOrdered&, const NotTotallyOrdered&);
};
static_assert(!std::is_invocable_v<std::ranges::greater_equal, NotTotallyOrdered, NotTotallyOrdered>);
static_assert(!std::is_invocable_v<std::ranges::greater_equal, int, MoveOnly>);
static_assert(std::is_invocable_v<std::ranges::greater_equal, explicit_operators, explicit_operators>);
static_assert(requires { typename std::ranges::greater_equal::is_transparent; });
constexpr bool test() {
auto fn = std::ranges::greater_equal();
assert(fn(MoveOnly(42), MoveOnly(42)));
ForwardingTestObject a;
ForwardingTestObject b;
assert(fn(a, b));
assert(!fn(std::move(a), std::move(b)));
assert(fn(2, 2));
assert(fn(2, 1));
assert(!fn(1, 2));
assert(fn(2, 1L));
return true;
}
int main(int, char**) {
test();
static_assert(test());
// test total ordering of int* for greater_equal<int*> and greater_equal<void>.
do_pointer_comparison_test(std::ranges::greater_equal());
return 0;
}

View File

@ -0,0 +1,63 @@
//===----------------------------------------------------------------------===//
//
// 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
// UNSUPPORTED: libcpp-no-concepts
// <functional>
// ranges::less
#include <functional>
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "compare_types.h"
#include "MoveOnly.h"
#include "pointer_comparison_test_helper.h"
struct NotTotallyOrdered {
friend bool operator<(const NotTotallyOrdered&, const NotTotallyOrdered&);
};
static_assert(!std::is_invocable_v<std::ranges::less, NotTotallyOrdered, NotTotallyOrdered>);
static_assert(!std::is_invocable_v<std::ranges::less, int, MoveOnly>);
static_assert(std::is_invocable_v<std::ranges::less, explicit_operators, explicit_operators>);
static_assert(requires { typename std::ranges::less::is_transparent; });
constexpr bool test() {
auto fn = std::ranges::less();
assert(fn(MoveOnly(41), MoveOnly(42)));
ForwardingTestObject a;
ForwardingTestObject b;
assert(!fn(a, b));
assert(fn(std::move(a), std::move(b)));
assert(fn(1, 2));
assert(!fn(2, 2));
assert(!fn(2, 1));
assert(!fn(2, 1L));
return true;
}
int main(int, char**) {
test();
static_assert(test());
// test total ordering of int* for less<int*> and less<void>.
do_pointer_comparison_test(std::ranges::less());
return 0;
}

View File

@ -0,0 +1,64 @@
//===----------------------------------------------------------------------===//
//
// 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
// UNSUPPORTED: libcpp-no-concepts
// <functional>
// ranges::less_equal
#include <functional>
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "compare_types.h"
#include "MoveOnly.h"
#include "pointer_comparison_test_helper.h"
struct NotTotallyOrdered {
friend bool operator<(const NotTotallyOrdered&, const NotTotallyOrdered&);
};
static_assert(!std::is_invocable_v<std::ranges::less_equal, NotTotallyOrdered, NotTotallyOrdered>);
static_assert(!std::is_invocable_v<std::ranges::less_equal, int, MoveOnly>);
static_assert(std::is_invocable_v<std::ranges::less_equal, explicit_operators, explicit_operators>);
static_assert(requires { typename std::ranges::less_equal::is_transparent; });
constexpr bool test() {
auto fn = std::ranges::less_equal();
assert(fn(MoveOnly(41), MoveOnly(42)));
// These are the opposite of other tests.
ForwardingTestObject a;
ForwardingTestObject b;
assert(fn(a, b));
assert(!fn(std::move(a), std::move(b)));
assert(fn(1, 2));
assert(fn(2, 2));
assert(!fn(2, 1));
assert(!fn(2, 1L));
return true;
}
int main(int, char**) {
test();
static_assert(test());
// test total ordering of int* for less_equal<int*> and less_equal<void>.
do_pointer_comparison_test(std::ranges::less_equal());
return 0;
}

View File

@ -0,0 +1,75 @@
//===----------------------------------------------------------------------===//
//
// 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
// UNSUPPORTED: libcpp-no-concepts
// <functional>
// ranges::not_equal_to
#include <functional>
#include <type_traits>
#include <cassert>
#include "test_macros.h"
#include "compare_types.h"
#include "MoveOnly.h"
#include "pointer_comparison_test_helper.h"
struct NotEqualityComparable {
friend bool operator==(const NotEqualityComparable&, const NotEqualityComparable&);
friend bool operator!=(const NotEqualityComparable&, const NotEqualityComparable&) = delete;
};
static_assert(!std::is_invocable_v<std::ranges::equal_to, NotEqualityComparable, NotEqualityComparable>);
static_assert(!std::is_invocable_v<std::ranges::equal_to, int, MoveOnly>);
static_assert(std::is_invocable_v<std::ranges::equal_to, explicit_operators, explicit_operators>);
static_assert(requires { typename std::ranges::not_equal_to::is_transparent; });
struct PtrAndNotEqOperator {
constexpr operator void*() const { return nullptr; }
// We *don't* want operator!= to be picked here.
friend constexpr bool operator!=(PtrAndNotEqOperator, PtrAndNotEqOperator) { return true; }
};
constexpr bool test() {
auto fn = std::ranges::not_equal_to();
assert(fn(MoveOnly(41), MoveOnly(42)));
// These are the opposite of other tests.
ForwardingTestObject a;
ForwardingTestObject b;
assert(fn(a, b));
assert(!fn(std::move(a), std::move(b)));
assert(fn(1, 2));
assert(!fn(2, 2));
assert(fn(2, 1));
assert(fn(2, 1L));
// Make sure that "ranges::equal_to(x, y) == !ranges::not_equal_to(x, y)", even here.
assert(!fn(PtrAndNotEqOperator(), PtrAndNotEqOperator()));
assert(std::ranges::equal_to()(PtrAndNotEqOperator(), PtrAndNotEqOperator()));
return true;
}
int main(int, char**) {
test();
static_assert(test());
// test total ordering of int* for not_equal_to<int*> and not_equal_to<void>.
do_pointer_comparison_test(std::ranges::not_equal_to());
return 0;
}

View File

@ -5,8 +5,8 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef TEST_STD_CONCEPTS_COMPARISON_TYPES_H
#define TEST_STD_CONCEPTS_COMPARISON_TYPES_H
#ifndef TEST_SUPPORT_COMPARE_TYPES_H
#define TEST_SUPPORT_COMPARE_TYPES_H
#include <compare>
#include <concepts>
@ -23,8 +23,7 @@ struct cxx20_member_eq {
};
struct cxx20_friend_eq {
friend bool operator==(cxx20_friend_eq const&,
cxx20_friend_eq const&) = default;
friend bool operator==(cxx20_friend_eq const&, cxx20_friend_eq const&) = default;
};
struct member_three_way_comparable {
@ -32,8 +31,7 @@ struct member_three_way_comparable {
};
struct friend_three_way_comparable {
friend auto operator<=>(friend_three_way_comparable const&,
friend_three_way_comparable const&) = default;
friend auto operator<=>(friend_three_way_comparable const&, friend_three_way_comparable const&) = default;
};
struct explicit_operators {
@ -43,16 +41,11 @@ struct explicit_operators {
friend bool operator>(explicit_operators, explicit_operators) noexcept;
friend bool operator<=(explicit_operators, explicit_operators) noexcept;
friend bool operator>=(explicit_operators, explicit_operators) noexcept;
friend bool operator<=>(explicit_operators, explicit_operators) noexcept;
friend bool operator==(explicit_operators const&,
equality_comparable_with_ec1 const&) noexcept;
friend bool operator==(equality_comparable_with_ec1 const&,
explicit_operators const&) noexcept;
friend bool operator!=(explicit_operators const&,
equality_comparable_with_ec1 const&) noexcept;
friend bool operator!=(equality_comparable_with_ec1 const&,
explicit_operators const&) noexcept;
friend bool operator==(explicit_operators const&, equality_comparable_with_ec1 const&) noexcept;
friend bool operator==(equality_comparable_with_ec1 const&, explicit_operators const&) noexcept;
friend bool operator!=(explicit_operators const&, equality_comparable_with_ec1 const&) noexcept;
friend bool operator!=(equality_comparable_with_ec1 const&, explicit_operators const&) noexcept;
};
struct different_return_types {
@ -76,8 +69,7 @@ struct boolean {
};
struct one_member_one_friend {
friend boolean operator==(one_member_one_friend,
one_member_one_friend) noexcept;
friend boolean operator==(one_member_one_friend, one_member_one_friend) noexcept;
boolean operator!=(one_member_one_friend) const noexcept;
operator explicit_operators() const noexcept;
@ -208,51 +200,39 @@ struct wrong_return_type {
};
struct cxx20_member_eq_operator_with_deleted_ne {
bool
operator==(cxx20_member_eq_operator_with_deleted_ne const&) const = default;
bool
operator!=(cxx20_member_eq_operator_with_deleted_ne const&) const = delete;
bool operator==(cxx20_member_eq_operator_with_deleted_ne const&) const = default;
bool operator!=(cxx20_member_eq_operator_with_deleted_ne const&) const = delete;
};
struct cxx20_friend_eq_operator_with_deleted_ne {
friend bool
operator==(cxx20_friend_eq_operator_with_deleted_ne const&,
cxx20_friend_eq_operator_with_deleted_ne const&) = default;
friend bool
operator!=(cxx20_friend_eq_operator_with_deleted_ne const&,
cxx20_friend_eq_operator_with_deleted_ne const&) = delete;
friend bool operator==(cxx20_friend_eq_operator_with_deleted_ne const&,
cxx20_friend_eq_operator_with_deleted_ne const&) = default;
friend bool operator!=(cxx20_friend_eq_operator_with_deleted_ne const&,
cxx20_friend_eq_operator_with_deleted_ne const&) = delete;
};
struct member_three_way_comparable_with_deleted_eq {
auto operator<=>(member_three_way_comparable_with_deleted_eq const&) const =
default;
bool
operator==(member_three_way_comparable_with_deleted_eq const&) const = delete;
auto operator<=>(member_three_way_comparable_with_deleted_eq const&) const = default;
bool operator==(member_three_way_comparable_with_deleted_eq const&) const = delete;
};
struct member_three_way_comparable_with_deleted_ne {
auto operator<=>(member_three_way_comparable_with_deleted_ne const&) const =
default;
bool
operator!=(member_three_way_comparable_with_deleted_ne const&) const = delete;
auto operator<=>(member_three_way_comparable_with_deleted_ne const&) const = default;
bool operator!=(member_three_way_comparable_with_deleted_ne const&) const = delete;
};
struct friend_three_way_comparable_with_deleted_eq {
friend auto
operator<=>(friend_three_way_comparable_with_deleted_eq const&,
friend_three_way_comparable_with_deleted_eq const&) = default;
friend bool
operator==(friend_three_way_comparable_with_deleted_eq const&,
friend_three_way_comparable_with_deleted_eq const&) = delete;
friend auto operator<=>(friend_three_way_comparable_with_deleted_eq const&,
friend_three_way_comparable_with_deleted_eq const&) = default;
friend bool operator==(friend_three_way_comparable_with_deleted_eq const&,
friend_three_way_comparable_with_deleted_eq const&) = delete;
};
struct friend_three_way_comparable_with_deleted_ne {
friend auto
operator<=>(friend_three_way_comparable_with_deleted_ne const&,
friend_three_way_comparable_with_deleted_ne const&) = default;
friend bool
operator!=(friend_three_way_comparable_with_deleted_ne const&,
friend_three_way_comparable_with_deleted_ne const&) = delete;
friend auto operator<=>(friend_three_way_comparable_with_deleted_ne const&,
friend_three_way_comparable_with_deleted_ne const&) = default;
friend bool operator!=(friend_three_way_comparable_with_deleted_ne const&,
friend_three_way_comparable_with_deleted_ne const&) = delete;
};
struct one_way_eq {
@ -270,9 +250,7 @@ struct one_way_ne {
operator explicit_operators() const;
};
static_assert(requires(explicit_operators const x, one_way_ne const y) {
x != y;
});
static_assert(requires(explicit_operators const x, one_way_ne const y) { x != y; });
struct explicit_bool {
explicit operator bool() const noexcept;
@ -283,10 +261,8 @@ struct totally_ordered_with_others {
};
struct no_lt_not_totally_ordered_with {
[[nodiscard]] bool
operator==(no_lt_not_totally_ordered_with const&) const = default;
[[nodiscard]] auto
operator<=>(no_lt_not_totally_ordered_with const&) const = default;
[[nodiscard]] bool operator==(no_lt_not_totally_ordered_with const&) const = default;
[[nodiscard]] auto operator<=>(no_lt_not_totally_ordered_with const&) const = default;
operator totally_ordered_with_others() const noexcept;
[[nodiscard]] bool operator==(totally_ordered_with_others const&) const;
@ -295,10 +271,8 @@ struct no_lt_not_totally_ordered_with {
};
struct no_gt_not_totally_ordered_with {
[[nodiscard]] bool
operator==(no_gt_not_totally_ordered_with const&) const = default;
[[nodiscard]] auto
operator<=>(no_gt_not_totally_ordered_with const&) const = default;
[[nodiscard]] bool operator==(no_gt_not_totally_ordered_with const&) const = default;
[[nodiscard]] auto operator<=>(no_gt_not_totally_ordered_with const&) const = default;
operator totally_ordered_with_others() const noexcept;
[[nodiscard]] bool operator==(totally_ordered_with_others const&) const;
@ -307,10 +281,8 @@ struct no_gt_not_totally_ordered_with {
};
struct no_le_not_totally_ordered_with {
[[nodiscard]] bool
operator==(no_le_not_totally_ordered_with const&) const = default;
[[nodiscard]] auto
operator<=>(no_le_not_totally_ordered_with const&) const = default;
[[nodiscard]] bool operator==(no_le_not_totally_ordered_with const&) const = default;
[[nodiscard]] auto operator<=>(no_le_not_totally_ordered_with const&) const = default;
operator totally_ordered_with_others() const noexcept;
[[nodiscard]] bool operator==(totally_ordered_with_others const&) const;
@ -319,10 +291,8 @@ struct no_le_not_totally_ordered_with {
};
struct no_ge_not_totally_ordered_with {
[[nodiscard]] bool
operator==(no_ge_not_totally_ordered_with const&) const = default;
[[nodiscard]] auto
operator<=>(no_ge_not_totally_ordered_with const&) const = default;
[[nodiscard]] bool operator==(no_ge_not_totally_ordered_with const&) const = default;
[[nodiscard]] auto operator<=>(no_ge_not_totally_ordered_with const&) const = default;
operator totally_ordered_with_others() const noexcept;
[[nodiscard]] bool operator==(totally_ordered_with_others const&) const;
@ -331,35 +301,28 @@ struct no_ge_not_totally_ordered_with {
};
struct partial_ordering_totally_ordered_with {
[[nodiscard]] auto operator<=>(
partial_ordering_totally_ordered_with const&) const noexcept = default;
[[nodiscard]] std::partial_ordering
operator<=>(totally_ordered_with_others const&) const noexcept;
[[nodiscard]] auto operator<=>(partial_ordering_totally_ordered_with const&) const noexcept = default;
[[nodiscard]] std::partial_ordering operator<=>(totally_ordered_with_others const&) const noexcept;
operator totally_ordered_with_others() const;
};
struct weak_ordering_totally_ordered_with {
[[nodiscard]] auto operator<=>(
weak_ordering_totally_ordered_with const&) const noexcept = default;
[[nodiscard]] std::weak_ordering
operator<=>(totally_ordered_with_others const&) const noexcept;
[[nodiscard]] auto operator<=>(weak_ordering_totally_ordered_with const&) const noexcept = default;
[[nodiscard]] std::weak_ordering operator<=>(totally_ordered_with_others const&) const noexcept;
operator totally_ordered_with_others() const;
};
struct strong_ordering_totally_ordered_with {
[[nodiscard]] auto operator<=>(
strong_ordering_totally_ordered_with const&) const noexcept = default;
[[nodiscard]] std::strong_ordering
operator<=>(totally_ordered_with_others const&) const noexcept;
[[nodiscard]] auto operator<=>(strong_ordering_totally_ordered_with const&) const noexcept = default;
[[nodiscard]] std::strong_ordering operator<=>(totally_ordered_with_others const&) const noexcept;
operator totally_ordered_with_others() const;
};
struct eq_returns_explicit_bool {
friend explicit_bool operator==(eq_returns_explicit_bool,
eq_returns_explicit_bool);
friend explicit_bool operator==(eq_returns_explicit_bool, eq_returns_explicit_bool);
friend bool operator!=(eq_returns_explicit_bool, eq_returns_explicit_bool);
friend bool operator<(eq_returns_explicit_bool, eq_returns_explicit_bool);
friend bool operator>(eq_returns_explicit_bool, eq_returns_explicit_bool);
@ -368,10 +331,8 @@ struct eq_returns_explicit_bool {
operator totally_ordered_with_others() const;
friend explicit_bool operator==(eq_returns_explicit_bool,
totally_ordered_with_others);
friend explicit_bool operator==(totally_ordered_with_others,
eq_returns_explicit_bool);
friend explicit_bool operator==(eq_returns_explicit_bool, totally_ordered_with_others);
friend explicit_bool operator==(totally_ordered_with_others, eq_returns_explicit_bool);
friend bool operator!=(eq_returns_explicit_bool, totally_ordered_with_others);
friend bool operator!=(totally_ordered_with_others, eq_returns_explicit_bool);
friend bool operator<(eq_returns_explicit_bool, totally_ordered_with_others);
@ -386,8 +347,7 @@ struct eq_returns_explicit_bool {
struct ne_returns_explicit_bool {
friend bool operator==(ne_returns_explicit_bool, ne_returns_explicit_bool);
friend explicit_bool operator!=(ne_returns_explicit_bool,
ne_returns_explicit_bool);
friend explicit_bool operator!=(ne_returns_explicit_bool, ne_returns_explicit_bool);
friend bool operator<(ne_returns_explicit_bool, ne_returns_explicit_bool);
friend bool operator>(ne_returns_explicit_bool, ne_returns_explicit_bool);
friend bool operator<=(ne_returns_explicit_bool, ne_returns_explicit_bool);
@ -396,10 +356,8 @@ struct ne_returns_explicit_bool {
operator totally_ordered_with_others() const;
friend bool operator==(ne_returns_explicit_bool, totally_ordered_with_others);
friend explicit_bool operator!=(ne_returns_explicit_bool,
totally_ordered_with_others);
friend explicit_bool operator!=(totally_ordered_with_others,
ne_returns_explicit_bool);
friend explicit_bool operator!=(ne_returns_explicit_bool, totally_ordered_with_others);
friend explicit_bool operator!=(totally_ordered_with_others, ne_returns_explicit_bool);
friend bool operator<(ne_returns_explicit_bool, totally_ordered_with_others);
friend bool operator<(totally_ordered_with_others, ne_returns_explicit_bool);
friend bool operator>(ne_returns_explicit_bool, totally_ordered_with_others);
@ -413,8 +371,7 @@ struct ne_returns_explicit_bool {
struct lt_returns_explicit_bool {
friend bool operator==(lt_returns_explicit_bool, lt_returns_explicit_bool);
friend bool operator!=(lt_returns_explicit_bool, lt_returns_explicit_bool);
friend explicit_bool operator<(lt_returns_explicit_bool,
lt_returns_explicit_bool);
friend explicit_bool operator<(lt_returns_explicit_bool, lt_returns_explicit_bool);
friend bool operator>(lt_returns_explicit_bool, lt_returns_explicit_bool);
friend bool operator<=(lt_returns_explicit_bool, lt_returns_explicit_bool);
friend bool operator>=(lt_returns_explicit_bool, lt_returns_explicit_bool);
@ -424,8 +381,7 @@ struct lt_returns_explicit_bool {
friend bool operator==(lt_returns_explicit_bool, totally_ordered_with_others);
friend bool operator!=(lt_returns_explicit_bool, totally_ordered_with_others);
friend bool operator!=(totally_ordered_with_others, lt_returns_explicit_bool);
friend explicit_bool operator<(lt_returns_explicit_bool,
totally_ordered_with_others);
friend explicit_bool operator<(lt_returns_explicit_bool, totally_ordered_with_others);
friend bool operator<(totally_ordered_with_others, lt_returns_explicit_bool);
friend bool operator>(lt_returns_explicit_bool, totally_ordered_with_others);
friend bool operator>(totally_ordered_with_others, lt_returns_explicit_bool);
@ -439,8 +395,7 @@ struct gt_returns_explicit_bool {
friend bool operator==(gt_returns_explicit_bool, gt_returns_explicit_bool);
friend bool operator!=(gt_returns_explicit_bool, gt_returns_explicit_bool);
friend bool operator<(gt_returns_explicit_bool, gt_returns_explicit_bool);
friend explicit_bool operator>(gt_returns_explicit_bool,
gt_returns_explicit_bool);
friend explicit_bool operator>(gt_returns_explicit_bool, gt_returns_explicit_bool);
friend bool operator<=(gt_returns_explicit_bool, gt_returns_explicit_bool);
friend bool operator>=(gt_returns_explicit_bool, gt_returns_explicit_bool);
@ -451,8 +406,7 @@ struct gt_returns_explicit_bool {
friend bool operator!=(totally_ordered_with_others, gt_returns_explicit_bool);
friend bool operator<(gt_returns_explicit_bool, totally_ordered_with_others);
friend bool operator<(totally_ordered_with_others, gt_returns_explicit_bool);
friend explicit_bool operator>(gt_returns_explicit_bool,
totally_ordered_with_others);
friend explicit_bool operator>(gt_returns_explicit_bool, totally_ordered_with_others);
friend bool operator>(totally_ordered_with_others, gt_returns_explicit_bool);
friend bool operator<=(gt_returns_explicit_bool, totally_ordered_with_others);
friend bool operator<=(totally_ordered_with_others, gt_returns_explicit_bool);
@ -465,8 +419,7 @@ struct le_returns_explicit_bool {
friend bool operator!=(le_returns_explicit_bool, le_returns_explicit_bool);
friend bool operator<(le_returns_explicit_bool, le_returns_explicit_bool);
friend bool operator>(le_returns_explicit_bool, le_returns_explicit_bool);
friend explicit_bool operator<=(le_returns_explicit_bool,
le_returns_explicit_bool);
friend explicit_bool operator<=(le_returns_explicit_bool, le_returns_explicit_bool);
friend bool operator>=(le_returns_explicit_bool, le_returns_explicit_bool);
operator totally_ordered_with_others() const;
@ -479,8 +432,7 @@ struct le_returns_explicit_bool {
friend bool operator>(le_returns_explicit_bool, totally_ordered_with_others);
friend bool operator>(totally_ordered_with_others, le_returns_explicit_bool);
friend bool operator<=(le_returns_explicit_bool, totally_ordered_with_others);
friend explicit_bool operator<=(totally_ordered_with_others,
le_returns_explicit_bool);
friend explicit_bool operator<=(totally_ordered_with_others, le_returns_explicit_bool);
friend bool operator>=(le_returns_explicit_bool, totally_ordered_with_others);
friend bool operator>=(totally_ordered_with_others, le_returns_explicit_bool);
};
@ -491,8 +443,7 @@ struct ge_returns_explicit_bool {
friend bool operator<(ge_returns_explicit_bool, ge_returns_explicit_bool);
friend bool operator>(ge_returns_explicit_bool, ge_returns_explicit_bool);
friend bool operator<=(ge_returns_explicit_bool, ge_returns_explicit_bool);
friend explicit_bool operator>=(ge_returns_explicit_bool,
ge_returns_explicit_bool);
friend explicit_bool operator>=(ge_returns_explicit_bool, ge_returns_explicit_bool);
operator totally_ordered_with_others() const;
@ -506,8 +457,7 @@ struct ge_returns_explicit_bool {
friend bool operator<=(ge_returns_explicit_bool, totally_ordered_with_others);
friend bool operator<=(totally_ordered_with_others, ge_returns_explicit_bool);
friend bool operator>=(ge_returns_explicit_bool, totally_ordered_with_others);
friend explicit_bool operator>=(totally_ordered_with_others,
ge_returns_explicit_bool);
friend explicit_bool operator>=(totally_ordered_with_others, ge_returns_explicit_bool);
};
struct returns_true_type {
@ -520,30 +470,18 @@ struct returns_true_type {
operator totally_ordered_with_others() const;
friend std::true_type operator==(returns_true_type,
totally_ordered_with_others);
friend std::true_type operator==(totally_ordered_with_others,
returns_true_type);
friend std::true_type operator!=(returns_true_type,
totally_ordered_with_others);
friend std::true_type operator!=(totally_ordered_with_others,
returns_true_type);
friend std::true_type operator<(returns_true_type,
totally_ordered_with_others);
friend std::true_type operator<(totally_ordered_with_others,
returns_true_type);
friend std::true_type operator>(returns_true_type,
totally_ordered_with_others);
friend std::true_type operator>(totally_ordered_with_others,
returns_true_type);
friend std::true_type operator<=(returns_true_type,
totally_ordered_with_others);
friend std::true_type operator<=(totally_ordered_with_others,
returns_true_type);
friend std::true_type operator>=(returns_true_type,
totally_ordered_with_others);
friend std::true_type operator>=(totally_ordered_with_others,
returns_true_type);
friend std::true_type operator==(returns_true_type, totally_ordered_with_others);
friend std::true_type operator==(totally_ordered_with_others, returns_true_type);
friend std::true_type operator!=(returns_true_type, totally_ordered_with_others);
friend std::true_type operator!=(totally_ordered_with_others, returns_true_type);
friend std::true_type operator<(returns_true_type, totally_ordered_with_others);
friend std::true_type operator<(totally_ordered_with_others, returns_true_type);
friend std::true_type operator>(returns_true_type, totally_ordered_with_others);
friend std::true_type operator>(totally_ordered_with_others, returns_true_type);
friend std::true_type operator<=(returns_true_type, totally_ordered_with_others);
friend std::true_type operator<=(totally_ordered_with_others, returns_true_type);
friend std::true_type operator>=(returns_true_type, totally_ordered_with_others);
friend std::true_type operator>=(totally_ordered_with_others, returns_true_type);
};
struct returns_int_ptr {
@ -570,4 +508,24 @@ struct returns_int_ptr {
friend int* operator>=(totally_ordered_with_others, returns_int_ptr);
};
#endif // TEST_STD_CONCEPTS_COMPARISON_TYPES_H
struct ForwardingTestObject {
constexpr bool operator<(ForwardingTestObject&&) && { return true; }
constexpr bool operator<(const ForwardingTestObject&) const& { return false; }
constexpr bool operator==(ForwardingTestObject&&) && { return true; }
constexpr bool operator==(const ForwardingTestObject&) const& { return false; }
constexpr bool operator!=(ForwardingTestObject&&) && { return true; }
constexpr bool operator!=(const ForwardingTestObject&) const& { return false; }
constexpr bool operator<=(ForwardingTestObject&&) && { return true; }
constexpr bool operator<=(const ForwardingTestObject&) const& { return false; }
constexpr bool operator>(ForwardingTestObject&&) && { return true; }
constexpr bool operator>(const ForwardingTestObject&) const& { return false; }
constexpr bool operator>=(ForwardingTestObject&&) && { return true; }
constexpr bool operator>=(const ForwardingTestObject&) const& { return false; }
};
#endif // TEST_SUPPORT_COMPARE_TYPES_H

View File

@ -0,0 +1,54 @@
#ifndef POINTER_COMPARISON_TEST_HELPER_H
#define POINTER_COMPARISON_TEST_HELPER_H
#include <cstdint>
#include <cassert>
#include "test_macros.h"
template <template <class> class CompareTemplate>
void do_pointer_comparison_test() {
typedef CompareTemplate<int*> Compare;
typedef CompareTemplate<std::uintptr_t> UIntCompare;
#if TEST_STD_VER > 11
typedef CompareTemplate<void> VoidCompare;
#else
typedef Compare VoidCompare;
#endif
Compare comp;
UIntCompare ucomp;
VoidCompare vcomp;
struct {
int a, b;
} local;
int* pointers[] = {&local.a, &local.b, nullptr, &local.a + 1};
for (int* lhs : pointers) {
for (int* rhs : pointers) {
std::uintptr_t lhs_uint = reinterpret_cast<std::uintptr_t>(lhs);
std::uintptr_t rhs_uint = reinterpret_cast<std::uintptr_t>(rhs);
assert(comp(lhs, rhs) == ucomp(lhs_uint, rhs_uint));
assert(vcomp(lhs, rhs) == ucomp(lhs_uint, rhs_uint));
}
}
}
template <class Comp>
void do_pointer_comparison_test(Comp comp) {
struct {
int a, b;
} local;
int* pointers[] = {&local.a, &local.b, nullptr, &local.a + 1};
for (int* lhs : pointers) {
for (int* rhs : pointers) {
std::uintptr_t lhs_uint = reinterpret_cast<std::uintptr_t>(lhs);
std::uintptr_t rhs_uint = reinterpret_cast<std::uintptr_t>(rhs);
void* lhs_void = static_cast<void*>(lhs);
void* rhs_void = static_cast<void*>(rhs);
assert(comp(lhs, rhs) == comp(lhs_uint, rhs_uint));
assert(comp(lhs_void, rhs_void) == comp(lhs_uint, rhs_uint));
}
}
}
#endif // POINTER_COMPARISON_TEST_HELPER_H