From 17db24a7a8f23eb5adb24f36b9d51bb7cc5ae564 Mon Sep 17 00:00:00 2001 From: Christopher Di Bella Date: Mon, 8 Feb 2021 05:08:25 +0000 Subject: [PATCH] [libcxx] adds concepts `std::invocable` and `std::regular_invocable` 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/D96235 --- libcxx/include/concepts | 12 +++ libcxx/test/std/concepts/callable/functions.h | 40 +++++++ .../concepts/callable/invocable.compile.pass.cpp | 117 +++++++++++++++++++++ .../callable/regularinvocable.compile.pass.cpp | 116 ++++++++++++++++++++ .../std/concepts/lang/derived.compile.pass.cpp | 2 +- 5 files changed, 286 insertions(+), 1 deletion(-) create mode 100644 libcxx/test/std/concepts/callable/functions.h create mode 100644 libcxx/test/std/concepts/callable/invocable.compile.pass.cpp create mode 100644 libcxx/test/std/concepts/callable/regularinvocable.compile.pass.cpp diff --git a/libcxx/include/concepts b/libcxx/include/concepts index 7c42dc8..478b865 100644 --- a/libcxx/include/concepts +++ b/libcxx/include/concepts @@ -135,7 +135,9 @@ namespace std { */ #include <__config> +#include #include +#include #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -216,6 +218,16 @@ concept copy_constructible = constructible_from<_Tp, const _Tp&> && convertible_to && constructible_from<_Tp, const _Tp> && convertible_to; +// [concept.invocable] +template +concept invocable = requires(_Fn&& __fn, _Args&&... __args) { + _VSTD::invoke(_VSTD::forward<_Fn>(__fn), _VSTD::forward<_Args>(__args)...); // not required to be equality preserving +}; + +// [concept.regular.invocable] +template +concept regular_invocable = invocable<_Fn, _Args...>; + #endif //_LIBCPP_STD_VER > 17 && defined(__cpp_concepts) && __cpp_concepts >= 201811L _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/test/std/concepts/callable/functions.h b/libcxx/test/std/concepts/callable/functions.h new file mode 100644 index 0000000..bf77e44 --- /dev/null +++ b/libcxx/test/std/concepts/callable/functions.h @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +#ifndef CALLABLE_FUNCTIONS_H +#define CALLABLE_FUNCTIONS_H + +namespace RegularInvocable { +struct A { + int I = 13; + constexpr int F() const noexcept { return 42; } + constexpr int G(int X) { return 2 * X + 1; } + constexpr int H(int J) && { return I * J; } +}; + +constexpr int F() noexcept { return 13; } +constexpr int G(int I) { return 2 * I + 1; } +} // namespace RegularInvocable + +namespace Predicate { +struct L2rSorted { + template + constexpr bool operator()(T const& A, T const& B, T const& C) const noexcept { + return A <= B && B <= C; + } +}; + +struct NotAPredicate { + void operator()() const noexcept {} +}; +} // namespace Predicate + +namespace Relation { +int Greater(int X, int Y) noexcept { return X > Y; } +} // namespace Relation + +#endif // CALLABLE_FUNCTIONS_H diff --git a/libcxx/test/std/concepts/callable/invocable.compile.pass.cpp b/libcxx/test/std/concepts/callable/invocable.compile.pass.cpp new file mode 100644 index 0000000..9afa9d9 --- /dev/null +++ b/libcxx/test/std/concepts/callable/invocable.compile.pass.cpp @@ -0,0 +1,117 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// concept invocable; + +#include +#include +#include +#include +#include + +#include "functions.h" + +template +requires std::invocable constexpr void +ModelsInvocable(F, Args&&...) noexcept{}; + +template +requires(!std::invocable) constexpr + void NotInvocable(F, Args&&...) noexcept {} + +static_assert(!std::invocable); +static_assert(!std::invocable); +static_assert(!std::invocable); +static_assert(!std::invocable); +static_assert(!std::invocable); + +int main(int, char**) { + { + using namespace RegularInvocable; + + ModelsInvocable(F); + NotInvocable(F, 0); + + ModelsInvocable(G, 2); + NotInvocable(G); + NotInvocable(G, 3, 0); + + NotInvocable(&A::I); + NotInvocable(&A::F); + + { + auto X = A{}; + ModelsInvocable(&A::I, X); + ModelsInvocable(&A::F, X); + ModelsInvocable(&A::G, X, 0); + NotInvocable(&A::G, X); + NotInvocable(&A::G, 0); + NotInvocable(&A::H); + + auto const& Y = X; + ModelsInvocable(&A::I, Y); + ModelsInvocable(&A::F, Y); + NotInvocable(&A::G, Y, 0); + NotInvocable(&A::H, Y, 0); + } + + ModelsInvocable(&A::I, A{}); + ModelsInvocable(&A::F, A{}); + ModelsInvocable(&A::G, A{}, 0); + ModelsInvocable(&A::H, A{}, 0); + + { + auto Up = std::make_unique(); + ModelsInvocable(&A::I, Up); + ModelsInvocable(&A::F, Up); + ModelsInvocable(&A::G, Up, 0); + NotInvocable(&A::H, Up, 0); + } + { + auto Sp = std::make_shared(); + ModelsInvocable(&A::I, Sp); + ModelsInvocable(&A::F, Sp); + ModelsInvocable(&A::G, Sp, 0); + NotInvocable(&A::H, Sp, 0); + } + } + { + using namespace Predicate; + { + ModelsInvocable(L2rSorted{}, 0, 1, 2); + NotInvocable(L2rSorted{}); + NotInvocable(L2rSorted{}, 0); + NotInvocable(L2rSorted{}, 0, 1); + } + { + auto Up = std::make_unique(); + ModelsInvocable(&L2rSorted::operator(), Up, 0, 1, 2); + NotInvocable(&L2rSorted::operator(), Up); + NotInvocable(&L2rSorted::operator(), Up, 0); + NotInvocable(&L2rSorted::operator(), Up, 0, 1); + } + { + auto Sp = std::make_shared(); + ModelsInvocable(&L2rSorted::operator(), Sp, 0, 1, 2); + NotInvocable(&L2rSorted::operator(), Sp); + NotInvocable(&L2rSorted::operator(), Sp, 0); + NotInvocable(&L2rSorted::operator(), Sp, 0, 1); + } + } + { + auto G = std::mt19937_64( + std::chrono::high_resolution_clock().now().time_since_epoch().count()); + auto D = std::uniform_int_distribution<>(); + ModelsInvocable(D, G); + } + return 0; +} diff --git a/libcxx/test/std/concepts/callable/regularinvocable.compile.pass.cpp b/libcxx/test/std/concepts/callable/regularinvocable.compile.pass.cpp new file mode 100644 index 0000000..f342ca5 --- /dev/null +++ b/libcxx/test/std/concepts/callable/regularinvocable.compile.pass.cpp @@ -0,0 +1,116 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// concept regular_invocable; + +#include +#include +#include +#include + +#include "functions.h" + +template +requires std::invocable constexpr void +ModelsRegularInvocable(F, Args&&...) noexcept{}; + +template +requires(!std::invocable) constexpr + void NotRegularInvocable(F, Args&&...) noexcept {} + +static_assert(!std::invocable); +static_assert(!std::invocable); +static_assert(!std::invocable); +static_assert(!std::invocable); +static_assert(!std::invocable); + +int main(int, char**) { + { + using namespace RegularInvocable; + + ModelsRegularInvocable(F); + NotRegularInvocable(F, 0); + + ModelsRegularInvocable(G, 2); + NotRegularInvocable(G); + NotRegularInvocable(G, 3, 0); + + NotRegularInvocable(&A::I); + NotRegularInvocable(&A::F); + + { + auto X = A{}; + ModelsRegularInvocable(&A::I, X); + ModelsRegularInvocable(&A::F, X); + ModelsRegularInvocable(&A::G, X, 0); + NotRegularInvocable(&A::G, X); + NotRegularInvocable(&A::G, 0); + NotRegularInvocable(&A::H); + + auto const& Y = X; + ModelsRegularInvocable(&A::I, Y); + ModelsRegularInvocable(&A::F, Y); + NotRegularInvocable(&A::G, Y, 0); + NotRegularInvocable(&A::H, Y, 0); + } + + ModelsRegularInvocable(&A::I, A{}); + ModelsRegularInvocable(&A::F, A{}); + ModelsRegularInvocable(&A::G, A{}, 0); + ModelsRegularInvocable(&A::H, A{}, 0); + + { + auto Up = std::make_unique(); + ModelsRegularInvocable(&A::I, Up); + ModelsRegularInvocable(&A::F, Up); + ModelsRegularInvocable(&A::G, Up, 0); + NotRegularInvocable(&A::H, Up, 0); + } + { + auto Sp = std::make_shared(); + ModelsRegularInvocable(&A::I, Sp); + ModelsRegularInvocable(&A::F, Sp); + ModelsRegularInvocable(&A::G, Sp, 0); + NotRegularInvocable(&A::H, Sp, 0); + } + } + { + using namespace Predicate; + { + ModelsRegularInvocable(L2rSorted{}, 0, 1, 2); + NotRegularInvocable(L2rSorted{}); + NotRegularInvocable(L2rSorted{}, 0); + NotRegularInvocable(L2rSorted{}, 0, 1); + } + { + auto Up = std::make_unique(); + ModelsRegularInvocable(&L2rSorted::operator(), Up, 0, 1, 2); + NotRegularInvocable(&L2rSorted::operator(), Up); + NotRegularInvocable(&L2rSorted::operator(), Up, 0); + NotRegularInvocable(&L2rSorted::operator(), Up, 0, 1); + } + { + auto Sp = std::make_shared(); + ModelsRegularInvocable(&L2rSorted::operator(), Sp, 0, 1, 2); + NotRegularInvocable(&L2rSorted::operator(), Sp); + NotRegularInvocable(&L2rSorted::operator(), Sp, 0); + NotRegularInvocable(&L2rSorted::operator(), Sp, 0, 1); + } + } + // { + // RNG doesn't model regular_invocable, left here for documentation + // auto G = std::mt19937_64(std::random_device()()); + // auto D = std::uniform_int_distribution<>(); + // models_invocable(D, G); + // } + return 0; +} diff --git a/libcxx/test/std/concepts/lang/derived.compile.pass.cpp b/libcxx/test/std/concepts/lang/derived.compile.pass.cpp index 1aca4e4..f8b57e4 100644 --- a/libcxx/test/std/concepts/lang/derived.compile.pass.cpp +++ b/libcxx/test/std/concepts/lang/derived.compile.pass.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 +// UNSUPPORTED: c++03, c++11, c++14, c++17 // UNSUPPORTED: libcpp-no-concepts // template -- 2.7.4