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,51 @@ #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)) {} + LIBC_INLINE ~function() = default; + + template + LIBC_INLINE function( + Callable &&callable, + enable_if_t, function>::value> * = + nullptr, + cpp::enable_if_t::value || + cpp::is_convertible()( + cpp::declval()...)), + Ret>::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,19 @@ 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 add_rvalue_reference : type_identity {}; + +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>); @@ -148,6 +163,31 @@ template using conditional_t = typename conditional::type; +template typename add_rvalue_reference::type declval() {} + +template +struct is_void : cpp::is_same::type> {}; + +// Compile time checks on implicit conversions. +namespace details { +// Return the true type if T can be returned, otherwise return false type. +template +decltype(void(static_cast(nullptr)), true_type{}) returnable(int); +template false_type returnable(...); +// Return the true type if T can be converted to F, otherwise return false type. +template +decltype(void(declval()(declval())), true_type{}) +implicitly_convertible(int); +template false_type implicitly_convertible(...); +} // namespace details + +template +struct is_convertible + : integral_constant(0))::value && + decltype(details::implicitly_convertible( + 0))::value) || + (is_void::value && is_void::value)> {}; + } // namespace cpp } // namespace __llvm_libc 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