Add wrapper for getting X509_digest from a cert
[folly.git] / folly / Function.h
index d33ec9ebb4f1e102c234908658adafc4529588f8..ec145688b75ca0316e184db6c915277acbcc386b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016 Facebook, Inc.
+ * Copyright 2017-present Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+/*
+ * @author Eric Niebler (eniebler@fb.com), Sven Over (over@fb.com)
+ * Acknowledgements: Giuseppe Ottaviano (ott@fb.com)
+ */
 
 /**
  * @class Function
  * type of the embedded callable. E.g. a `folly::Function<int(int)>`
  * can wrap callables that return an `int` when passed an `int`. This can be a
  * function pointer or any class object implementing one or both of
+ *
  *     int operator(int);
  *     int operator(int) const;
+ *
  * If both are defined, the non-const one takes precedence.
  *
  * Unlike `std::function`, a `folly::Function` can wrap objects that are not
@@ -42,6 +48,7 @@
  * const-reference.
  *
  * For example:
+ *
  *     class Foo {
  *      public:
  *       void operator()() {
@@ -57,6 +64,7 @@
  *         foo_();
  *       }
  *     };
+ *
  * Even though `mutateFoo` is a const-method, so it can only reference `foo_`
  * as const, it is able to call the non-const `operator()` of the Foo
  * object that is embedded in the foo_ function.
  * wrapped function in a const context, you can wrap any functor that
  * implements either or both of const and non-const `operator()`.
  *
- * The first (and usually only specified) template parameter of
- * `folly::Function`, the `FunctionType`, can be const-qualified. Be aware
- * that the const is part of the function signature. It does not mean that
- * the function type is a const type.
+ * The template parameter of `folly::Function`, the `FunctionType`, can be
+ * const-qualified. Be aware that the const is part of the function signature.
+ * It does not mean that the function type is a const type.
  *
  *   using FunctionType = R(Args...);
  *   using ConstFunctionType = R(Args...) const;
  * Casting from a non-const to a const signature is potentially dangerous,
  * as it means that a function that may change its inner state when invoked
  * is made possible to call from a const context. Therefore this cast does
- * not happen implicitly. The function `folly::constCastfolly::Function` can
+ * not happen implicitly. The function `folly::constCastFunction` can
  * be used to perform the cast.
  *
  *     // Mutable lambda: can only be stored in a non-const folly::Function:
  *
  *     // const-cast to a const folly::Function:
  *     folly::Function<void() const> print_number_const =
- *       constCastfolly::Function(std::move(print_number));
+ *       constCastFunction(std::move(print_number));
  *
  * When to use const function types?
  * Generally, only when you need them. When you use a `folly::Function` as a
  *
  *     std::function<void(void)> stdfunc = someCallable;
  *
- *     folly::Function<void(void) const> uniqfunc = constCastfolly::Function(
+ *     folly::Function<void(void) const> uniqfunc = constCastFunction(
  *       folly::Function<void(void)>(someCallable)
  *     );
  *
  * You need to wrap the callable first in a non-const `folly::Function` to
  * select a non-const invoke operator (or the const one if no non-const one is
  * present), and then move it into a const `folly::Function` using
- * `constCastfolly::Function`.
- * The name of `constCastfolly::Function` should warn you that something
+ * `constCastFunction`.
+ * The name of `constCastFunction` should warn you that something
  * potentially dangerous is happening. As a matter of fact, using
  * `std::function` always involves this potentially dangerous aspect, which
  * is why it is not considered fully const-safe or even const-correct.
  * However, in most of the cases you will not need the dangerous aspect at all.
  * Either you do not require invokation of the function from a const context,
- * in which case you do not need to use `constCastfolly::Function` and just
+ * in which case you do not need to use `constCastFunction` and just
  * use the inner `folly::Function` in the example above, i.e. just use a
  * non-const `folly::Function`. Or, you may need invokation from const, but
  * the callable you are wrapping does not mutate its state (e.g. it is a class
  * object and implements `operator() const`, or it is a normal,
  * non-mutable lambda), in which case you can wrap the callable in a const
- * `folly::Function` directly, without using `constCastfolly::Function`.
+ * `folly::Function` directly, without using `constCastFunction`.
  * Only if you require invokation from a const context of a callable that
  * may mutate itself when invoked you have to go through the above procedure.
  * However, in that case what you do is potentially dangerous and requires
  * the equivalent of a `const_cast`, hence you need to call
- * `constCastfolly::Function`.
- *
- * `folly::Function` also has two additional template paremeters:
- *   * `NTM`: if set to `folly::FunctionMoveCtor::NO_THROW`, the
- *     `folly::Function` object is guaranteed to be nothrow move constructible.
- *     The downside is that any function object that itself is
- *     not nothrow move constructible cannot be stored in-place in the
- *     `folly::Function` object and will be stored on the heap instead.
- *   * `EmbedFunctorSize`: a number of bytes that will be reserved in the
- *     `folly::Function` object to store callable objects in-place. If you
- *     wrap a callable object bigger than this in a `folly::Function` object,
- *     it will be stored on the heap and the `folly::Function` object will keep
- *     a `std::unique_ptr` to it.
+ * `constCastFunction`.
  */
 
 #pragma once
 
 #include <functional>
