#include <folly/CppAttributes.h>
#include <folly/Portability.h>
#include <folly/Traits.h>
+#include <folly/functional/Invoke.h>
namespace folly {
Function<ReturnType(Args...) const> constCastFunction(
Function<ReturnType(Args...)>&&) noexcept;
+#if FOLLY_HAVE_NOEXCEPT_FUNCTION_TYPE
+template <typename ReturnType, typename... Args>
+Function<ReturnType(Args...) const noexcept> constCastFunction(
+ Function<ReturnType(Args...) noexcept>&&) noexcept;
+#endif
+
namespace detail {
namespace function {
};
};
+#if FOLLY_HAVE_NOEXCEPT_FUNCTION_TYPE
+template <typename ReturnType, typename... Args>
+struct FunctionTraits<ReturnType(Args...) noexcept> {
+ using Call = ReturnType (*)(Data&, Args&&...) noexcept;
+ using IsConst = std::false_type;
+ using ConstSignature = ReturnType(Args...) const noexcept;
+ using NonConstSignature = ReturnType(Args...) noexcept;
+ using OtherSignature = ConstSignature;
+
+ template <typename F, typename G = typename std::decay<F>::type>
+ using ResultOf = decltype(
+ static_cast<ReturnType>(std::declval<G&>()(std::declval<Args>()...)));
+
+ template <typename Fun>
+ static ReturnType callSmall(Data& p, Args&&... args) noexcept {
+ return static_cast<ReturnType>((*static_cast<Fun*>(
+ static_cast<void*>(&p.tiny)))(static_cast<Args&&>(args)...));
+ }
+
+ template <typename Fun>
+ static ReturnType callBig(Data& p, Args&&... args) noexcept {
+ return static_cast<ReturnType>(
+ (*static_cast<Fun*>(p.big))(static_cast<Args&&>(args)...));
+ }
+
+ static ReturnType uninitCall(Data&, Args&&...) noexcept {
+ throw std::bad_function_call();
+ }
+
+ ReturnType operator()(Args... args) noexcept {
+ auto& fn = *static_cast<Function<NonConstSignature>*>(this);
+ return fn.call_(fn.data_, static_cast<Args&&>(args)...);
+ }
+
+ class SharedProxy {
+ std::shared_ptr<Function<NonConstSignature>> sp_;
+
+ public:
+ explicit SharedProxy(Function<NonConstSignature>&& func)
+ : sp_(std::make_shared<Function<NonConstSignature>>(std::move(func))) {}
+ ReturnType operator()(Args&&... args) const {
+ return (*sp_)(static_cast<Args&&>(args)...);
+ }
+ };
+};
+
+template <typename ReturnType, typename... Args>
+struct FunctionTraits<ReturnType(Args...) const noexcept> {
+ using Call = ReturnType (*)(Data&, Args&&...) noexcept;
+ using IsConst = std::true_type;
+ using ConstSignature = ReturnType(Args...) const noexcept;
+ using NonConstSignature = ReturnType(Args...) noexcept;
+ using OtherSignature = NonConstSignature;
+
+ template <typename F, typename G = typename std::decay<F>::type>
+ using ResultOf = decltype(static_cast<ReturnType>(
+ std::declval<const G&>()(std::declval<Args>()...)));
+
+ template <typename Fun>
+ static ReturnType callSmall(Data& p, Args&&... args) noexcept {
+ return static_cast<ReturnType>((*static_cast<const Fun*>(
+ static_cast<void*>(&p.tiny)))(static_cast<Args&&>(args)...));
+ }
+
+ template <typename Fun>
+ static ReturnType callBig(Data& p, Args&&... args) noexcept {
+ return static_cast<ReturnType>(
+ (*static_cast<const Fun*>(p.big))(static_cast<Args&&>(args)...));
+ }
+
+ static ReturnType uninitCall(Data&, Args&&...) noexcept {
+ throw std::bad_function_call();
+ }
+
+ ReturnType operator()(Args... args) const noexcept {
+ auto& fn = *static_cast<const Function<ConstSignature>*>(this);
+ return fn.call_(fn.data_, static_cast<Args&&>(args)...);
+ }
+
+ class SharedProxy {
+ std::shared_ptr<Function<ConstSignature>> sp_;
+
+ public:
+ explicit SharedProxy(Function<ConstSignature>&& func)
+ : sp_(std::make_shared<Function<ConstSignature>>(std::move(func))) {}
+ ReturnType operator()(Args&&... args) const {
+ return (*sp_)(static_cast<Args&&>(args)...);
+ }
+ };
+};
+#endif
+
template <typename Fun>
bool execSmall(Op o, Data* src, Data* dst) {
switch (o) {
return true;
}
-// Invoke helper
-template <typename F, typename... Args>
-inline constexpr auto invoke(F&& f, Args&&... args)
- -> decltype(std::forward<F>(f)(std::forward<Args>(args)...)) {
- return std::forward<F>(f)(std::forward<Args>(args)...);
-}
-
-template <typename M, typename C, typename... Args>
-inline constexpr auto invoke(M(C::*d), Args&&... args)
- -> decltype(std::mem_fn(d)(std::forward<Args>(args)...)) {
- return std::mem_fn(d)(std::forward<Args>(args)...);
-}
-
} // namespace function
} // namespace detail
// invoking undefined behavior. Const-correctness is only violated when
// `FunctionType` is a const function type (e.g., `int() const`) and `*this`
// is the result of calling `constCastFunction`.
- mutable Data data_;
+ mutable Data data_{};
Call call_{&Traits::uninitCall};
Exec exec_{&detail::function::uninitNoop};
Function(const Function&) = delete;
#if __OBJC__
- // Delete conversion from Objective-C blocks
+ // Make sure Objective C blocks are copied
template <class ReturnType, class... Args>
- Function(ReturnType (^)(Args...)) = delete;
+ /*implicit*/ Function(ReturnType (^objCBlock)(Args... args))
+ : Function([blockCopy = (ReturnType (^)(Args...))[objCBlock copy]](
+ Args... args) { return blockCopy(args...); }){};
#endif
/**
Function& operator=(const Function&) = delete;
#if __OBJC__
- // Delete conversion from Objective-C blocks
+ // Make sure Objective C blocks are copied
template <class ReturnType, class... Args>
- Function& operator=(ReturnType (^)(Args...)) = delete;
+ /* implicit */ Function &operator=(ReturnType (^objCBlock)(Args... args)) {
+ (*this) = [blockCopy = (ReturnType (^)(Args...))[objCBlock copy]](
+ Args... args) { return blockCopy(args...); };
+ return *this;
+ }
#endif
/**
return std::move(that);
}
+#if FOLLY_HAVE_NOEXCEPT_FUNCTION_TYPE
+template <typename ReturnType, typename... Args>
+Function<ReturnType(Args...) const noexcept> constCastFunction(
+ Function<ReturnType(Args...) noexcept>&& that) noexcept {
+ return Function<ReturnType(Args...) const noexcept>{
+ std::move(that), detail::function::CoerceTag{}};
+}
+
+template <typename ReturnType, typename... Args>
+Function<ReturnType(Args...) const noexcept> constCastFunction(
+ Function<ReturnType(Args...) const noexcept>&& that) noexcept {
+ return std::move(that);
+}
+#endif
+
namespace detail {
namespace function {
template <typename Fun, typename FunctionType, typename = void>
template <typename Fun, typename FunctionType>
struct IsCallableAs : IsCallableAsImpl<Fun, FunctionType> {};
-}
-}
+} // namespace function
+} // namespace detail
/**
* @class FunctionRef
template <typename Fun>
static ReturnType call(void* object, Args&&... args) {
using Pointer = _t<std::add_pointer<Fun>>;
- return static_cast<ReturnType>(detail::function::invoke(
+ return static_cast<ReturnType>(invoke(
static_cast<Fun&&>(*static_cast<Pointer>(object)),
static_cast<Args&&>(args)...));
}