[libcxx-commits] [libcxx] 17db24a - [libcxx] adds concepts `std::invocable` and `std::regular_invocable`
Christopher Di Bella via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Feb 10 11:38:36 PST 2021
Author: Christopher Di Bella
Date: 2021-02-10T19:35:53Z
New Revision: 17db24a7a8f23eb5adb24f36b9d51bb7cc5ae564
URL: https://github.com/llvm/llvm-project/commit/17db24a7a8f23eb5adb24f36b9d51bb7cc5ae564
DIFF: https://github.com/llvm/llvm-project/commit/17db24a7a8f23eb5adb24f36b9d51bb7cc5ae564.diff
LOG: [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
Added:
libcxx/test/std/concepts/callable/functions.h
libcxx/test/std/concepts/callable/invocable.compile.pass.cpp
libcxx/test/std/concepts/callable/regularinvocable.compile.pass.cpp
Modified:
libcxx/include/concepts
libcxx/test/std/concepts/lang/derived.compile.pass.cpp
Removed:
################################################################################
diff --git a/libcxx/include/concepts b/libcxx/include/concepts
index 7c42dc87b177..478b8658f02b 100644
--- a/libcxx/include/concepts
+++ b/libcxx/include/concepts
@@ -135,7 +135,9 @@ namespace std {
*/
#include <__config>
+#include <functional>
#include <type_traits>
+#include <utility>
#include <version>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -216,6 +218,16 @@ concept copy_constructible =
constructible_from<_Tp, const _Tp&> && convertible_to<const _Tp&, _Tp> &&
constructible_from<_Tp, const _Tp> && convertible_to<const _Tp, _Tp>;
+// [concept.invocable]
+template<class _Fn, class... _Args>
+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<class _Fn, class... _Args>
+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 000000000000..bf77e44f15da
--- /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 <class T>
+ 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 000000000000..9afa9d9a7126
--- /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<class T, class U>
+// concept invocable;
+
+#include <chrono>
+#include <concepts>
+#include <memory>
+#include <random>
+#include <type_traits>
+
+#include "functions.h"
+
+template <class F, class... Args>
+requires std::invocable<F, Args...> constexpr void
+ModelsInvocable(F, Args&&...) noexcept{};
+
+template <class F, class... Args>
+requires(!std::invocable<F, Args...>) constexpr
+ void NotInvocable(F, Args&&...) noexcept {}
+
+static_assert(!std::invocable<void>);
+static_assert(!std::invocable<void*>);
+static_assert(!std::invocable<int>);
+static_assert(!std::invocable<int&>);
+static_assert(!std::invocable<int&&>);
+
+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<A>();
+ ModelsInvocable(&A::I, Up);
+ ModelsInvocable(&A::F, Up);
+ ModelsInvocable(&A::G, Up, 0);
+ NotInvocable(&A::H, Up, 0);
+ }
+ {
+ auto Sp = std::make_shared<A>();
+ 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<L2rSorted>();
+ ModelsInvocable(&L2rSorted::operator()<int>, Up, 0, 1, 2);
+ NotInvocable(&L2rSorted::operator()<int>, Up);
+ NotInvocable(&L2rSorted::operator()<int>, Up, 0);
+ NotInvocable(&L2rSorted::operator()<int>, Up, 0, 1);
+ }
+ {
+ auto Sp = std::make_shared<L2rSorted>();
+ ModelsInvocable(&L2rSorted::operator()<int>, Sp, 0, 1, 2);
+ NotInvocable(&L2rSorted::operator()<int>, Sp);
+ NotInvocable(&L2rSorted::operator()<int>, Sp, 0);
+ NotInvocable(&L2rSorted::operator()<int>, 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 000000000000..f342ca58af26
--- /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<class T, class U>
+// concept regular_invocable;
+
+#include <concepts>
+#include <memory>
+#include <random>
+#include <type_traits>
+
+#include "functions.h"
+
+template <class F, class... Args>
+requires std::invocable<F, Args...> constexpr void
+ModelsRegularInvocable(F, Args&&...) noexcept{};
+
+template <class F, class... Args>
+requires(!std::invocable<F, Args...>) constexpr
+ void NotRegularInvocable(F, Args&&...) noexcept {}
+
+static_assert(!std::invocable<void>);
+static_assert(!std::invocable<void*>);
+static_assert(!std::invocable<int>);
+static_assert(!std::invocable<int&>);
+static_assert(!std::invocable<int&&>);
+
+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<A>();
+ ModelsRegularInvocable(&A::I, Up);
+ ModelsRegularInvocable(&A::F, Up);
+ ModelsRegularInvocable(&A::G, Up, 0);
+ NotRegularInvocable(&A::H, Up, 0);
+ }
+ {
+ auto Sp = std::make_shared<A>();
+ 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<L2rSorted>();
+ ModelsRegularInvocable(&L2rSorted::operator()<int>, Up, 0, 1, 2);
+ NotRegularInvocable(&L2rSorted::operator()<int>, Up);
+ NotRegularInvocable(&L2rSorted::operator()<int>, Up, 0);
+ NotRegularInvocable(&L2rSorted::operator()<int>, Up, 0, 1);
+ }
+ {
+ auto Sp = std::make_shared<L2rSorted>();
+ ModelsRegularInvocable(&L2rSorted::operator()<int>, Sp, 0, 1, 2);
+ NotRegularInvocable(&L2rSorted::operator()<int>, Sp);
+ NotRegularInvocable(&L2rSorted::operator()<int>, Sp, 0);
+ NotRegularInvocable(&L2rSorted::operator()<int>, 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 1aca4e4df178..f8b57e46b69e 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<class Derived, class Base>
More information about the libcxx-commits
mailing list