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 + namespace __llvm_libc { namespace cpp { -template 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 class function; + +template class function { + Ret (*callback)(intptr_t callable, Params... params) = nullptr; + intptr_t callable; -template class function { - R (*func)(Args...) = nullptr; + template + LIBC_INLINE static Ret callback_fn(intptr_t callable, Params... params) { + return (*reinterpret_cast(callable))( + forward(params)...); + } public: - constexpr function() = default; - template constexpr function(F &&f) : func(f) {} + LIBC_INLINE function() = default; + LIBC_INLINE function(decltype(nullptr)) {} + LIBC_INLINE ~function() = default; + + template + LIBC_INLINE function( + Callable &&callable, + // This is not the copy-constructor. + enable_if_t, function>::value> * = + nullptr, + // Functor must be callable and return a suitable type. + enable_if_t || + is_convertible_v< + decltype(declval()(declval()...)), Ret>> + * = nullptr) + : callback(callback_fn>), + callable(reinterpret_cast(&callable)) {} + + LIBC_INLINE Ret operator()(Params... params) const { + return callback(callable, forward(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 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 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,26 @@ struct conditional : type_identity {}; template using conditional_t = typename conditional::type; +template +struct is_void : is_same::type> {}; +template inline constexpr bool is_void_v = is_void::value; +template T declval(); + +// Compile time checks on implicit conversions. +namespace details { +template using void_t = void; +template void convertible_to_helper(T); +} // namespace details + +template +inline constexpr bool is_convertible_v = false; + +template +inline constexpr bool + is_convertible_v( + declval()))>> = 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 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