[libc-commits] [libc] 7090c10 - [libc] Adjust the `cpp:function` type to support lambdas

Joseph Huber via libc-commits libc-commits at lists.llvm.org
Mon Apr 24 13:48:05 PDT 2023


Author: Joseph Huber
Date: 2023-04-24T15:47:54-05:00
New Revision: 7090c102731192d5abafb7e0b2b49adb4912efae

URL: https://github.com/llvm/llvm-project/commit/7090c102731192d5abafb7e0b2b49adb4912efae
DIFF: https://github.com/llvm/llvm-project/commit/7090c102731192d5abafb7e0b2b49adb4912efae.diff

LOG: [libc] Adjust the `cpp:function` type to support lambdas

The current function type does not support generic lambdas because it
relies on the lambda being implicitly convertible to a function pointer.
This patch adds support for this by copying the existing lightweight
`function_ref` type.

Reviewed By: sivachandra

Differential Revision: https://reviews.llvm.org/D148971

Added: 
    

Modified: 
    libc/src/__support/CPP/functional.h
    libc/src/__support/CPP/type_traits.h
    libc/src/__support/CPP/utility.h

Removed: 
    


################################################################################
diff  --git a/libc/src/__support/CPP/functional.h b/libc/src/__support/CPP/functional.h
index 5919306ad707e..e346011debab1 100644
--- a/libc/src/__support/CPP/functional.h
+++ b/libc/src/__support/CPP/functional.h
@@ -9,19 +9,54 @@
 #ifndef LLVM_LIBC_SRC_SUPPORT_CPP_FUNCTIONAL_H
 #define LLVM_LIBC_SRC_SUPPORT_CPP_FUNCTIONAL_H
 
