diff --git a/libc/src/__support/CPP/functional.h b/libc/src/__support/CPP/functional.h --- a/libc/src/__support/CPP/functional.h +++ b/libc/src/__support/CPP/functional.h @@ -9,19 +9,46 @@ #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 + namespace __llvm_libc { namespace cpp { -template class function; +/// A function type adapted from LLVM's function_ref type. This class does not +/// own the callable, so it is not in general safe to store a function_ref. +template class function; -template class function { - R (*func)(Args...) = nullptr; +template class function { + Ret (*callback)(intptr_t callable, Params... params) = nullptr; + intptr_t callable; -public: - constexpr function() = default; - template constexpr function(F &&f) : func(f) {} + template + LIBC_INLINE static Ret callback_fn(intptr_t callable, Params... params) { + return (*reinterpret_cast(callable))( + forward(params)...); + } - constexpr R operator()(Args... params) { return func(params...); } +public: + LIBC_INLINE function() = default; + LIBC_INLINE function(decltype(nullptr)) {} + + template + LIBC_INLINE + function(Callable &&callable, + enable_if_t, function>::value> * = + nullptr) + : callback(callback_fn>), + callable(reinterpret_cast(&callable)) {} + + LIBC_INLINE Ret operator()(Params... params) const { + return callback(callable, forward(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 --- 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 struct type_identity { using type = T; }; +template struct type_identity { + using type = T; +}; template struct enable_if; template struct enable_if : type_identity {}; @@ -49,6 +51,17 @@ template struct remove_cv : type_identity {}; template using remove_cv_t = typename remove_cv::type; +template struct remove_reference : type_identity {}; +template struct remove_reference : type_identity {}; +template struct remove_reference : type_identity {}; +template +using remove_reference_t = typename remove_reference::type; + +template struct remove_cvref { + using type = remove_cv_t>; +}; +template using remove_cvref_t = typename remove_cvref::type; + namespace details { template constexpr bool is_unqualified_any_of() { return (... || is_same_v, Args>); diff --git a/libc/src/__support/CPP/utility.h b/libc/src/__support/CPP/utility.h --- 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 @@ using make_integer_sequence = typename internal::make_integer_sequence::type; +template +LIBC_INLINE constexpr T &&forward(typename remove_reference::type &value) { + return static_cast(value); +} + +template +LIBC_INLINE constexpr T &&forward(typename remove_reference::type &&value) { + return static_cast(value); +} + +template +LIBC_INLINE constexpr typename remove_reference::type &&move(T &&value) { + return static_cast::type &&>(value); +} + } // namespace __llvm_libc::cpp #endif // LLVM_LIBC_SRC_SUPPORT_CPP_UTILITY_H