[libcxx] adds remaining callable concepts

* `std::predicate`
* `std::relation`
* `std::equivalence_relation`
* `std::strict_weak_order`

Implements parts of:
    - P0898R3 Standard Library Concepts
    - P1754 Rename concepts to standard_case for C++20, while we still can

Differential Revision: https://reviews.llvm.org/D96477
This commit is contained in:
Christopher Di Bella 2021-03-31 05:28:25 +00:00
parent 9c8b28a69b
commit 96dbdd753a
10 changed files with 522 additions and 2 deletions

View File

@ -76,7 +76,7 @@
"`P1209R0 <https://wg21.link/P1209R0>`__","LWG","Adopt Consistent Container Erasure from Library Fundamentals 2 for C++20","San Diego","|Complete|","8.0"
"`P1210R0 <https://wg21.link/P1210R0>`__","LWG","Completing the Rebase of Library Fundamentals, Version 3, Working Draft","San Diego","* *",""
"`P1236R1 <https://wg21.link/P1236R1>`__","CWG","Alternative Wording for P0907R4 Signed Integers are Two's Complement","San Diego","* *",""
"`P1248R1 <https://wg21.link/P1248R1>`__","LWG","Remove CommonReference requirement from StrictWeakOrdering (a.k.a Fixing Relations)","San Diego","* *",""
"`P1248R1 <https://wg21.link/P1248R1>`__","LWG","Remove CommonReference requirement from StrictWeakOrdering (a.k.a Fixing Relations)","San Diego","|Complete|","13.0"
"`P1285R0 <https://wg21.link/P1285R0>`__","LWG","Improving Completeness Requirements for Type Traits","San Diego","* *",""
"`P1353R0 <https://wg21.link/P1353R0>`__","CWG","Missing feature test macros","San Diego","* *",""
"","","","","",""

1 Paper # Group Paper Name Meeting Status First released version
76 `P1209R0 <https://wg21.link/P1209R0>`__ LWG Adopt Consistent Container Erasure from Library Fundamentals 2 for C++20 San Diego |Complete| 8.0
77 `P1210R0 <https://wg21.link/P1210R0>`__ LWG Completing the Rebase of Library Fundamentals, Version 3, Working Draft San Diego * *
78 `P1236R1 <https://wg21.link/P1236R1>`__ CWG Alternative Wording for P0907R4 Signed Integers are Two's Complement San Diego * *
79 `P1248R1 <https://wg21.link/P1248R1>`__ LWG Remove CommonReference requirement from StrictWeakOrdering (a.k.a Fixing Relations) San Diego * * |Complete| 13.0
80 `P1285R0 <https://wg21.link/P1285R0>`__ LWG Improving Completeness Requirements for Type Traits San Diego * *
81 `P1353R0 <https://wg21.link/P1353R0>`__ CWG Missing feature test macros San Diego * *
82

View File

