[llvm] Add invoke (PR #65753)

Guillaume Chatelet via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 8 06:18:28 PDT 2023


https://github.com/gchatelet created https://github.com/llvm/llvm-project/pull/65753:

- [libc] Add is_object
- [libc] add invoke_result type traits
- [libc] add invoke type traits


>From 3ab691253d62985f86e20c8780ea29b5bbec3c20 Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Fri, 8 Sep 2023 11:26:07 +0000
Subject: [PATCH 1/3] [libc] Add is_object

---
 libc/src/__support/CPP/type_traits.h          |  1 +
 .../src/__support/CPP/type_traits/is_object.h | 30 +++++++++++++++++++
 .../llvm-project-overlay/libc/BUILD.bazel     |  1 +
 3 files changed, 32 insertions(+)
 create mode 100644 libc/src/__support/CPP/type_traits/is_object.h

diff --git a/libc/src/__support/CPP/type_traits.h b/libc/src/__support/CPP/type_traits.h
index c0d3591f8d37eb..9deb08b221593e 100644
--- a/libc/src/__support/CPP/type_traits.h
+++ b/libc/src/__support/CPP/type_traits.h
@@ -32,6 +32,7 @@
 #include "src/__support/CPP/type_traits/is_lvalue_reference.h"
 #include "src/__support/CPP/type_traits/is_member_pointer.h"
 #include "src/__support/CPP/type_traits/is_null_pointer.h"
+#include "src/__support/CPP/type_traits/is_object.h"
 #include "src/__support/CPP/type_traits/is_pointer.h"
 #include "src/__support/CPP/type_traits/is_reference.h"
 #include "src/__support/CPP/type_traits/is_rvalue_reference.h"
diff --git a/libc/src/__support/CPP/type_traits/is_object.h b/libc/src/__support/CPP/type_traits/is_object.h
new file mode 100644
index 00000000000000..9928fb7b85e3d8
--- /dev/null
+++ b/libc/src/__support/CPP/type_traits/is_object.h
@@ -0,0 +1,30 @@
+//===-- is_object type_traits -----------------------------------*- C++ -*-===//
+//
+// 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 LLVM_LIBC_SRC_SUPPORT_CPP_TYPE_TRAITS_IS_OBJECT_H
+#define LLVM_LIBC_SRC_SUPPORT_CPP_TYPE_TRAITS_IS_OBJECT_H
+
+#include "src/__support/CPP/type_traits/bool_constant.h"
+#include "src/__support/CPP/type_traits/is_array.h"
+#include "src/__support/CPP/type_traits/is_class.h"
+#include "src/__support/CPP/type_traits/is_scalar.h"
+#include "src/__support/CPP/type_traits/is_union.h"
+#include "src/__support/macros/attributes.h"
+
+namespace __llvm_libc::cpp {
+
+// is_object
+template <class T>
+struct is_object
+    : cpp::bool_constant<cpp::is_scalar_v<T> || cpp::is_array_v<T> ||
+                         cpp::is_union_v<T> || cpp::is_class_v<T>> {};
+template <class T>
+LIBC_INLINE_VAR constexpr bool is_object_v = is_object<T>::value;
+
+} // namespace __llvm_libc::cpp
+
+#endif // LLVM_LIBC_SRC_SUPPORT_CPP_TYPE_TRAITS_IS_OBJECT_H
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index 3680ee730e72d5..17e4913749d51c 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -309,6 +309,7 @@ libc_support_library(
         "src/__support/CPP/type_traits/is_lvalue_reference.h",
         "src/__support/CPP/type_traits/is_member_pointer.h",
         "src/__support/CPP/type_traits/is_null_pointer.h",
+        "src/__support/CPP/type_traits/is_object.h",
         "src/__support/CPP/type_traits/is_pointer.h",
         "src/__support/CPP/type_traits/is_reference.h",
         "src/__support/CPP/type_traits/is_rvalue_reference.h",

>From 07281d72cd500c2cfb55a4c008357ef914f539d5 Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Fri, 8 Sep 2023 13:10:05 +0000
Subject: [PATCH 2/3] [libc] add invoke_result type traits

---
 libc/src/__support/CPP/type_traits.h          |  1 +
 .../__support/CPP/type_traits/invoke_result.h | 90 +++++++++++++++++++
 .../llvm-project-overlay/libc/BUILD.bazel     |  2 +
 3 files changed, 93 insertions(+)
 create mode 100644 libc/src/__support/CPP/type_traits/invoke_result.h

diff --git a/libc/src/__support/CPP/type_traits.h b/libc/src/__support/CPP/type_traits.h
index 9deb08b221593e..cec5de1198c96f 100644
--- a/libc/src/__support/CPP/type_traits.h
+++ b/libc/src/__support/CPP/type_traits.h
@@ -18,6 +18,7 @@
 #include "src/__support/CPP/type_traits/enable_if.h"
 #include "src/__support/CPP/type_traits/false_type.h"
 #include "src/__support/CPP/type_traits/integral_constant.h"
+#include "src/__support/CPP/type_traits/invoke_result.h"
 #include "src/__support/CPP/type_traits/is_arithmetic.h"
 #include "src/__support/CPP/type_traits/is_array.h"
 #include "src/__support/CPP/type_traits/is_base_of.h"
diff --git a/libc/src/__support/CPP/type_traits/invoke_result.h b/libc/src/__support/CPP/type_traits/invoke_result.h
new file mode 100644
index 00000000000000..47b0ffb88e5739
--- /dev/null
+++ b/libc/src/__support/CPP/type_traits/invoke_result.h
@@ -0,0 +1,90 @@
+//===-- invoke_result type_traits -------------------------------*- C++ -*-===//
+//
+// 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 LLVM_LIBC_SRC_SUPPORT_CPP_TYPE_TRAITS_INVOKE_RESULT_H
+#define LLVM_LIBC_SRC_SUPPORT_CPP_TYPE_TRAITS_INVOKE_RESULT_H
+
+#include "src/__support/CPP/type_traits/decay.h"
+#include "src/__support/CPP/type_traits/enable_if.h"
+#include "src/__support/CPP/type_traits/false_type.h"
+#include "src/__support/CPP/type_traits/is_base_of.h"
+#include "src/__support/CPP/type_traits/is_function.h"
+#include "src/__support/CPP/type_traits/true_type.h"
+#include "src/__support/CPP/utility/declval.h"
+#include "src/__support/CPP/utility/forward.h"
+
+// BEWARE : this implementation is not fully conformant as it doesn't take
+// `cpp::reference_wrapper` into account.
+
+namespace __llvm_libc::cpp {
+
+// invoke_result
+
+namespace detail {
+template <class T> struct is_reference_wrapper : cpp::false_type {};
+
+// Disable specialization on `cpp::reference_wrapper` as it is not yet
+// implemented.
+
+// template <class U> struct
+// is_reference_wrapper<cpp::reference_wrapper<U>> : cpp::true_type {};
+
+template <class T> struct invoke_impl {
+  template <class F, class... Args>
+  static auto call(F &&f, Args &&...args)
+      -> decltype(cpp::forward<F>(f)(cpp::forward<Args>(args)...));
+};
+
+template <class B, class MT> struct invoke_impl<MT B::*> {
+  template <class T, class Td = cpp::decay_t<T>,
+            class = cpp::enable_if_t<cpp::is_base_of_v<B, Td>>>
+  static auto get(T &&t) -> T &&;
+
+  template <class T, class Td = cpp::decay_t<T>,
+            class = cpp::enable_if_t<is_reference_wrapper<Td>::value>>
+  static auto get(T &&t) -> decltype(t.get());
+
+  template <class T, class Td = cpp::decay_t<T>,
+            class = cpp::enable_if_t<!cpp::is_base_of_v<B, Td>>,
+            class = cpp::enable_if_t<!is_reference_wrapper<Td>::value>>
+  static auto get(T &&t) -> decltype(*cpp::forward<T>(t));
+
+  template <class T, class... Args, class MT1,
+            class = cpp::enable_if_t<cpp::is_function_v<MT1>>>
+  static auto call(MT1 B::*pmf, T &&t, Args &&...args)
+      -> decltype((invoke_impl::get(cpp::forward<T>(t)).*
+                   pmf)(cpp::forward<Args>(args)...));
+
+  template <class T>
+  static auto call(MT B::*pmd, T &&t)
+      -> decltype(invoke_impl::get(cpp::forward<T>(t)).*pmd);
+};
+
+template <class F, class... Args, class Fd = typename cpp::decay_t<F>>
+auto INVOKE(F &&f, Args &&...args)
+    -> decltype(invoke_impl<Fd>::call(cpp::forward<F>(f),
+                                      cpp::forward<Args>(args)...));
+
+template <typename AlwaysVoid, typename, typename...> struct invoke_result {};
+template <typename F, typename... Args>
+struct invoke_result<decltype(void(detail::INVOKE(cpp::declval<F>(),
+                                                  cpp::declval<Args>()...))),
+                     F, Args...> {
+  using type =
+      decltype(detail::INVOKE(cpp::declval<F>(), cpp::declval<Args>()...));
+};
+} // namespace detail
+
+template <class F, class... ArgTypes>
+struct invoke_result : detail::invoke_result<void, F, ArgTypes...> {};
+
+template <class F, class... ArgTypes>
+using invoke_result_t = typename invoke_result<F, ArgTypes...>::type;
+
+} // namespace __llvm_libc::cpp
+
+#endif // LLVM_LIBC_SRC_SUPPORT_CPP_TYPE_TRAITS_INVOKE_RESULT_H
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index 17e4913749d51c..da9bdc64fb7815 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -295,6 +295,7 @@ libc_support_library(
         "src/__support/CPP/type_traits/enable_if.h",
         "src/__support/CPP/type_traits/false_type.h",
         "src/__support/CPP/type_traits/integral_constant.h",
+        "src/__support/CPP/type_traits/invoke_result.h",
         "src/__support/CPP/type_traits/is_arithmetic.h",
         "src/__support/CPP/type_traits/is_array.h",
         "src/__support/CPP/type_traits/is_base_of.h",
@@ -333,6 +334,7 @@ libc_support_library(
         "src/__support/CPP/type_traits/type_identity.h",
         "src/__support/CPP/type_traits/void_t.h",
         "src/__support/CPP/utility/declval.h",
+        "src/__support/CPP/utility/forward.h",
     ],
     deps = [
         ":__support_macros_attributes",

>From 2b4edbb4fd79b9b08365e1bf47a4657bb970bae3 Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Fri, 8 Sep 2023 13:17:37 +0000
Subject: [PATCH 3/3] [libc] add invoke type traits

---
 libc/src/__support/CPP/type_traits.h          |  1 +
 libc/src/__support/CPP/type_traits/invoke.h   | 64 +++++++++++++++++++
 .../llvm-project-overlay/libc/BUILD.bazel     |  1 +
 3 files changed, 66 insertions(+)
 create mode 100644 libc/src/__support/CPP/type_traits/invoke.h

diff --git a/libc/src/__support/CPP/type_traits.h b/libc/src/__support/CPP/type_traits.h
index cec5de1198c96f..3de2ca58903184 100644
--- a/libc/src/__support/CPP/type_traits.h
+++ b/libc/src/__support/CPP/type_traits.h
@@ -18,6 +18,7 @@
 #include "src/__support/CPP/type_traits/enable_if.h"
 #include "src/__support/CPP/type_traits/false_type.h"
 #include "src/__support/CPP/type_traits/integral_constant.h"
+#include "src/__support/CPP/type_traits/invoke.h"
 #include "src/__support/CPP/type_traits/invoke_result.h"
 #include "src/__support/CPP/type_traits/is_arithmetic.h"
 #include "src/__support/CPP/type_traits/is_array.h"
diff --git a/libc/src/__support/CPP/type_traits/invoke.h b/libc/src/__support/CPP/type_traits/invoke.h
new file mode 100644
index 00000000000000..b31c93de976076
--- /dev/null
+++ b/libc/src/__support/CPP/type_traits/invoke.h
@@ -0,0 +1,64 @@
+//===-- invoke type_traits --------------------------------------*- C++ -*-===//
+//
+// 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 LLVM_LIBC_SRC_SUPPORT_CPP_TYPE_TRAITS_INVOKE_H
+#define LLVM_LIBC_SRC_SUPPORT_CPP_TYPE_TRAITS_INVOKE_H
+
+#include "src/__support/CPP/type_traits/decay.h"
+#include "src/__support/CPP/type_traits/invoke_result.h"
+#include "src/__support/CPP/type_traits/is_base_of.h"
+#include "src/__support/CPP/type_traits/is_function.h"
+#include "src/__support/CPP/type_traits/is_member_pointer.h"
+#include "src/__support/CPP/type_traits/is_object.h"
+#include "src/__support/CPP/utility/forward.h"
+
+// BEWARE : this implementation is not fully conformant as it doesn't take
+// `cpp::reference_wrapper` into account. It also bypasses noexcept detection.
+
+namespace __llvm_libc::cpp {
+
+// invoke
+namespace detail {
+template <class> constexpr bool is_reference_wrapper_v = false;
+
+// Disable specialization on `cpp::reference_wrapper` as it is not yet
+// implemented.
+
+// template <class U>
+// constexpr bool is_reference_wrapper_v<cpp::reference_wrapper<U>> = true;
+
+template <class C, class Pointed, class T1, class... Args>
+constexpr decltype(auto) invoke_memptr(Pointed C::*f, T1 &&t1, Args &&...args) {
+  if constexpr (cpp::is_function_v<Pointed>) {
+    if constexpr (cpp::is_base_of_v<C, cpp::decay_t<T1>>)
+      return (cpp::forward<T1>(t1).*f)(cpp::forward<Args>(args)...);
+    else if constexpr (is_reference_wrapper_v<cpp::decay_t<T1>>)
+      return (t1.get().*f)(cpp::forward<Args>(args)...);
+    else
+      return ((*cpp::forward<T1>(t1)).*f)(cpp::forward<Args>(args)...);
+  } else {
+    static_assert(cpp::is_object_v<Pointed> && sizeof...(args) == 0);
+    if constexpr (cpp::is_base_of_v<C, cpp::decay_t<T1>>)
+      return cpp::forward<T1>(t1).*f;
+    else if constexpr (is_reference_wrapper_v<cpp::decay_t<T1>>)
+      return t1.get().*f;
+    else
+      return (*cpp::forward<T1>(t1)).*f;
+  }
+}
+} // namespace detail
+
+template <class F, class... Args>
+constexpr cpp::invoke_result_t<F, Args...> invoke(F &&f, Args &&...args) {
+  if constexpr (cpp::is_member_pointer_v<cpp::decay_t<F>>)
+    return detail::invoke_memptr(f, cpp::forward<Args>(args)...);
+  else
+    return cpp::forward<F>(f)(cpp::forward<Args>(args)...);
+}
+} // namespace __llvm_libc::cpp
+
+#endif // LLVM_LIBC_SRC_SUPPORT_CPP_TYPE_TRAITS_INVOKE_H
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index da9bdc64fb7815..06cabc015decf3 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -295,6 +295,7 @@ libc_support_library(
         "src/__support/CPP/type_traits/enable_if.h",
         "src/__support/CPP/type_traits/false_type.h",
         "src/__support/CPP/type_traits/integral_constant.h",
+        "src/__support/CPP/type_traits/invoke.h",
         "src/__support/CPP/type_traits/invoke_result.h",
         "src/__support/CPP/type_traits/is_arithmetic.h",
         "src/__support/CPP/type_traits/is_array.h",



More information about the llvm-commits mailing list