+#include <memory>
+#include <new>
 #include <type_traits>
-#include <typeinfo>
 #include <utility>
 
-#include <folly/ScopeGuard.h>
-#include <folly/portability/Constexpr.h>
+#include <folly/CppAttributes.h>
+#include <folly/Portability.h>
+#include <folly/Traits.h>
+#include <folly/functional/Invoke.h>
 
 namespace folly {
 
-enum class FunctionMoveCtor { NO_THROW, MAY_THROW };
-
-template <
-    typename FunctionType,
-    FunctionMoveCtor NTM = FunctionMoveCtor::NO_THROW,
-    size_t EmbedFunctorSize = (NTM == FunctionMoveCtor::NO_THROW)
-        ? sizeof(void (*)(void))
-        : sizeof(std::function<void(void)>)>
+template <typename FunctionType>
 class Function;
 
-} // folly
+template <typename ReturnType, typename... Args>
+Function<ReturnType(Args...) const> constCastFunction(
+    Function<ReturnType(Args...)>&&) noexcept;
 
-// boring predeclarations and details
-#include "Function-pre.h"
+#if FOLLY_HAVE_NOEXCEPT_FUNCTION_TYPE
+template <typename ReturnType, typename... Args>
+Function<ReturnType(Args...) const noexcept> constCastFunction(
+    Function<ReturnType(Args...) noexcept>&&) noexcept;
+#endif
 
