[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