[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