diff --git a/libcxx/include/concepts b/libcxx/include/concepts --- a/libcxx/include/concepts +++ b/libcxx/include/concepts @@ -135,7 +135,9 @@ */ #include <__config> +#include #include +#include #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -176,6 +178,15 @@ concept default_initializable = constructible_from<_Tp> && requires { _Tp{}; } && __default_initializable<_Tp>; +// [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 diff --git a/libcxx/test/std/concepts/callable/functions.h b/libcxx/test/std/concepts/callable/functions.h new file mode 100644 --- /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 --- /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 --- /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; +}