@ -426,7 +426,25 @@ concept invocable = requires(_Fn&& __fn, _Args&&... __args) {
template<class _Fn, class... _Args>
concept regular_invocable = invocable<_Fn, _Args...>;
#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS)
// [concept.predicate]
template<class _Fn, class... _Args>
concept predicate =
regular_invocable<_Fn, _Args...> && __boolean_testable<invoke_result_t<_Fn, _Args...>>;
// [concept.relation]
template<class _Rp, class _Tp, class _Up>
concept relation =
predicate<_Rp, _Tp, _Tp> && predicate<_Rp, _Up, _Up> &&
predicate<_Rp, _Tp, _Up> && predicate<_Rp, _Up, _Tp>;
// [concept.equiv]
template<class _Rp, class _Tp, class _Up>
concept equivalence_relation = relation<_Rp, _Tp, _Up>;
// [concept.strictweakorder]
template<class _Rp, class _Tp, class _Up>
concept strict_weak_order = relation<_Rp, _Tp, _Up>;
#endif //_LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS)
_LIBCPP_END_NAMESPACE_STD

View File

@ -0,0 +1,59 @@
//===----------------------------------------------------------------------===//
//
// 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
// template<class F, class... Args>
// concept equivalence_relation;
#include <concepts>
static_assert(std::equivalence_relation<bool(int, int), int, int>);
static_assert(std::equivalence_relation<bool(int, int), double, double>);
static_assert(std::equivalence_relation<bool(int, double), double, double>);
static_assert(!std::equivalence_relation<bool (*)(), int, double>);
static_assert(!std::equivalence_relation<bool (*)(int), int, double>);
static_assert(!std::equivalence_relation<bool (*)(double), int, double>);
static_assert(
!std::equivalence_relation<bool(double, double*), double, double*>);
static_assert(!std::equivalence_relation<bool(int&, int&), double&, double&>);
struct S1 {};
static_assert(std::relation<bool (S1::*)(S1*), S1*, S1*>);
static_assert(std::relation<bool (S1::*)(S1&), S1&, S1&>);
struct S2 {};
struct P1 {
bool operator()(S1, S1) const;
};
static_assert(std::equivalence_relation<P1, S1, S1>);
struct P2 {
bool operator()(S1, S1) const;
bool operator()(S1, S2) const;
};
static_assert(!std::equivalence_relation<P2, S1, S2>);
struct P3 {
bool operator()(S1, S1) const;
bool operator()(S1, S2) const;
bool operator()(S2, S1) const;
};
static_assert(!std::equivalence_relation<P3, S1, S2>);
struct P4 {
bool operator()(S1, S1) const;
bool operator()(S1, S2) const;
bool operator()(S2, S1) const;
bool operator()(S2, S2) const;
};
static_assert(std::equivalence_relation<P4, S1, S2>);

View File

@ -0,0 +1,85 @@
//===----------------------------------------------------------------------===//
//
// 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
// template<class F, class... Args>
// concept equivalence_relation;
#include <concepts>
struct S1 {};
struct S2 {};
struct R {
bool operator()(S1, S1) const;
bool operator()(S1, S2) const;
bool operator()(S2, S1) const;
bool operator()(S2, S2) const;
};
// clang-format off
template<class F, class T, class U>
requires std::relation<F, T, U>
[[nodiscard]] constexpr bool check_equivalence_relation_subsumes_relation() {
return false;
}
template<class F, class T, class U>
requires std::equivalence_relation<F, T, U> && true
[[nodiscard]] constexpr bool check_equivalence_relation_subsumes_relation() {
return true;
}
// clang-format on
static_assert(check_equivalence_relation_subsumes_relation<int (*)(int, int),
int, int>());
static_assert(check_equivalence_relation_subsumes_relation<int (*)(int, double),
int, double>());
static_assert(check_equivalence_relation_subsumes_relation<R, S1, S1>());
static_assert(check_equivalence_relation_subsumes_relation<R, S1, S2>());
// clang-format off
template<class F, class T, class U>
requires std::relation<F, T, U> && true
[[nodiscard]] constexpr bool check_relation_subsumes_equivalence_relation() {
return true;
}
template<class F, class T, class U>
requires std::equivalence_relation<F, T, U>
[[nodiscard]] constexpr bool check_relation_subsumes_equivalence_relation() {
return false;
}
// clang-format on
static_assert(check_relation_subsumes_equivalence_relation<int (*)(int, int),
int, int>());
static_assert(check_relation_subsumes_equivalence_relation<int (*)(int, double),
int, double>());
static_assert(check_relation_subsumes_equivalence_relation<R, S1, S1>());
static_assert(check_relation_subsumes_equivalence_relation<R, S1, S2>());
// clang-format off
template<class F, class T, class U>
requires std::equivalence_relation<F, T, T> && std::equivalence_relation<F, U, U>
[[nodiscard]] constexpr bool check_equivalence_relation_subsumes_itself() {
return false;
}
template<class F, class T, class U>
requires std::equivalence_relation<F, T, U>
[[nodiscard]] constexpr bool check_equivalence_relation_subsumes_itself() {
return true;
}
// clang-format on
static_assert(
check_equivalence_relation_subsumes_itself<int (*)(int, int), int, int>());
static_assert(check_equivalence_relation_subsumes_itself<R, S1, S1>());

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
// template<class F, class... Args>
// concept predicate;
#include <concepts>
static_assert(std::predicate<bool()>);
static_assert(std::predicate<bool (*)()>);
static_assert(std::predicate<bool (&)()>);
static_assert(!std::predicate<void()>);
static_assert(!std::predicate<void (*)()>);
static_assert(!std::predicate<void (&)()>);
struct S {};
static_assert(!std::predicate<S(int), int>);
static_assert(!std::predicate<S(double), double>);
static_assert(std::predicate<int S::*, S*>);
static_assert(std::predicate<int (S::*)(), S*>);
static_assert(std::predicate<int (S::*)(), S&>);
static_assert(!std::predicate<void (S::*)(), S*>);
static_assert(!std::predicate<void (S::*)(), S&>);
static_assert(!std::predicate<bool(S)>);
static_assert(!std::predicate<bool(S&), S>);
static_assert(!std::predicate<bool(S&), S const&>);
static_assert(std::predicate<bool(S&), S&>);
struct Predicate {
bool operator()(int, double, char);
};
static_assert(std::predicate<Predicate, int, double, char>);
static_assert(std::predicate<Predicate&, int, double, char>);
static_assert(!std::predicate<const Predicate, int, double, char>);
static_assert(!std::predicate<const Predicate&, int, double, char>);
[[nodiscard]] constexpr bool check_lambda(auto) { return false; }
[[nodiscard]] constexpr bool check_lambda(std::predicate auto) { return true; }
static_assert(check_lambda([] { return std::true_type(); }));
static_assert(check_lambda([]() -> int* { return nullptr; }));
struct boolean {
operator bool() const noexcept;
};
static_assert(check_lambda([] { return boolean(); }));
struct explicit_bool {
explicit operator bool() const noexcept;
};
static_assert(!check_lambda([] { return explicit_bool(); }));

View File

@ -0,0 +1,31 @@
//===----------------------------------------------------------------------===//
//
// 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
// template<class F, class... Args>
// concept predicate;
#include <concepts>
[[nodiscard]] constexpr bool check_subsumption(std::regular_invocable auto) {
return false;
}
// clang-format off
template<class F>
requires std::predicate<F> && true
[[nodiscard]] constexpr bool check_subsumption(F)
{
return true;
}
// clang-format on
static_assert(!check_subsumption([] {}));
static_assert(check_subsumption([] { return true; }));

View File

@ -0,0 +1,57 @@
//===----------------------------------------------------------------------===//
//
// 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
// template<class F, class... Args>
// concept relation;
#include <concepts>
static_assert(std::relation<bool(int, int), int, int>);
static_assert(std::relation<bool(int, int), double, double>);
static_assert(std::relation<bool(int, double), double, double>);
static_assert(!std::relation<bool(), int, double>);
static_assert(!std::relation<bool(int), int, double>);
static_assert(!std::relation<bool(double), int, double>);
static_assert(!std::relation<bool(double, double*), double, double*>);
static_assert(!std::relation<bool(int&, int&), double&, double&>);
struct S1 {};
static_assert(std::relation<bool (S1::*)(S1*), S1*, S1*>);
static_assert(std::relation<bool (S1::*)(S1&), S1&, S1&>);
struct S2 {};
struct P1 {
bool operator()(S1, S1) const;
};
static_assert(std::relation<P1, S1, S1>);
struct P2 {
bool operator()(S1, S1) const;
bool operator()(S1, S2) const;
};
static_assert(!std::relation<P2, S1, S2>);
struct P3 {
bool operator()(S1, S1) const;
bool operator()(S1, S2) const;
bool operator()(S2, S1) const;
};
static_assert(!std::relation<P3, S1, S2>);
struct P4 {
bool operator()(S1, S1) const;
bool operator()(S1, S2) const;
bool operator()(S2, S1) const;
bool operator()(S2, S2) const;
};
static_assert(std::relation<P4, S1, S2>);

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
// template<class F, class... Args>
// concept relation;
#include <concepts>
struct S1 {};
struct S2 {};
struct R {
bool operator()(S1, S1) const;
bool operator()(S1, S2) const;
bool operator()(S2, S1) const;
bool operator()(S2, S2) const;
};
// clang-format off
template<class F, class T, class U>
requires std::predicate<F, T, T> && std::predicate<F, T, U> &&
std::predicate<F, U, T> && std::predicate<F, U, U>
[[nodiscard]] constexpr bool check_relation_subsumes_predicate() {
return false;
}
template<class F, class T, class U>
requires std::relation<F, T, U> && true
[[nodiscard]] constexpr bool check_relation_subsumes_predicate() {
return true;
}
// clang-format on
static_assert(
check_relation_subsumes_predicate<int (*)(int, double), int, int>());
static_assert(
check_relation_subsumes_predicate<int (*)(int, double), int, double>());
static_assert(check_relation_subsumes_predicate<R, S1, S1>());
static_assert(check_relation_subsumes_predicate<R, S1, S2>());
// clang-format off
template<class F, class T, class U>
requires std::relation<F, T, T> && std::relation<F, U, U>
[[nodiscard]] constexpr bool check_relation_subsumes_itself() {
return false;
}
template<class F, class T, class U>
requires std::relation<F, T, U>
[[nodiscard]] constexpr bool check_relation_subsumes_itself() {
return true;
}
// clang-format on
static_assert(check_relation_subsumes_itself<int (*)(int, double), int, int>());
static_assert(check_relation_subsumes_itself<R, S1, S1>());

View File

@ -0,0 +1,58 @@
//===----------------------------------------------------------------------===//
//
// 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
// template<class F, class... Args>
// concept strict_weak_order;
#include <concepts>
static_assert(std::strict_weak_order<bool(int, int), int, int>);
static_assert(std::strict_weak_order<bool(int, int), double, double>);
static_assert(std::strict_weak_order<bool(int, double), double, double>);
static_assert(!std::strict_weak_order<bool (*)(), int, double>);
static_assert(!std::strict_weak_order<bool (*)(int), int, double>);
static_assert(!std::strict_weak_order<bool (*)(double), int, double>);
static_assert(!std::strict_weak_order<bool(double, double*), double, double*>);
static_assert(!std::strict_weak_order<bool(int&, int&), double&, double&>);
struct S1 {};
static_assert(std::strict_weak_order<bool (S1::*)(S1*), S1*, S1*>);
static_assert(std::strict_weak_order<bool (S1::*)(S1&), S1&, S1&>);
struct S2 {};
struct P1 {
bool operator()(S1, S1) const;
};
static_assert(std::strict_weak_order<P1, S1, S1>);
struct P2 {
bool operator()(S1, S1) const;
bool operator()(S1, S2) const;
};
static_assert(!std::strict_weak_order<P2, S1, S2>);
struct P3 {
bool operator()(S1, S1) const;
bool operator()(S1, S2) const;
bool operator()(S2, S1) const;
};
static_assert(!std::strict_weak_order<P3, S1, S2>);
struct P4 {
bool operator()(S1, S1) const;
bool operator()(S1, S2) const;
bool operator()(S2, S1) const;
bool operator()(S2, S2) const;
};
static_assert(std::strict_weak_order<P4, S1, S2>);

View File

@ -0,0 +1,85 @@
//===----------------------------------------------------------------------===//
//
// 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
// template<class F, class... Args>
// concept strict_weak_order;
#include <concepts>
struct S1 {};
struct S2 {};
struct R {
bool operator()(S1, S1) const;
bool operator()(S1, S2) const;
bool operator()(S2, S1) const;
bool operator()(S2, S2) const;
};
// clang-format off
template<class F, class T, class U>
requires std::relation<F, T, U>
[[nodiscard]] constexpr bool check_strict_weak_order_subsumes_relation() {
return false;
}
template<class F, class T, class U>
requires std::strict_weak_order<F, T, U> && true
[[nodiscard]] constexpr bool check_strict_weak_order_subsumes_relation() {
return true;
}
// clang-format on
static_assert(
check_strict_weak_order_subsumes_relation<int (*)(int, int), int, int>());
static_assert(check_strict_weak_order_subsumes_relation<int (*)(int, double),
int, double>());
static_assert(check_strict_weak_order_subsumes_relation<R, S1, S1>());
static_assert(check_strict_weak_order_subsumes_relation<R, S1, S2>());
// clang-format off
template<class F, class T, class U>
requires std::relation<F, T, U> && true
[[nodiscard]] constexpr bool check_relation_subsumes_strict_weak_order() {
return true;
}
template<class F, class T, class U>
requires std::strict_weak_order<F, T, U>
[[nodiscard]] constexpr bool check_relation_subsumes_strict_weak_order() {
return false;
}
// clang-format on
static_assert(
check_relation_subsumes_strict_weak_order<int (*)(int, int), int, int>());
static_assert(check_relation_subsumes_strict_weak_order<int (*)(int, double),
int, double>());
static_assert(check_relation_subsumes_strict_weak_order<R, S1, S1>());
static_assert(check_relation_subsumes_strict_weak_order<R, S1, S2>());
// clang-format off
template<class F, class T, class U>
requires std::strict_weak_order<F, T, T> && std::strict_weak_order<F, U, U>
[[nodiscard]] constexpr bool check_strict_weak_order_subsumes_itself() {
return false;
}
template<class F, class T, class U>
requires std::strict_weak_order<F, T, U>
[[nodiscard]] constexpr bool check_strict_weak_order_subsumes_itself() {
return true;
}
// clang-format on
static_assert(
check_strict_weak_order_subsumes_itself<int (*)(int, int), int, int>());
static_assert(check_strict_weak_order_subsumes_itself<R, S1, S1>());