-namespace folly {
+namespace detail {
+namespace function {
+
+enum class Op { MOVE, NUKE, FULL, HEAP };
+
+union Data {
+  void* big;
+  std::aligned_storage<6 * sizeof(void*)>::type tiny;
+};
+
+template <typename Fun, typename = Fun*>
+using IsSmall = Conjunction<
+    std::integral_constant<bool, (sizeof(Fun) <= sizeof(Data::tiny))>,
+    std::is_nothrow_move_constructible<Fun>>;
+using SmallTag = std::true_type;
+using HeapTag = std::false_type;
+
+template <typename T>
+struct NotFunction : std::true_type {};
+template <typename T>
+struct NotFunction<Function<T>> : std::false_type {};
+
+template <typename T>
+using EnableIfNotFunction =
+    typename std::enable_if<NotFunction<T>::value>::type;
+
+struct CoerceTag {};
+
+template <typename T>
+bool isNullPtrFn(T* p) {
+  return p == nullptr;
+}
+template <typename T>
+std::false_type isNullPtrFn(T&&) {
+  return {};
+}
+
+inline bool uninitNoop(Op, Data*, Data*) {
+  return false;
+}
+
+template <typename FunctionType>
+struct FunctionTraits;
+
+template <typename ReturnType, typename... Args>
+struct FunctionTraits<ReturnType(Args...)> {
+  using Call = ReturnType (*)(Data&, Args&&...);
+  using IsConst = std::false_type;
+  using ConstSignature = ReturnType(Args...) const;
+  using NonConstSignature = ReturnType(Args...);
+  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) {
+    return static_cast<ReturnType>((*static_cast<Fun*>(
+        static_cast<void*>(&p.tiny)))(static_cast<Args&&>(args)...));
+  }
 
-template <typename FunctionType, FunctionMoveCtor NTM, size_t EmbedFunctorSize>
-class Function final
-    : public detail::function::FunctionTypeTraits<FunctionType>::
-          template InvokeOperator<
-              Function<FunctionType, NTM, EmbedFunctorSize>>,
-      public detail::function::MaybeUnaryOrBinaryFunction<FunctionType> {
- private:
-  using Traits = detail::function::FunctionTypeTraits<FunctionType>;
-  static_assert(
-      Traits::SuitableForFunction::value,
-      "Function<FunctionType>: FunctionType must be of the "
-      "form 'R(Args...)' or 'R(Args...) const'");
-
-  using ThisType = Function<FunctionType, NTM, EmbedFunctorSize>;
-  using InvokeOperator = typename Traits::template InvokeOperator<ThisType>;
-
-  static constexpr bool hasNoExceptMoveCtor() noexcept {
-    return NTM == FunctionMoveCtor::NO_THROW;
+  template <typename Fun>
+  static ReturnType callBig(Data& p, Args&&... args) {
+    return static_cast<ReturnType>(
+        (*static_cast<Fun*>(p.big))(static_cast<Args&&>(args)...));
+  }
+
+  static ReturnType uninitCall(Data&, Args&&...) {
+    throw std::bad_function_call();
+  }
+
+  ReturnType operator()(Args... args) {
+    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)...);
+    }
   };
+};
 
- public:
-  // not copyable
-  Function(Function const&) = delete;
-  Function& operator=(Function const&) = delete;
+template <typename ReturnType, typename... Args>
+struct FunctionTraits<ReturnType(Args...) const> {
+  using Call = ReturnType (*)(Data&, Args&&...);
+  using IsConst = std::true_type;
+  using ConstSignature = ReturnType(Args...) const;
+  using NonConstSignature = ReturnType(Args...);
+  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) {
+    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) {
+    return static_cast<ReturnType>(
+        (*static_cast<const Fun*>(p.big))(static_cast<Args&&>(args)...));
+  }
+
+  static ReturnType uninitCall(Data&, Args&&...) {
+    throw std::bad_function_call();
+  }
+
+  ReturnType operator()(Args... args) const {
+    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)...);
+    }
+  };
+};
+
+#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) {
+    case Op::MOVE:
+      ::new (static_cast<void*>(&dst->tiny))
+          Fun(std::move(*static_cast<Fun*>(static_cast<void*>(&src->tiny))));
+      FOLLY_FALLTHROUGH;
+    case Op::NUKE:
+      static_cast<Fun*>(static_cast<void*>(&src->tiny))->~Fun();
+      break;
+    case Op::FULL:
+      return true;
+    case Op::HEAP:
+      break;
+  }
+  return false;
+}
+
+template <typename Fun>
+bool execBig(Op o, Data* src, Data* dst) {
+  switch (o) {
+    case Op::MOVE:
+      dst->big = src->big;
+      src->big = nullptr;
+      break;
+    case Op::NUKE:
+      delete static_cast<Fun*>(src->big);
+      break;
+    case Op::FULL:
+    case Op::HEAP:
+      break;
+  }
+  return true;
+}
+
+} // namespace function
+} // namespace detail
+
+template <typename FunctionType>
+class Function final : private detail::function::FunctionTraits<FunctionType> {
+  // These utility types are defined outside of the template to reduce
+  // the number of instantiations, and then imported in the class
+  // namespace for convenience.
+  using Data = detail::function::Data;
+  using Op = detail::function::Op;
+  using SmallTag = detail::function::SmallTag;
+  using HeapTag = detail::function::HeapTag;
+  using CoerceTag = detail::function::CoerceTag;
+
+  using Traits = detail::function::FunctionTraits<FunctionType>;
+  using Call = typename Traits::Call;
+  using Exec = bool (*)(Op, Data*, Data*);
+
+  template <typename Fun>
+  using IsSmall = detail::function::IsSmall<Fun>;
+
+  // The `data_` member is mutable to allow `constCastFunction` to work without
+  // 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_{};
+  Call call_{&Traits::uninitCall};
+  Exec exec_{&detail::function::uninitNoop};
+
+  friend Traits;
+  friend Function<typename Traits::ConstSignature> folly::constCastFunction<>(
+      Function<typename Traits::NonConstSignature>&&) noexcept;
+  friend class Function<typename Traits::OtherSignature>;
+
+  template <typename Fun>
+  Function(Fun&& fun, SmallTag) noexcept {
+    using FunT = typename std::decay<Fun>::type;
+    if (!detail::function::isNullPtrFn(fun)) {
+      ::new (static_cast<void*>(&data_.tiny)) FunT(static_cast<Fun&&>(fun));
+      call_ = &Traits::template callSmall<FunT>;
+      exec_ = &detail::function::execSmall<FunT>;
+    }
+  }
+
+  template <typename Fun>
+  Function(Fun&& fun, HeapTag) {
+    using FunT = typename std::decay<Fun>::type;
+    data_.big = new FunT(static_cast<Fun&&>(fun));
+    call_ = &Traits::template callBig<FunT>;
+    exec_ = &detail::function::execBig<FunT>;
+  }
+
+  template <typename Signature>
+  Function(Function<Signature>&& that, CoerceTag)
+      : Function(static_cast<Function<Signature>&&>(that), HeapTag{}) {}
+
+  Function(
+      Function<typename Traits::OtherSignature>&& that,
+      CoerceTag) noexcept {
+    that.exec_(Op::MOVE, &that.data_, &data_);
+    std::swap(call_, that.call_);
+    std::swap(exec_, that.exec_);
+  }
+
+ public:
   /**
    * Default constructor. Constructs an empty Function.
    */
-  Function() noexcept {
-    initializeEmptyExecutor();
-  }
+  Function() = default;
 
-  ~Function() {
-    destroyExecutor();
+  // not copyable
+  Function(const Function&) = delete;
 
-    static_assert(
-        kStorageSize == sizeof(*this),
-        "There is something wrong with the size of Function");
-  }
+#if __OBJC__
+  // Make sure Objective C blocks are copied
+  template <class ReturnType, class... Args>
+  /*implicit*/ Function(ReturnType (^objCBlock)(Args... args))
+      : Function([blockCopy = (ReturnType (^)(Args...))[objCBlock copy]](
+                     Args... args) { return blockCopy(args...); }){};
+#endif
 
-  // construct/assign from Function
   /**
    * Move constructor
    */
-  Function(Function&& other) noexcept(hasNoExceptMoveCtor());
+  Function(Function&& that) noexcept {
+    that.exec_(Op::MOVE, &that.data_, &data_);
+    std::swap(call_, that.call_);
+    std::swap(exec_, that.exec_);
+  }
+
   /**
-   * Move assignment operator
+   * Constructs an empty `Function`.
    */
-  Function& operator=(Function&& rhs) noexcept(hasNoExceptMoveCtor());
+  /* implicit */ Function(std::nullptr_t) noexcept {}
 
   /**
-   * Constructs a `Function` by moving from one with different template
-   * parameters with regards to const-ness, no-except-movability and internal
-   * storage size.
+   * Constructs a new `Function` from any callable object that is _not_ a
+   * `folly::Function`. This handles function pointers, pointers to static
+   * member functions, `std::reference_wrapper` objects, `std::function`
+   * objects, and arbitrary objects that implement `operator()` if the parameter
+   * signature matches (i.e. it returns an object convertible to `R` when called
+   * with `Args...`).
+   *
+   * \note `typename = ResultOf<Fun>` prevents this overload from being
+   * selected by overload resolution when `fun` is not a compatible function.
+   *
+   * \note The noexcept requires some explanation. IsSmall is true when the
+   * decayed type fits within the internal buffer and is noexcept-movable. But
+   * this ctor might copy, not move. What we need here, if this ctor does a
+   * copy, is that this ctor be noexcept when the copy is noexcept. That is not
+   * checked in IsSmall, and shouldn't be, because once the Function is
+   * constructed, the contained object is never copied. This check is for this
+   * ctor only, in the case that this ctor does a copy.
    */
   template <
-      typename OtherFunctionType,
-      FunctionMoveCtor OtherNTM,
-      size_t OtherEmbedFunctorSize>
-  Function(Function<OtherFunctionType, OtherNTM, OtherEmbedFunctorSize>&& other)
-  noexcept(
-      OtherNTM == FunctionMoveCtor::NO_THROW &&
-      EmbedFunctorSize >= OtherEmbedFunctorSize);
+      typename Fun,
+      typename = detail::function::EnableIfNotFunction<Fun>,
+      typename = typename Traits::template ResultOf<Fun>>
+  /* implicit */ Function(Fun fun) noexcept(
+      IsSmall<Fun>::value && noexcept(Fun(std::declval<Fun>())))
+      : Function(static_cast<Fun&&>(fun), IsSmall<Fun>{}) {}
 
   /**
-   * Moves a `Function` with different template parameters with regards
-   * to const-ness, no-except-movability and internal storage size into this
-   * one.
+   * For move-constructing from a `folly::Function<X(Ys...) [const?]>`.
+   * For a `Function` with a `const` function type, the object must be
+   * callable from a `const`-reference, i.e. implement `operator() const`.
+   * For a `Function` with a non-`const` function type, the object will
+   * be called from a non-const reference, which means that it will execute
+   * a non-const `operator()` if it is defined, and falls back to
+   * `operator() const` otherwise.
    */
   template <
-      typename RhsFunctionType,
-      FunctionMoveCtor RhsNTM,
-      size_t RhsEmbedFunctorSize>
-  Function& operator=(Function<RhsFunctionType, RhsNTM, RhsEmbedFunctorSize>&&
-                          rhs) noexcept(RhsNTM == FunctionMoveCtor::NO_THROW);
+      typename Signature,
+      typename = typename Traits::template ResultOf<Function<Signature>>>
+  Function(Function<Signature>&& that) noexcept(
+      noexcept(Function(std::move(that), CoerceTag{})))
+      : Function(std::move(that), CoerceTag{}) {}
 
   /**
-   * Constructs an empty `Function`.
+   * If `ptr` is null, constructs an empty `Function`. Otherwise,
+   * this constructor is equivalent to `Function(std::mem_fn(ptr))`.
    */
-  /* implicit */ Function(std::nullptr_t) noexcept : Function() {}
+  template <
+      typename Member,
+      typename Class,
+      // Prevent this overload from being selected when `ptr` is not a
+      // compatible member function pointer.
+      typename = decltype(Function(std::mem_fn((Member Class::*)0)))>
+  /* implicit */ Function(Member Class::*ptr) noexcept {
+    if (ptr) {
+      *this = std::mem_fn(ptr);
+    }
+  }
 
-  /**
-   * Clears this `Function`.
-   */
-  Function& operator=(std::nullptr_t) noexcept {
-    destroyExecutor();
-    initializeEmptyExecutor();
+  ~Function() {
+    exec_(Op::NUKE, &data_, nullptr);
+  }
+
+  Function& operator=(const Function&) = delete;
+
+#if __OBJC__
+  // Make sure Objective C blocks are copied
+  template <class ReturnType, class... Args>
+  /* implicit */ Function &operator=(ReturnType (^objCBlock)(Args... args)) {
+    (*this) = [blockCopy = (ReturnType (^)(Args...))[objCBlock copy]](
+                  Args... args) { return blockCopy(args...); };
     return *this;
   }
+#endif
 
   /**
-   * Constructs a new `Function` from any callable object. This
-   * handles function pointers, pointers to static member functions,
-   * `std::reference_wrapper` objects, `std::function` objects, and arbitrary
-   * objects that implement `operator()` if the parameter signature
-   * matches (i.e. it returns R when called with Args...).
-   * For a `Function` with a const function type, the object must be
-   * callable from a const-reference, i.e. implement `operator() const`.
-   * For a `Function` with a non-const function type, the object will
-   * be called from a non-const reference, which means that it will execute
-   * a non-const `operator()` if it is defined, and falls back to
-   * `operator() const` otherwise
+   * Move assignment operator
+   *
+   * \note Leaves `that` in a valid but unspecified state. If `&that == this`
+   * then `*this` is left in a valid but unspecified state.
    */
-  template <typename F>
-  /* implicit */ Function(
-      F&& f,
-      typename std::enable_if<
-          detail::function::IsCallable<F, FunctionType>::value>::type* =
-          0) noexcept(noexcept(typename std::decay<F>::
-                                   type(std::forward<F>(f)))) {
-    createExecutor(std::forward<F>(f));
+  Function& operator=(Function&& that) noexcept {
+    // Q: Why is it safe to destroy and reconstruct this object in place?
+    // A: Two reasons: First, `Function` is a final class, so in doing this
+    //    we aren't slicing off any derived parts. And second, the move
+    //    operation is guaranteed not to throw so we always leave the object
+    //    in a valid state.
+    // In the case of self-move (this == &that), this leaves the object in
+    // a default-constructed state. First the object is destroyed, then we
+    // pass the destroyed object to the move constructor. The first thing the
+    // move constructor does is default-construct the object. That object is
+    // "moved" into itself, which is a no-op for a default-constructed Function.
+    this->~Function();
+    ::new (this) Function(std::move(that));
+    return *this;
   }
 
   /**
-   * Assigns a callable object to this `Function`.
+   * Assigns a callable object to this `Function`. If the operation fails,
+   * `*this` is left unmodified.
+   *
+   * \note `typename = ResultOf<Fun>` prevents this overload from being
+   * selected by overload resolution when `fun` is not a compatible function.
    */
-  template <typename F>
-  typename std::enable_if<
-      detail::function::IsCallable<F, FunctionType>::value,
-      Function&>::type
-  operator=(F&& f) noexcept(
-      noexcept(typename std::decay<F>::type(std::forward<F>(f)))) {
-    destroyExecutor();
-    SCOPE_FAIL {
-      initializeEmptyExecutor();
-    };
-    createExecutor(std::forward<F>(f));
+  template <typename Fun, typename = decltype(Function(std::declval<Fun>()))>
+  Function& operator=(Fun fun) noexcept(
+      noexcept(/* implicit */ Function(std::declval<Fun>()))) {
+    // Doing this in place is more efficient when we can do so safely.
+    if (noexcept(/* implicit */ Function(std::declval<Fun>()))) {
+      // Q: Why is is safe to destroy and reconstruct this object in place?
+      // A: See the explanation in the move assignment operator.
+      this->~Function();
+      ::new (this) Function(static_cast<Fun&&>(fun));
+    } else {
+      // Construct a temporary and (nothrow) swap.
+      Function(static_cast<Fun&&>(fun)).swap(*this);
+    }
     return *this;
   }
 
   /**
-   * Exchanges the callable objects of `*this` and `other`. `other` can be
-   * a Function with different settings with regard to
-   * no-except-movability and internal storage size, but must match
-   * `*this` with regards to return type and argument types.
+   * For assigning from a `Function<X(Ys..) [const?]>`.
    */
-  template <FunctionMoveCtor OtherNTM, size_t OtherEmbedFunctorSize>
-  void
-  swap(Function<FunctionType, OtherNTM, OtherEmbedFunctorSize>& o) noexcept(
-      hasNoExceptMoveCtor() && OtherNTM == FunctionMoveCtor::NO_THROW);
+  template <
+      typename Signature,
+      typename = typename Traits::template ResultOf<Function<Signature>>>
+  Function& operator=(Function<Signature>&& that) noexcept(
+      noexcept(Function(std::move(that)))) {
+    return (*this = Function(std::move(that)));
+  }
 
   /**
-   * Returns `true` if this `Function` contains a callable, i.e. is
-   * non-empty.
+   * Clears this `Function`.
    */
-  explicit operator bool() const noexcept;
+  Function& operator=(std::nullptr_t) noexcept {
+    return (*this = Function());
+  }
 
   /**
-   * Returns `true` if this `Function` stores the callable on the
-   * heap. If `false` is returned, there has been no additional memory
-   * allocation and the callable is stored inside the `Function`
-   * object itself.
+   * If `ptr` is null, clears this `Function`. Otherwise, this assignment
+   * operator is equivalent to `*this = std::mem_fn(ptr)`.
    */
-  bool hasAllocatedMemory() const noexcept;
+  template <typename Member, typename Class>
+  auto operator=(Member Class::*ptr) noexcept
+      // Prevent this overload from being selected when `ptr` is not a
+      // compatible member function pointer.
+      -> decltype(operator=(std::mem_fn(ptr))) {
+    return ptr ? (*this = std::mem_fn(ptr)) : (*this = Function());
+  }
 
   /**
-   * Returns the `type_info` (as returned by `typeid`) of the callable stored
-   * in this `Function`. Returns `typeid(void)` if empty.
+   * Call the wrapped callable object with the specified arguments.
    */
-  std::type_info const& target_type() const noexcept;
+  using Traits::operator();
 
   /**
-   * Returns a pointer to the stored callable if its type matches `T`, and
-   * `nullptr` otherwise.
+   * Exchanges the callable objects of `*this` and `that`.
    */
-  template <typename T>
-  T* target() noexcept;
+  void swap(Function& that) noexcept {
+    std::swap(*this, that);
+  }
 
   /**
-   * Returns a const-pointer to the stored callable if its type matches `T`,
-   * and `nullptr` otherwise.
+   * Returns `true` if this `Function` contains a callable, i.e. is
+   * non-empty.
    */
-  template <typename T>
-  const T* target() const noexcept;
+  explicit operator bool() const noexcept {
+    return exec_(Op::FULL, nullptr, nullptr);
+  }
 
   /**
-   * Move out this `Function` into one with a const function type.
-   *
-   * This is a potentially dangerous operation, equivalent to a `const_cast`.
-   * This converts a `Function` with a non-const function type, i.e.
-   * one that can only be called when in the form of a non-const reference,
-   * into one that can be called in a const context. Use at your own risk!
+   * Returns `true` if this `Function` stores the callable on the
+   * heap. If `false` is returned, there has been no additional memory
+   * allocation and the callable is stored inside the `Function`
+   * object itself.
    */
-  Function<typename Traits::ConstFunctionType, NTM, EmbedFunctorSize>
-      castToConstFunction() && noexcept(hasNoExceptMoveCtor());
-
-  using SignatureType = FunctionType;
-  using ResultType = typename Traits::ResultType;
-  using ArgsTuple = typename Traits::ArgsTuple;
-
- private:
-  template <class, FunctionMoveCtor, size_t>
-  friend class Function;
-
-  friend struct detail::function::FunctionTypeTraits<FunctionType>;
+  bool hasAllocatedMemory() const noexcept {
+    return exec_(Op::HEAP, nullptr, nullptr);
+  }
 
-  using ExecutorIf =
-      typename detail::function::Executors<FunctionType>::ExecutorIf;
-  using EmptyExecutor =
-      typename detail::function::Executors<FunctionType>::EmptyExecutor;
-  template <typename F, typename SelectFunctionTag>
-  using FunctorPtrExecutor = typename detail::function::Executors<
-      FunctionType>::template FunctorPtrExecutor<F, SelectFunctionTag>;
-  template <typename F, typename SelectFunctionTag>
-  using FunctorExecutor = typename detail::function::Executors<
-      FunctionType>::template FunctorExecutor<F, SelectFunctionTag>;
+  using typename Traits::SharedProxy;
 
-  template <typename T>
-  T const* access() const;
+  /**
+   * Move this `Function` into a copyable callable object, of which all copies
+   * share the state.
+   */
+  SharedProxy asSharedProxy() && {
+    return SharedProxy{std::move(*this)};
+  }
 
-  template <typename T>
-  T* access();
+  /**
+   * Construct a `std::function` by moving in the contents of this `Function`.
+   * Note that the returned `std::function` will share its state (i.e. captured
+   * data) across all copies you make of it, so be very careful when copying.
+   */
+  std::function<typename Traits::NonConstSignature> asStdFunction() && {
+    return std::move(*this).asSharedProxy();
+  }
+};
 
-  void initializeEmptyExecutor() noexcept;
+template <typename FunctionType>
+void swap(Function<FunctionType>& lhs, Function<FunctionType>& rhs) noexcept {
+  lhs.swap(rhs);
+}
 
-  template <typename F>
-  void createExecutor(F&& f) noexcept(
-      noexcept(typename std::decay<F>::type(std::forward<F>(f))));
+template <typename FunctionType>
+bool operator==(const Function<FunctionType>& fn, std::nullptr_t) {
+  return !fn;
+}
 
-  void destroyExecutor() noexcept;
+template <typename FunctionType>
+bool operator==(std::nullptr_t, const Function<FunctionType>& fn) {
+  return !fn;
+}
 
-  struct MinStorageSize;
+template <typename FunctionType>
+bool operator!=(const Function<FunctionType>& fn, std::nullptr_t) {
+  return !(fn == nullptr);
+}
 
-  typename std::aligned_storage<MinStorageSize::value>::type data_;
-  static constexpr size_t kStorageSize = sizeof(data_);
-};
+template <typename FunctionType>
+bool operator!=(std::nullptr_t, const Function<FunctionType>& fn) {
+  return !(nullptr == fn);
+}
 
-// operator==
-template <typename FunctionType, FunctionMoveCtor NTM, size_t EmbedFunctorSize>
-inline bool operator==(
-    Function<FunctionType, NTM, EmbedFunctorSize> const& f,
-    std::nullptr_t) noexcept {
-  return !f;
+/**
+ * NOTE: See detailed note about `constCastFunction` at the top of the file.
+ * This is potentially dangerous and requires the equivalent of a `const_cast`.
+ */
+template <typename ReturnType, typename... Args>
+Function<ReturnType(Args...) const> constCastFunction(
+    Function<ReturnType(Args...)>&& that) noexcept {
+  return Function<ReturnType(Args...) const>{std::move(that),
+                                             detail::function::CoerceTag{}};
 }
 
-template <typename FunctionType, FunctionMoveCtor NTM, size_t EmbedFunctorSize>
-inline bool operator==(
-    std::nullptr_t,
-    Function<FunctionType, NTM, EmbedFunctorSize> const& f) noexcept {
-  return !f;
+template <typename ReturnType, typename... Args>
+Function<ReturnType(Args...) const> constCastFunction(
+    Function<ReturnType(Args...) const>&& that) noexcept {
+  return std::move(that);
 }
 
-template <typename FunctionType, FunctionMoveCtor NTM, size_t EmbedFunctorSize>
-inline bool operator!=(
-    Function<FunctionType, NTM, EmbedFunctorSize> const& f,
-    std::nullptr_t) noexcept {
-  return !!f;
+#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 FunctionType, FunctionMoveCtor NTM, size_t EmbedFunctorSize>
-inline bool operator!=(
-    std::nullptr_t,
-    Function<FunctionType, NTM, EmbedFunctorSize> const& f) noexcept {
-  return !!f;
+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>
+struct IsCallableAsImpl : std::false_type {};
+
+template <typename Fun, typename ReturnType, typename... Args>
+struct IsCallableAsImpl<
+    Fun,
+    ReturnType(Args...),
+    void_t<typename std::result_of<Fun && (Args && ...)>::type>>
+    : std::is_convertible<
+          typename std::result_of<Fun && (Args && ...)>::type,
+          ReturnType> {};
+
+template <typename Fun, typename FunctionType>
+struct IsCallableAs : IsCallableAsImpl<Fun, FunctionType> {};
+} // namespace function
+} // namespace detail
 
 /**
- * Cast a `Function` into one with a const function type.
- *
- * This is a potentially dangerous operation, equivalent to a `const_cast`.
- * This converts a `Function` with a non-const function type, i.e.
- * one that can only be called when in the form of a non-const reference,
- * into one that can be called in a const context. Use at your own risk!
+ * @class FunctionRef
+ *
+ * @brief A reference wrapper for callable objects
+ *
+ * FunctionRef is similar to std::reference_wrapper, but the template parameter
+ * is the function signature type rather than the type of the referenced object.
+ * A folly::FunctionRef is cheap to construct as it contains only a pointer to
+ * the referenced callable and a pointer to a function which invokes the
+ * callable.
+ *
+ * The user of FunctionRef must be aware of the reference semantics: storing a
+ * copy of a FunctionRef is potentially dangerous and should be avoided unless
+ * the referenced object definitely outlives the FunctionRef object. Thus any
+ * function that accepts a FunctionRef parameter should only use it to invoke
+ * the referenced function and not store a copy of it. Knowing that FunctionRef
+ * itself has reference semantics, it is generally okay to use it to reference
+ * lambdas that capture by reference.
  */
-template <typename FunctionType, FunctionMoveCtor NTM, size_t EmbedFunctorSize>
-Function<
-    typename detail::function::FunctionTypeTraits<
-        FunctionType>::ConstFunctionType,
-    NTM,
-    EmbedFunctorSize>
-constCastFunction(Function<FunctionType, NTM, EmbedFunctorSize>&&
-                      from) noexcept(NTM == FunctionMoveCtor::NO_THROW) {
-  return std::move(from).castToConstFunction();
-}
 
-} // folly
+template <typename FunctionType>
+class FunctionRef;
 
-namespace std {
-template <typename FunctionType, bool NOM1, bool NOM2, size_t S1, size_t S2>
-void swap(
-    ::folly::Function<FunctionType, NOM1, S1>& lhs,
-    ::folly::Function<FunctionType, NOM2, S2>& rhs) {
-  lhs.swap(rhs);
-}
-} // std
+template <typename ReturnType, typename... Args>
+class FunctionRef<ReturnType(Args...)> final {
+  using Call = ReturnType (*)(void*, Args&&...);
+
+  static ReturnType uninitCall(void*, Args&&...) {
+    throw std::bad_function_call();
+  }
+
+  template <typename Fun>
+  static ReturnType call(void* object, Args&&... args) {
+    using Pointer = _t<std::add_pointer<Fun>>;
+    return static_cast<ReturnType>(invoke(
+        static_cast<Fun&&>(*static_cast<Pointer>(object)),
+        static_cast<Args&&>(args)...));
+  }
+
+  void* object_{nullptr};
+  Call call_{&FunctionRef::uninitCall};
+
+ public:
+  /**
+   * Default constructor. Constructs an empty FunctionRef.
+   *
+   * Invoking it will throw std::bad_function_call.
+   */
+  FunctionRef() = default;
+
+  /**
+   * Construct a FunctionRef from a reference to a callable object.
+   */
+  template <
+      typename Fun,
+      typename std::enable_if<
+          Conjunction<
+              Negation<std::is_same<FunctionRef, _t<std::decay<Fun>>>>,
+              detail::function::IsCallableAs<Fun, ReturnType(Args...)>>::value,
+          int>::type = 0>
+  constexpr /* implicit */ FunctionRef(Fun&& fun) noexcept
+      // `Fun` may be a const type, in which case we have to do a const_cast
+      // to store the address in a `void*`. This is safe because the `void*`
+      // will be cast back to `Fun*` (which is a const pointer whenever `Fun`
+      // is a const type) inside `FunctionRef::call`
+      : object_(
+            const_cast<void*>(static_cast<void const*>(std::addressof(fun)))),
+        call_(&FunctionRef::call<Fun>) {}
+
+  ReturnType operator()(Args... args) const {
+    return call_(object_, static_cast<Args&&>(args)...);
+  }
+
+  constexpr explicit operator bool() const {
+    return object_;
+  }
+};
 
-#include "Function-inl.h"
+} // namespace folly