+#include "src/__support/CPP/type_traits.h"
+#include "src/__support/CPP/utility.h"
+#include "src/__support/macros/attributes.h"
+
+#include <stdint.h>
+
 namespace __llvm_libc {
 namespace cpp {
 
-template <typename F> class function;
+/// A function type adapted from LLVM's function_ref.
+/// This class does not own the callable, so it is not in general safe to
+/// store a function.
+template <typename Fn> class function;
+
+template <typename Ret, typename... Params> class function<Ret(Params...)> {
+  Ret (*callback)(intptr_t callable, Params... params) = nullptr;
+  intptr_t callable;
 
-template <typename R, typename... Args> class function<R(Args...)> {
-  R (*func)(Args...) = nullptr;
+  template <typename Callable>
+  LIBC_INLINE static Ret callback_fn(intptr_t callable, Params... params) {
+    return (*reinterpret_cast<Callable *>(callable))(
+        forward<Params>(params)...);
+  }
 
 public:
-  constexpr function() = default;
-  template <typename F> constexpr function(F &&f) : func(f) {}
+  LIBC_INLINE function() = default;
+  LIBC_INLINE function(decltype(nullptr)) {}
+  LIBC_INLINE ~function() = default;
+
+  template <typename Callable>
+  LIBC_INLINE function(
+      Callable &&callable,
+      // This is not the copy-constructor.
+      enable_if_t<!is_same<remove_cvref_t<Callable>, function>::value> * =
+          nullptr,
+      // Functor must be callable and return a suitable type.
+      enable_if_t<is_void_v<Ret> ||
+                  is_convertible_v<
+                      decltype(declval<Callable>()(declval<Params>()...)), Ret>>
+          * = nullptr)
+      : callback(callback_fn<remove_reference_t<Callable>>),
+        callable(reinterpret_cast<intptr_t>(&callable)) {}
+
+  LIBC_INLINE Ret operator()(Params... params) const {
+    return callback(callable, forward<Params>(params)...);
+  }
 
-  constexpr R operator()(Args... params) { return func(params...); }
+  LIBC_INLINE explicit operator bool() const { return callback; }
 };
 
 } // namespace cpp

diff  --git a/libc/src/__support/CPP/type_traits.h b/libc/src/__support/CPP/type_traits.h
index e5614021ca17a..f888bdcb8e112 100644
--- a/libc/src/__support/CPP/type_traits.h
+++ b/libc/src/__support/CPP/type_traits.h
@@ -12,7 +12,9 @@
 namespace __llvm_libc {
 namespace cpp {
 
-template <typename T> struct type_identity { using type = T; };
+template <typename T> struct type_identity {
+  using type = T;
+};
 
 template <bool B, typename T> struct enable_if;
 template <typename T> struct enable_if<true, T> : type_identity<T> {};
@@ -49,6 +51,19 @@ template <typename T> struct remove_cv<volatile T> : type_identity<T> {};
 template <typename T> struct remove_cv<const volatile T> : type_identity<T> {};
 template <typename T> using remove_cv_t = typename remove_cv<T>::type;
 
+template <typename T> struct remove_reference : type_identity<T> {};
+template <typename T> struct remove_reference<T &> : type_identity<T> {};
+template <typename T> struct remove_reference<T &&> : type_identity<T> {};
+template <typename T>
+using remove_reference_t = typename remove_reference<T>::type;
+
+template <typename T> struct add_rvalue_reference : type_identity<T &&> {};
+
+template <typename T> struct remove_cvref {
+  using type = remove_cv_t<remove_reference_t<T>>;
+};
+template <typename T> using remove_cvref_t = typename remove_cvref<T>::type;
+
 namespace details {
 template <typename T, typename... Args> constexpr bool is_unqualified_any_of() {
   return (... || is_same_v<remove_cv_t<T>, Args>);
@@ -148,6 +163,26 @@ struct conditional<false, T, F> : type_identity<F> {};
 template <bool B, typename T, typename F>
 using conditional_t = typename conditional<B, T, F>::type;
 
+template <typename T>
+struct is_void : is_same<void, typename remove_cv<T>::type> {};
+template <typename T> inline constexpr bool is_void_v = is_void<T>::value;
+template <class T> T declval();
+
+// Compile time checks on implicit conversions.
+namespace details {
+template <typename...> using void_t = void;
+template <typename T> void convertible_to_helper(T);
+} // namespace details
+
+template <typename F, typename T, typename = void>
+inline constexpr bool is_convertible_v = false;
+
+template <typename F, typename T>
+inline constexpr bool
+    is_convertible_v<F, T,
+                     details::void_t<decltype(details::convertible_to_helper<T>(
+                         declval<F>()))>> = true;
+
 } // namespace cpp
 } // namespace __llvm_libc
 

diff  --git a/libc/src/__support/CPP/utility.h b/libc/src/__support/CPP/utility.h
index 52044eb0b9b72..40455d5e61f87 100644
--- a/libc/src/__support/CPP/utility.h
+++ b/libc/src/__support/CPP/utility.h
@@ -10,6 +10,7 @@
 #define LLVM_LIBC_SRC_SUPPORT_CPP_UTILITY_H
 
 #include "src/__support/CPP/type_traits.h"
+#include "src/__support/macros/attributes.h"
 
 namespace __llvm_libc::cpp {
 
@@ -35,6 +36,21 @@ template <typename T, int N>
 using make_integer_sequence =
     typename internal::make_integer_sequence<T, N - 1>::type;
 
+template <typename T>
+LIBC_INLINE constexpr T &&forward(typename remove_reference<T>::type &value) {
+  return static_cast<T &&>(value);
+}
+
+template <typename T>
+LIBC_INLINE constexpr T &&forward(typename remove_reference<T>::type &&value) {
+  return static_cast<T &&>(value);
+}
+
+template <typename T>
+LIBC_INLINE constexpr typename remove_reference<T>::type &&move(T &&value) {
+  return static_cast<typename remove_reference<T>::type &&>(value);
+}
+
 } // namespace __llvm_libc::cpp
 
 #endif // LLVM_LIBC_SRC_SUPPORT_CPP_UTILITY_H


        


More information about the libc-commits mailing list