]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
Add function2 header
authorAdam C. Emerson <aemerson@redhat.com>
Sun, 21 Oct 2018 23:04:03 +0000 (19:04 -0400)
committerAdam C. Emerson <aemerson@redhat.com>
Mon, 8 Apr 2019 16:45:41 +0000 (12:45 -0400)
From https://github.com/Naios/function2/

This provides unique_function, a move-only, type-erased function
wrapper.

I copied the file in rather than using a submodule because it's only
one file, and a submodule seems rather like killing a mosquito with an
anti-tank gun.

Chosen over the slightly more capable cxx_function because that
version fails its basic contract.

Signed-off-by: Adam C. Emerson <aemerson@redhat.com>
COPYING
src/include/function2.hpp [new file with mode: 0644]

diff --git a/COPYING b/COPYING
index 8d663702b639b4a652ab246b2aa96d06da1ebf83..47b3146219bcd1a026b4d23ee13a6c10eb2c6795 100644 (file)
--- a/COPYING
+++ b/COPYING
@@ -154,3 +154,6 @@ Files: src/ceph-volume/plugin/zfs/*
 Copyright: 2018, Willem Jan Withagen
 License: BSD 3-clause
 
+Files: src/include/function2.hpp
+Copyright: 2015-2018, Denis Blank
+License: Boost Software License, Version 1.0
\ No newline at end of file
diff --git a/src/include/function2.hpp b/src/include/function2.hpp
new file mode 100644 (file)
index 0000000..613e651
--- /dev/null
@@ -0,0 +1,1581 @@
+
+//  Copyright 2015-2018 Denis Blank <denis.blank at outlook dot com>
+//     Distributed under the Boost Software License, Version 1.0
+//       (See accompanying file LICENSE_1_0.txt or copy at
+//             http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef FU2_INCLUDED_FUNCTION2_HPP_
+#define FU2_INCLUDED_FUNCTION2_HPP_
+
+#include <cassert>
+#include <cstdlib>
+#include <memory>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+// Defines:
+// - FU2_HAS_DISABLED_EXCEPTIONS
+#if defined(FU2_WITH_DISABLED_EXCEPTIONS) ||                                   \
+    defined(FU2_MACRO_DISABLE_EXCEPTIONS)
+#define FU2_HAS_DISABLED_EXCEPTIONS
+#else // FU2_WITH_DISABLED_EXCEPTIONS
+#if defined(_MSC_VER)
+#if !defined(_HAS_EXCEPTIONS) || (_HAS_EXCEPTIONS == 0)
+#define FU2_HAS_DISABLED_EXCEPTIONS
+#endif
+#elif defined(__clang__)
+#if !(__EXCEPTIONS && __has_feature(cxx_exceptions))
+#define FU2_HAS_DISABLED_EXCEPTIONS
+#endif
+#elif defined(__GNUC__)
+#if !__EXCEPTIONS
+#define FU2_HAS_DISABLED_EXCEPTIONS
+#endif
+#endif
+#endif // FU2_WITH_DISABLED_EXCEPTIONS
+// - FU2_HAS_NO_FUNCTIONAL_HEADER
+#if !defined(FU2_WITH_NO_FUNCTIONAL_HEADER) ||                                 \
+    !defined(FU2_NO_FUNCTIONAL_HEADER) ||                                      \
+    !defined(FU2_HAS_DISABLED_EXCEPTIONS)
+#define FU2_HAS_NO_FUNCTIONAL_HEADER
+#include <functional>
+#endif
+// - FU2_HAS_CXX17_NOEXCEPT_FUNCTION_TYPE
+#if defined(FU2_WITH_CXX17_NOEXCEPT_FUNCTION_TYPE)
+#define FU2_HAS_CXX17_NOEXCEPT_FUNCTION_TYPE
+#else // FU2_WITH_CXX17_NOEXCEPT_FUNCTION_TYPE
+#if defined(_MSC_VER)
+#if defined(_HAS_CXX17) && _HAS_CXX17
+#define FU2_HAS_CXX17_NOEXCEPT_FUNCTION_TYPE
+#endif
+#elif defined(__cpp_noexcept_function_type)
+#define FU2_HAS_CXX17_NOEXCEPT_FUNCTION_TYPE
+#elif defined(__cplusplus) && (__cplusplus >= 201703L)
+#define FU2_HAS_CXX17_NOEXCEPT_FUNCTION_TYPE
+#endif
+#endif // FU2_WITH_CXX17_NOEXCEPT_FUNCTION_TYPE
+
+#if !defined(FU2_HAS_DISABLED_EXCEPTIONS)
+#include <exception>
+#endif
+
+namespace fu2 {
+inline namespace abi_310 {
+namespace detail {
+template <typename Config, typename Property>
+class function;
+
+template <typename...>
+struct identity {};
+
+// Equivalent to C++17's std::void_t which is targets a bug in GCC,
+// that prevents correct SFINAE behavior.
+// See http://stackoverflow.com/questions/35753920 for details.
+template <typename...>
+struct deduce_to_void : std::common_type<void> {};
+
+template <typename... T>
+using void_t = typename deduce_to_void<T...>::type;
+
+// Copy enabler helper class
+template <bool /*Copyable*/>
+struct copyable {};
+template <>
+struct copyable<false> {
+  copyable() = default;
+  ~copyable() = default;
+  copyable(copyable const&) = delete;
+  copyable(copyable&&) = default;
+  copyable& operator=(copyable const&) = delete;
+  copyable& operator=(copyable&&) = default;
+};
+
+/// Configuration trait to configure the function_base class.
+template <bool Owning, bool Copyable, std::size_t Capacity>
+struct config {
+  // Is true if the function is copyable.
+  static constexpr auto const is_owning = Owning;
+
+  // Is true if the function is copyable.
+  static constexpr auto const is_copyable = Copyable;
+
+  // The internal capacity of the function
+  // used in small functor optimization.
+  static constexpr auto const capacity = Capacity;
+};
+
+/// A config which isn't compatible to other configs
+template <bool Throws, bool HasStrongExceptGuarantee, typename... Args>
+struct property {
+  // Is true when the function throws an exception on empty invocation.
+  static constexpr auto const is_throwing = Throws;
+
+  // Is true when the function throws an exception on empty invocation.
+  static constexpr auto const is_strong_exception_guaranteed = Throws;
+};
+
+/// Provides utilities for invocing callable objects
+namespace invocation {
+/// Invokes the given callable object with the given arguments
+template <typename Callable, typename... Args>
+constexpr auto invoke(Callable&& callable, Args&&... args) noexcept(
+    noexcept(std::forward<Callable>(callable)(std::forward<Args>(args)...)))
+    -> decltype(std::forward<Callable>(callable)(std::forward<Args>(args)...)) {
+
+  return std::forward<Callable>(callable)(std::forward<Args>(args)...);
+}
+/// Invokes the given member function pointer by reference
+template <typename T, typename Type, typename Self, typename... Args>
+constexpr auto invoke(Type T::*member, Self&& self, Args&&... args) noexcept(
+    noexcept((std::forward<Self>(self).*member)(std::forward<Args>(args)...)))
+    -> decltype((std::forward<Self>(self).*
+                 member)(std::forward<Args>(args)...)) {
+  return (std::forward<Self>(self).*member)(std::forward<Args>(args)...);
+}
+/// Invokes the given member function pointer by pointer
+template <typename T, typename Type, typename Self, typename... Args>
+constexpr auto invoke(Type T::*member, Self&& self, Args&&... args) noexcept(
+    noexcept((std::forward<Self>(self)->*member)(std::forward<Args>(args)...)))
+    -> decltype(
+        (std::forward<Self>(self)->*member)(std::forward<Args>(args)...)) {
+  return (std::forward<Self>(self)->*member)(std::forward<Args>(args)...);
+}
+/// Invokes the given pointer to a scalar member by reference
+template <typename T, typename Type, typename Self>
+constexpr auto
+invoke(Type T::*member,
+       Self&& self) noexcept(noexcept(std::forward<Self>(self).*member))
+    -> decltype(std::forward<Self>(self).*member) {
+  return (std::forward<Self>(self).*member);
+}
+/// Invokes the given pointer to a scalar member by pointer
+template <typename T, typename Type, typename Self>
+constexpr auto
+invoke(Type T::*member,
+       Self&& self) noexcept(noexcept(std::forward<Self>(self)->*member))
+    -> decltype(std::forward<Self>(self)->*member) {
+  return std::forward<Self>(self)->*member;
+}
+
+/// Deduces to a true type if the callable object can be invoked with
+/// the given arguments.
+/// We don't use invoke here because MSVC can't evaluate the nested expression
+/// SFINAE here.
+template <typename T, typename Args, typename = void>
+struct can_invoke : std::false_type {};
+template <typename T, typename... Args>
+struct can_invoke<T, identity<Args...>,
+                  decltype((void)std::declval<T>()(std::declval<Args>()...))>
+    : std::true_type {};
+template <typename Pointer, typename T, typename... Args>
+struct can_invoke<Pointer, identity<T&, Args...>,
+                  decltype((void)((std::declval<T&>().*std::declval<Pointer>())(
+                      std::declval<Args>()...)))> : std::true_type {};
+template <typename Pointer, typename T, typename... Args>
+struct can_invoke<Pointer, identity<T&&, Args...>,
+                  decltype(
+                      (void)((std::declval<T&&>().*std::declval<Pointer>())(
+                          std::declval<Args>()...)))> : std::true_type {};
+template <typename Pointer, typename T, typename... Args>
+struct can_invoke<Pointer, identity<T*, Args...>,
+                  decltype(
+                      (void)((std::declval<T*>()->*std::declval<Pointer>())(
+                          std::declval<Args>()...)))> : std::true_type {};
+template <typename Pointer, typename T>
+struct can_invoke<Pointer, identity<T&>,
+                  decltype((void)(std::declval<T&>().*std::declval<Pointer>()))>
+    : std::true_type {};
+template <typename Pointer, typename T>
+struct can_invoke<Pointer, identity<T&&>,
+                  decltype((void)(std::declval<T&&>().*
+                                  std::declval<Pointer>()))> : std::true_type {
+};
+template <typename Pointer, typename T>
+struct can_invoke<Pointer, identity<T*>,
+                  decltype(
+                      (void)(std::declval<T*>()->*std::declval<Pointer>()))>
+    : std::true_type {};
+
+template <bool RequiresNoexcept, typename T, typename Args>
+struct is_noexcept_correct : std::true_type {};
+template <typename T, typename... Args>
+struct is_noexcept_correct<true, T, identity<Args...>>
+    : std::integral_constant<bool, noexcept(invoke(std::declval<T>(),
+                                                   std::declval<Args>()...))> {
+};
+} // end namespace invocation
+
+namespace overloading {
+template <typename... Args>
+struct overload_impl;
+template <typename Current, typename Next, typename... Rest>
+struct overload_impl<Current, Next, Rest...> : Current,
+                                               overload_impl<Next, Rest...> {
+  explicit overload_impl(Current current, Next next, Rest... rest)
+      : Current(std::move(current)), overload_impl<Next, Rest...>(
+                                         std::move(next), std::move(rest)...) {
+  }
+
+  using Current::operator();
+  using overload_impl<Next, Rest...>::operator();
+};
+template <typename Current>
+struct overload_impl<Current> : Current {
+  explicit overload_impl(Current current) : Current(std::move(current)) {
+  }
+
+  using Current::operator();
+};
+
+template <typename... T>
+constexpr auto overload(T&&... callables) {
+  return overload_impl<std::decay_t<T>...>{std::forward<T>(callables)...};
+}
+} // namespace overloading
+
+/// Declares the namespace which provides the functionality to work with a
+/// type-erased object.
+namespace type_erasure {
+/// Specialization to work with addresses of callable objects
+template <typename T, typename = void>
+struct address_taker {
+  template <typename O>
+  static void* take(O&& obj) {
+    return std::addressof(obj);
+  }
+  static T& restore(void* ptr) {
+    return *static_cast<T*>(ptr);
+  }
+  static T const& restore(void const* ptr) {
+    return *static_cast<T const*>(ptr);
+  }
+  static T volatile& restore(void volatile* ptr) {
+    return *static_cast<T volatile*>(ptr);
+  }
+  static T const volatile& restore(void const volatile* ptr) {
+    return *static_cast<T const volatile*>(ptr);
+  }
+};
+/// Specialization to work with addresses of raw function pointers
+template <typename T>
+struct address_taker<T, std::enable_if_t<std::is_pointer<T>::value>> {
+  template <typename O>
+  static void* take(O&& obj) {
+    return reinterpret_cast<void*>(obj);
+  }
+  template <typename O>
+  static T restore(O ptr) {
+    return reinterpret_cast<T>(const_cast<void*>(ptr));
+  }
+};
+
+template <typename Box>
+struct box_factory;
+/// Store the allocator inside the box
+template <bool IsCopyable, typename T, typename Allocator>
+struct box : private Allocator {
+  friend box_factory<box>;
+
+  T value_;
+
+  explicit box(T value, Allocator allocator)
+      : Allocator(std::move(allocator)), value_(std::move(value)) {
+  }
+
+  box(box&&) = default;
+  box(box const&) = default;
+  box& operator=(box&&) = default;
+  box& operator=(box const&) = default;
+  ~box() = default;
+};
+template <typename T, typename Allocator>
+struct box<false, T, Allocator> : private Allocator {
+  friend box_factory<box>;
+
+  T value_;
+
+  explicit box(T value, Allocator allocator)
+      : Allocator(std::move(allocator)), value_(std::move(value)) {
+  }
+
+  box(box&&) = default;
+  box(box const&) = delete;
+  box& operator=(box&&) = default;
+  box& operator=(box const&) = delete;
+  ~box() = default;
+};
+
+template <bool IsCopyable, typename T, typename Allocator>
+struct box_factory<box<IsCopyable, T, Allocator>> {
+  using real_allocator =
+      typename std::allocator_traits<std::decay_t<Allocator>>::
+          template rebind_alloc<box<IsCopyable, T, Allocator>>;
+
+  /// Allocates space through the boxed allocator
+  static box<IsCopyable, T, Allocator>*
+  box_allocate(box<IsCopyable, T, Allocator> const* me) {
+    real_allocator allocator(*static_cast<Allocator const*>(me));
+
+    return static_cast<box<IsCopyable, T, Allocator>*>(
+        std::allocator_traits<real_allocator>::allocate(allocator, 1U));
+  }
+
+  /// Destroys the box through the given allocator
+  static void box_deallocate(box<IsCopyable, T, Allocator>* me) {
+    real_allocator allocator(*static_cast<Allocator const*>(me));
+
+    me->~box();
+    std::allocator_traits<real_allocator>::deallocate(allocator, me, 1U);
+  }
+};
+
+/// Creates a box containing the given value and allocator
+template <bool IsCopyable, typename T,
+          typename Allocator = std::allocator<std::decay_t<T>>>
+auto make_box(std::integral_constant<bool, IsCopyable>, T&& value,
+              Allocator&& allocator = Allocator{}) {
+  return box<IsCopyable, std::decay_t<T>, std::decay_t<Allocator>>{
+      std::forward<T>(value), std::forward<Allocator>(allocator)};
+}
+
+template <typename T>
+struct is_box : std::false_type {};
+template <bool IsCopyable, typename T, typename Allocator>
+struct is_box<box<IsCopyable, T, Allocator>> : std::true_type {};
+
+/// Provides access to the pointer to a heal allocated erased object
+/// as well to the inplace storage.
+union data_accessor {
+  data_accessor() = default;
+  explicit constexpr data_accessor(std::nullptr_t) noexcept : ptr_(nullptr) {
+  }
+  explicit constexpr data_accessor(void* ptr) noexcept : ptr_(ptr) {
+  }
+
+  /// The pointer we use if the object is on the heap
+  void* ptr_;
+  /// The first field of the inplace storage
+  std::size_t inplace_storage_;
+};
+
+/// See opcode::op_fetch_empty
+constexpr void write_empty(data_accessor* accessor, bool empty) noexcept {
+  accessor->inplace_storage_ = std::size_t(empty);
+}
+
+template <typename From, typename To>
+using transfer_const_t =
+    std::conditional_t<std::is_const<std::remove_pointer_t<From>>::value,
+                       std::add_const_t<To>, To>;
+template <typename From, typename To>
+using transfer_volatile_t =
+    std::conditional_t<std::is_volatile<std::remove_pointer_t<From>>::value,
+                       std::add_volatile_t<To>, To>;
+
+/// The retriever when the object is allocated inplace
+template <typename T, typename Accessor>
+constexpr auto retrieve(std::true_type /*is_inplace*/, Accessor from,
+                        std::size_t from_capacity) {
+  using type = transfer_const_t<Accessor, transfer_volatile_t<Accessor, void>>*;
+
+  /// Process the command by using the data inside the internal capacity
+  auto storage = &(from->inplace_storage_);
+  auto inplace = const_cast<void*>(static_cast<type>(storage));
+  return type(std::align(alignof(T), sizeof(T), inplace, from_capacity));
+}
+
+/// The retriever which is used when the object is allocated
+/// through the allocator
+template <typename T, typename Accessor>
+constexpr auto retrieve(std::false_type /*is_inplace*/, Accessor from,
+                        std::size_t /*from_capacity*/) {
+
+  return from->ptr_;
+}
+
+namespace invocation_table {
+#if !defined(FU2_HAS_DISABLED_EXCEPTIONS)
+#if defined(FU2_HAS_NO_FUNCTIONAL_HEADER)
+struct bad_function_call : std::exception {
+  bad_function_call() noexcept {
+  }
+
+  char const* what() const noexcept override {
+    return "bad function call";
+  }
+};
+#elif
+using std::bad_function_call;
+#endif
+#endif
+
+#ifdef FU2_HAS_CXX17_NOEXCEPT_FUNCTION_TYPE
+#define FU2_EXPAND_QUALIFIERS_NOEXCEPT(F)                                      \
+  F(, , noexcept, , &)                                                         \
+  F(const, , noexcept, , &)                                                    \
+  F(, volatile, noexcept, , &)                                                 \
+  F(const, volatile, noexcept, , &)                                            \
+  F(, , noexcept, &, &)                                                        \
+  F(const, , noexcept, &, &)                                                   \
+  F(, volatile, noexcept, &, &)                                                \
+  F(const, volatile, noexcept, &, &)                                           \
+  F(, , noexcept, &&, &&)                                                      \
+  F(const, , noexcept, &&, &&)                                                 \
+  F(, volatile, noexcept, &&, &&)                                              \
+  F(const, volatile, noexcept, &&, &&)
+#else // FU2_HAS_CXX17_NOEXCEPT_FUNCTION_TYPE
+#define FU2_EXPAND_QUALIFIERS_NOEXCEPT(F)
+#endif // FU2_HAS_CXX17_NOEXCEPT_FUNCTION_TYPE
+
+#define FU2_EXPAND_QUALIFIERS(F)                                               \
+  F(, , , , &)                                                                 \
+  F(const, , , , &)                                                            \
+  F(, volatile, , , &)                                                         \
+  F(const, volatile, , , &)                                                    \
+  F(, , , &, &)                                                                \
+  F(const, , , &, &)                                                           \
+  F(, volatile, , &, &)                                                        \
+  F(const, volatile, , &, &)                                                   \
+  F(, , , &&, &&)                                                              \
+  F(const, , , &&, &&)                                                         \
+  F(, volatile, , &&, &&)                                                      \
+  F(const, volatile, , &&, &&)                                                 \
+  FU2_EXPAND_QUALIFIERS_NOEXCEPT(F)
+
+/// If the function is qualified as noexcept, the call will never throw
+template <bool IsNoexcept>
+[[noreturn]] void throw_or_abortnoexcept(
+    std::integral_constant<bool, IsNoexcept> /*is_throwing*/) noexcept {
+  std::abort();
+}
+/// Calls std::abort on empty function calls
+[[noreturn]] inline void
+throw_or_abort(std::false_type /*is_throwing*/) noexcept {
+  std::abort();
+}
+/// Throws bad_function_call on empty funciton calls
+[[noreturn]] inline void throw_or_abort(std::true_type /*is_throwing*/) {
+#ifdef FU2_HAS_DISABLED_EXCEPTIONS
+  throw_or_abort(std::false_type{});
+#else
+  throw bad_function_call{};
+#endif
+}
+
+template <typename T>
+struct function_trait;
+
+using is_noexcept_ = std::false_type;
+using is_noexcept_noexcept = std::true_type;
+
+#define FU2_DEFINE_FUNCTION_TRAIT(CONST, VOLATILE, NOEXCEPT, OVL_REF, REF)     \
+  template <typename Ret, typename... Args>                                    \
+  struct function_trait<Ret(Args...) CONST VOLATILE OVL_REF NOEXCEPT> {        \
+    using pointer_type = Ret (*)(data_accessor CONST VOLATILE*,                \
+                                 std::size_t capacity, Args...);               \
+    template <typename T, bool IsInplace>                                      \
+    struct internal_invoker {                                                  \
+      static Ret invoke(data_accessor CONST VOLATILE* data,                    \
+                        std::size_t capacity, Args... args) NOEXCEPT {         \
+        auto obj = retrieve<T>(std::integral_constant<bool, IsInplace>{},      \
+                               data, capacity);                                \
+        auto box = static_cast<T CONST VOLATILE*>(obj);                        \
+        return invocation::invoke(                                             \
+            static_cast<std::decay_t<decltype(box->value_)> CONST VOLATILE     \
+                            REF>(box->value_),                                 \
+            std::forward<Args>(args)...);                                      \
+      }                                                                        \
+    };                                                                         \
+                                                                               \
+    template <typename T>                                                      \
+    struct view_invoker {                                                      \
+      static Ret invoke(data_accessor CONST VOLATILE* data, std::size_t,       \
+                        Args... args) NOEXCEPT {                               \
+                                                                               \
+        auto ptr = static_cast<void CONST VOLATILE*>(data->ptr_);              \
+        return invocation::invoke(address_taker<T>::restore(ptr),              \
+                                  std::forward<Args>(args)...);                \
+      }                                                                        \
+    };                                                                         \
+                                                                               \
+    template <typename T>                                                      \
+    using callable = T CONST VOLATILE REF;                                     \
+                                                                               \
+    using arguments = identity<Args...>;                                       \
+                                                                               \
+    using is_noexcept = is_noexcept_##NOEXCEPT;                                \
+                                                                               \
+    template <bool Throws>                                                     \
+    struct empty_invoker {                                                     \
+      static Ret invoke(data_accessor CONST VOLATILE* /*data*/,                \
+                        std::size_t /*capacity*/, Args... /*args*/) NOEXCEPT { \
+        throw_or_abort##NOEXCEPT(std::integral_constant<bool, Throws>{});      \
+      }                                                                        \
+    };                                                                         \
+  };
+
+FU2_EXPAND_QUALIFIERS(FU2_DEFINE_FUNCTION_TRAIT)
+#undef FU2_DEFINE_FUNCTION_TRAIT
+
+/// Deduces to the function pointer to the given signature
+template <typename Signature>
+using function_pointer_of = typename function_trait<Signature>::pointer_type;
+
+template <typename... Args>
+struct invoke_table;
+
+/// We optimize the vtable_t in case there is a single function overload
+template <typename First>
+struct invoke_table<First> {
+  using type = function_pointer_of<First>;
+
+  /// Return the function pointer itself
+  template <std::size_t Index>
+  static constexpr auto fetch(type pointer) noexcept {
+    static_assert(Index == 0U, "The index should be 0 here!");
+    return pointer;
+  }
+
+  /// Returns the thunk of an single overloaded callable
+  template <typename T, bool IsInplace>
+  static constexpr type get_invocation_table_of() noexcept {
+    return &function_trait<First>::template internal_invoker<T,
+                                                             IsInplace>::invoke;
+  }
+  /// Returns the thunk of an single overloaded callable
+  template <typename T>
+  static constexpr type get_invocation_view_table_of() noexcept {
+    return &function_trait<First>::template view_invoker<T>::invoke;
+  }
+  /// Returns the thunk of an empty single overloaded callable
+  template <bool IsThrowing>
+  static constexpr type get_empty_invocation_table() noexcept {
+    return &function_trait<First>::template empty_invoker<IsThrowing>::invoke;
+  }
+};
+/// We generate a table in case of multiple function overloads
+template <typename First, typename Second, typename... Args>
+struct invoke_table<First, Second, Args...> {
+  using type =
+      std::tuple<function_pointer_of<First>, function_pointer_of<Second>,
+                 function_pointer_of<Args>...> const*;
+
+  /// Return the function pointer at the particular index
+  template <std::size_t Index>
+  static constexpr auto fetch(type table) noexcept {
+    return std::get<Index>(*table);
+  }
+
+  /// The invocation vtable for a present object
+  template <typename T, bool IsInplace>
+  struct invocation_vtable : public std::tuple<function_pointer_of<First>,
+                                               function_pointer_of<Second>,
+                                               function_pointer_of<Args>...> {
+    constexpr invocation_vtable() noexcept
+        : std::tuple<function_pointer_of<First>, function_pointer_of<Second>,
+                     function_pointer_of<Args>...>(std::make_tuple(
+              &function_trait<First>::template internal_invoker<
+                  T, IsInplace>::invoke,
+              &function_trait<Second>::template internal_invoker<
+                  T, IsInplace>::invoke,
+              &function_trait<Args>::template internal_invoker<
+                  T, IsInplace>::invoke...)) {
+    }
+  };
+
+  /// Returns the thunk of an multi overloaded callable
+  template <typename T, bool IsInplace>
+  static type get_invocation_table_of() noexcept {
+    static invocation_vtable<T, IsInplace> const table;
+    return &table;
+  }
+
+  /// The invocation vtable for a present object
+  template <typename T>
+  struct invocation_view_vtable
+      : public std::tuple<function_pointer_of<First>,
+                          function_pointer_of<Second>,
+                          function_pointer_of<Args>...> {
+    constexpr invocation_view_vtable() noexcept
+        : std::tuple<function_pointer_of<First>, function_pointer_of<Second>,
+                     function_pointer_of<Args>...>(std::make_tuple(
+              &function_trait<First>::template view_invoker<T>::invoke,
+              &function_trait<Second>::template view_invoker<T>::invoke,
+              &function_trait<Args>::template view_invoker<T>::invoke...)) {
+    }
+  };
+
+  /// Returns the thunk of an multi overloaded callable
+  template <typename T>
+  static type get_invocation_view_table_of() noexcept {
+    static invocation_view_vtable<T> const table;
+    return &table;
+  }
+
+  /// The invocation table for an empty wrapper
+  template <bool IsThrowing>
+  struct empty_vtable : public std::tuple<function_pointer_of<First>,
+                                          function_pointer_of<Second>,
+                                          function_pointer_of<Args>...> {
+    constexpr empty_vtable() noexcept
+        : std::tuple<function_pointer_of<First>, function_pointer_of<Second>,
+                     function_pointer_of<Args>...>(
+              std::make_tuple(&function_trait<First>::template empty_invoker<
+                                  IsThrowing>::invoke,
+                              &function_trait<Second>::template empty_invoker<
+                                  IsThrowing>::invoke,
+                              &function_trait<Args>::template empty_invoker<
+                                  IsThrowing>::invoke...)) {
+    }
+  };
+
+  /// Returns the thunk of an multi single overloaded callable
+  template <bool IsThrowing>
+  static type get_empty_invocation_table() noexcept {
+    static empty_vtable<IsThrowing> const table;
+    return &table;
+  }
+};
+
+template <std::size_t Index, typename Function, typename... Signatures>
+class operator_impl;
+
+#define FU2_DEFINE_FUNCTION_TRAIT(CONST, VOLATILE, NOEXCEPT, OVL_REF, REF)     \
+  template <std::size_t Index, typename Function, typename Ret,                \
+            typename... Args, typename Next, typename... Signatures>           \
+  class operator_impl<Index, Function,                                         \
+                      Ret(Args...) CONST VOLATILE OVL_REF NOEXCEPT, Next,      \
+                      Signatures...>                                           \
+      : operator_impl<Index + 1, Function, Next, Signatures...> {              \
+                                                                               \
+    template <std::size_t, typename, typename...>                              \
+    friend class operator_impl;                                                \
+                                                                               \
+  protected:                                                                   \
+    operator_impl() = default;                                                 \
+    ~operator_impl() = default;                                                \
+    operator_impl(operator_impl const&) = default;                             \
+    operator_impl(operator_impl&&) = default;                                  \
+    operator_impl& operator=(operator_impl const&) = default;                  \
+    operator_impl& operator=(operator_impl&&) = default;                       \
+                                                                               \
+    using operator_impl<Index + 1, Function, Next, Signatures...>::operator(); \
+                                                                               \
+    Ret operator()(Args... args) CONST VOLATILE OVL_REF NOEXCEPT {             \
+      auto parent = static_cast<Function CONST VOLATILE*>(this);               \
+      using erasure_t = std::decay_t<decltype(parent->erasure_)>;              \
+                                                                               \
+      return erasure_t::template invoke<Index>(                                \
+          static_cast<erasure_t CONST VOLATILE REF>(parent->erasure_),         \
+          std::forward<Args>(args)...);                                        \
+    }                                                                          \
+  };                                                                           \
+  template <std::size_t Index, typename Config, typename Property,             \
+            typename Ret, typename... Args>                                    \
+  class operator_impl<Index, function<Config, Property>,                       \
+                      Ret(Args...) CONST VOLATILE OVL_REF NOEXCEPT>            \
+      : copyable<Config::is_owning || Config::is_copyable> {                   \
+                                                                               \
+    template <std::size_t, typename, typename...>                              \
+    friend class operator_impl;                                                \
+                                                                               \
+  protected:                                                                   \
+    operator_impl() = default;                                                 \
+    ~operator_impl() = default;                                                \
+    operator_impl(operator_impl const&) = default;                             \
+    operator_impl(operator_impl&&) = default;                                  \
+    operator_impl& operator=(operator_impl const&) = default;                  \
+    operator_impl& operator=(operator_impl&&) = default;                       \
+                                                                               \
+    Ret operator()(Args... args) CONST VOLATILE OVL_REF NOEXCEPT {             \
+      auto parent =                                                            \
+          static_cast<function<Config, Property> CONST VOLATILE*>(this);       \
+      using erasure_t = std::decay_t<decltype(parent->erasure_)>;              \
+                                                                               \
+      return erasure_t::template invoke<Index>(                                \
+          static_cast<erasure_t CONST VOLATILE REF>(parent->erasure_),         \
+          std::forward<Args>(args)...);                                        \
+    }                                                                          \
+  };
+
+FU2_EXPAND_QUALIFIERS(FU2_DEFINE_FUNCTION_TRAIT)
+#undef FU2_DEFINE_FUNCTION_TRAIT
+} // namespace invocation_table
+
+namespace tables {
+/// Identifies the action which is dispatched on the erased object
+enum class opcode {
+  op_move,         //< Move the object and set the vtable
+  op_copy,         //< Copy the object and set the vtable
+  op_destroy,      //< Destroy the object and reset the vtable
+  op_weak_destroy, //< Destroy the object without resetting the vtable
+  op_fetch_empty,  //< Stores true or false into the to storage
+                   //< to indicate emptiness
+};
+
+/// Abstraction for a vtable together with a command table
+/// TODO Add optimization for a single formal argument
+/// TODO Add optimization to merge both tables if the function is size
+/// optimized
+template <typename Property>
+class vtable;
+template <bool IsThrowing, bool HasStrongExceptGuarantee,
+          typename... FormalArgs>
+class vtable<property<IsThrowing, HasStrongExceptGuarantee, FormalArgs...>> {
+  using command_function_t = void (*)(vtable* /*this*/, opcode /*op*/,
+                                      data_accessor* /*from*/,
+                                      std::size_t /*from_capacity*/,
+                                      data_accessor* /*to*/,
+                                      std::size_t /*to_capacity*/);
+
+  using invoke_table_t = invocation_table::invoke_table<FormalArgs...>;
+
+  command_function_t cmd_;
+  typename invoke_table_t::type vtable_;
+
+  template <typename T>
+  struct trait {
+    static_assert(is_box<T>::value,
+                  "The trait must be specialized with a box!");
+
+    /// The command table
+    template <bool IsInplace>
+    static void process_cmd(vtable* to_table, opcode op, data_accessor* from,
+                            std::size_t from_capacity, data_accessor* to,
+                            std::size_t to_capacity) {
+
+      switch (op) {
+        case opcode::op_move: {
+          /// Retrieve the pointer to the object
+          auto box = static_cast<T*>(retrieve<T>(
+              std::integral_constant<bool, IsInplace>{}, from, from_capacity));
+          assert(box && "The object must not be over aligned or null!");
+
+          if (!IsInplace) {
+            // Just swap both pointers if we allocated on the heap
+            to->ptr_ = from->ptr_;
+
+#ifndef _NDEBUG
+            // We don't need to null the pointer since we know that
+            // we don't own the data anymore through the vtable
+            // which is set to empty.
+            from->ptr_ = nullptr;
+#endif
+
+            to_table->template set_allocated<T>();
+
+          }
+          // The object is allocated inplace
+          else {
+            construct(std::true_type{}, std::move(*box), to_table, to,
+                      to_capacity);
+            box->~T();
+          }
+          return;
+        }
+        case opcode::op_copy: {
+          auto box = static_cast<T const*>(retrieve<T>(
+              std::integral_constant<bool, IsInplace>{}, from, from_capacity));
+          assert(box && "The object must not be over aligned or null!");
+
+          assert(std::is_copy_constructible<T>::value &&
+                 "The box is required to be copyable here!");
+
+          // Try to allocate the object inplace
+          construct(std::is_copy_constructible<T>{}, *box, to_table, to,
+                    to_capacity);
+          return;
+        }
+        case opcode::op_destroy:
+        case opcode::op_weak_destroy: {
+
+          assert(!to && !to_capacity && "Arg overflow!");
+          auto box = static_cast<T*>(retrieve<T>(
+              std::integral_constant<bool, IsInplace>{}, from, from_capacity));
+
+          if (IsInplace) {
+            box->~T();
+          } else {
+            box_factory<T>::box_deallocate(box);
+          }
+
+          if (op == opcode::op_destroy) {
+            to_table->set_empty();
+          }
+          return;
+        }
+        case opcode::op_fetch_empty: {
+          write_empty(to, false);
+          return;
+        }
+      }
+
+      // TODO Use an unreachable intrinsic
+      assert(false && "Unreachable!");
+      std::exit(-1);
+    }
+
+    template <typename Box>
+    static void
+    construct(std::true_type /*apply*/, Box&& box, vtable* to_table,
+              data_accessor* to,
+              std::size_t to_capacity) noexcept(HasStrongExceptGuarantee) {
+      // Try to allocate the object inplace
+      void* storage = retrieve<T>(std::true_type{}, to, to_capacity);
+      if (storage) {
+        to_table->template set_inplace<T>();
+      } else {
+        // Allocate the object through the allocator
+        to->ptr_ = storage =
+            box_factory<std::decay_t<Box>>::box_allocate(std::addressof(box));
+        to_table->template set_allocated<T>();
+      }
+      new (storage) T(std::forward<Box>(box));
+    }
+
+    template <typename Box>
+    static void
+    construct(std::false_type /*apply*/, Box&& /*box*/, vtable* /*to_table*/,
+              data_accessor* /*to*/,
+              std::size_t /*to_capacity*/) noexcept(HasStrongExceptGuarantee) {
+    }
+  };
+
+  /// The command table
+  static void empty_cmd(vtable* to_table, opcode op, data_accessor* /*from*/,
+                        std::size_t /*from_capacity*/, data_accessor* to,
+                        std::size_t /*to_capacity*/) {
+
+    switch (op) {
+      case opcode::op_move:
+      case opcode::op_copy: {
+        to_table->set_empty();
+        break;
+      }
+      case opcode::op_destroy:
+      case opcode::op_weak_destroy: {
+        // Do nothing
+        break;
+      }
+      case opcode::op_fetch_empty: {
+        write_empty(to, true);
+        break;
+      }
+    }
+  }
+
+public:
+  vtable() noexcept = default;
+
+  /// Initialize an object at the given position
+  template <typename T>
+  static void init(vtable& table, T&& object, data_accessor* to,
+                   std::size_t to_capacity) {
+
+    trait<std::decay_t<T>>::construct(std::true_type{}, std::forward<T>(object),
+                                      &table, to, to_capacity);
+  }
+
+  /// Moves the object at the given position
+  void move(vtable& to_table, data_accessor* from, std::size_t from_capacity,
+            data_accessor* to,
+            std::size_t to_capacity) noexcept(HasStrongExceptGuarantee) {
+    cmd_(&to_table, opcode::op_move, from, from_capacity, to, to_capacity);
+    set_empty();
+  }
+
+  /// Destroys the object at the given position
+  void copy(vtable& to_table, data_accessor const* from,
+            std::size_t from_capacity, data_accessor* to,
+            std::size_t to_capacity) const {
+    cmd_(&to_table, opcode::op_copy, const_cast<data_accessor*>(from),
+         from_capacity, to, to_capacity);
+  }
+
+  /// Destroys the object at the given position
+  void destroy(data_accessor* from,
+               std::size_t from_capacity) noexcept(HasStrongExceptGuarantee) {
+    cmd_(this, opcode::op_destroy, from, from_capacity, nullptr, 0U);
+  }
+
+  /// Destroys the object at the given position without invalidating the
+  /// vtable
+  void
+  weak_destroy(data_accessor* from,
+               std::size_t from_capacity) noexcept(HasStrongExceptGuarantee) {
+    cmd_(this, opcode::op_weak_destroy, from, from_capacity, nullptr, 0U);
+  }
+
+  /// Returns true when the vtable doesn't hold any erased object
+  bool empty() const noexcept {
+    data_accessor data;
+    cmd_(nullptr, opcode::op_fetch_empty, nullptr, 0U, &data, 0U);
+    return bool(data.inplace_storage_);
+  }
+
+  /// Invoke the function at the given index
+  template <std::size_t Index, typename... Args>
+  constexpr auto invoke(Args&&... args) const {
+    auto thunk = invoke_table_t::template fetch<Index>(vtable_);
+    return thunk(std::forward<Args>(args)...);
+  }
+  /// Invoke the function at the given index
+  template <std::size_t Index, typename... Args>
+  constexpr auto invoke(Args&&... args) const volatile {
+    auto thunk = invoke_table_t::template fetch<Index>(vtable_);
+    return thunk(std::forward<Args>(args)...);
+  }
+
+  template <typename T>
+  void set_inplace() noexcept {
+    using type = std::decay_t<T>;
+    vtable_ = invoke_table_t::template get_invocation_table_of<type, true>();
+    cmd_ = &trait<type>::template process_cmd<true>;
+  }
+
+  template <typename T>
+  void set_allocated() noexcept {
+    using type = std::decay_t<T>;
+    vtable_ = invoke_table_t::template get_invocation_table_of<type, false>();
+    cmd_ = &trait<type>::template process_cmd<false>;
+  }
+
+  void set_empty() noexcept {
+    vtable_ = invoke_table_t::template get_empty_invocation_table<IsThrowing>();
+    cmd_ = &empty_cmd;
+  }
+};
+} // namespace tables
+
+/// A union which makes the pointer to the heap object share the
+/// same space with the internal capacity.
+/// The storage type is distinguished by multiple versions of the
+/// control and vtable.
+template <std::size_t Capacity, typename = void>
+struct internal_capacity {
+  /// We extend the union through a technique similar to the tail object hack
+  typedef union {
+    /// Tag to access the structure in a type-safe way
+    data_accessor accessor_;
+    /// The internal capacity we use to allocate in-place
+    std::aligned_storage_t<Capacity> capacity_;
+  } type;
+};
+template <std::size_t Capacity>
+struct internal_capacity<Capacity,
+                         std::enable_if_t<(Capacity < sizeof(void*))>> {
+  typedef struct {
+    /// Tag to access the structure in a type-safe way
+    data_accessor accessor_;
+  } type;
+};
+
+template <std::size_t Capacity>
+class internal_capacity_holder {
+  // Tag to access the structure in a type-safe way
+  typename internal_capacity<Capacity>::type storage_;
+
+public:
+  constexpr internal_capacity_holder() = default;
+
+  constexpr data_accessor* opaque_ptr() noexcept {
+    return &storage_.accessor_;
+  }
+  constexpr data_accessor const* opaque_ptr() const noexcept {
+    return &storage_.accessor_;
+  }
+  constexpr data_accessor volatile* opaque_ptr() volatile noexcept {
+    return &storage_.accessor_;
+  }
+  constexpr data_accessor const volatile* opaque_ptr() const volatile noexcept {
+    return &storage_.accessor_;
+  }
+
+  static constexpr std::size_t capacity() noexcept {
+    return sizeof(storage_);
+  }
+};
+
+/// An owning erasure
+template <bool IsOwning /* = true*/, typename Config, typename Property>
+class erasure : internal_capacity_holder<Config::capacity> {
+  template <bool, typename, typename>
+  friend class erasure;
+  template <std::size_t, typename, typename...>
+  friend class operator_impl;
+
+  using vtable_t = tables::vtable<Property>;
+
+  vtable_t vtable_;
+
+public:
+  /// Returns the capacity of this erasure
+  static constexpr std::size_t capacity() noexcept {
+    return internal_capacity_holder<Config::capacity>::capacity();
+  }
+
+  constexpr erasure() noexcept {
+    vtable_.set_empty();
+  }
+
+  constexpr erasure(std::nullptr_t) noexcept {
+    vtable_.set_empty();
+  }
+
+  constexpr erasure(erasure&& right) noexcept(
+      Property::is_strong_exception_guaranteed) {
+    right.vtable_.move(vtable_, right.opaque_ptr(), right.capacity(),
+                       this->opaque_ptr(), capacity());
+  }
+
+  constexpr erasure(erasure const& right) {
+    right.vtable_.copy(vtable_, right.opaque_ptr(), right.capacity(),
+                       this->opaque_ptr(), capacity());
+  }
+
+  template <typename OtherConfig>
+  constexpr erasure(erasure<true, OtherConfig, Property> right) noexcept(
+      Property::is_strong_exception_guaranteed) {
+    right.vtable_.move(vtable_, right.opaque_ptr(), right.capacity(),
+                       this->opaque_ptr(), capacity());
+  }
+
+  template <typename T, typename Allocator = std::allocator<std::decay_t<T>>>
+  constexpr erasure(T&& callable, Allocator&& allocator = Allocator{}) {
+    vtable_t::init(vtable_,
+                   type_erasure::make_box(
+                       std::integral_constant<bool, Config::is_copyable>{},
+                       std::forward<T>(callable),
+                       std::forward<Allocator>(allocator)),
+                   this->opaque_ptr(), capacity());
+  }
+
+  ~erasure() {
+    vtable_.weak_destroy(this->opaque_ptr(), capacity());
+  }
+
+  constexpr erasure&
+  operator=(std::nullptr_t) noexcept(Property::is_strong_exception_guaranteed) {
+    vtable_.destroy(this->opaque_ptr(), capacity());
+    return *this;
+  }
+
+  constexpr erasure& operator=(erasure&& right) noexcept(
+      Property::is_strong_exception_guaranteed) {
+    vtable_.weak_destroy(this->opaque_ptr(), capacity());
+    right.vtable_.move(vtable_, right.opaque_ptr(), right.capacity(),
+                       this->opaque_ptr(), capacity());
+    return *this;
+  }
+
+  constexpr erasure& operator=(erasure const& right) {
+    vtable_.weak_destroy(this->opaque_ptr(), capacity());
+    right.vtable_.copy(vtable_, right.opaque_ptr(), right.capacity(),
+                       this->opaque_ptr(), capacity());
+    return *this;
+  }
+
+  template <typename OtherConfig>
+  constexpr erasure&
+  operator=(erasure<true, OtherConfig, Property> right) noexcept(
+      Property::is_strong_exception_guaranteed) {
+    vtable_.weak_destroy(this->opaque_ptr(), capacity());
+    right.vtable_.move(vtable_, right.opaque_ptr(), right.capacity(),
+                       this->opaque_ptr(), capacity());
+    return *this;
+  }
+
+  template <typename T>
+  constexpr erasure& operator=(T&& callable) {
+    vtable_.weak_destroy(this->opaque_ptr(), capacity());
+    vtable_t::init(vtable_,
+                   type_erasure::make_box(
+                       std::integral_constant<bool, Config::is_copyable>{},
+                       std::forward<T>(callable)),
+                   this->opaque_ptr(), capacity());
+    return *this;
+  }
+
+  template <typename T, typename Allocator>
+  void assign(T&& callable, Allocator&& allocator) {
+    vtable_.weak_destroy(this->opaque_ptr(), capacity());
+    vtable_t::init(vtable_,
+                   type_erasure::make_box(
+                       std::integral_constant<bool, Config::is_copyable>{},
+                       std::forward<T>(callable),
+                       std::forward<Allocator>(allocator)),
+                   this->opaque_ptr(), capacity());
+  }
+
+  /// Returns true when the erasure doesn't hold any erased object
+  constexpr bool empty() const noexcept {
+    return vtable_.empty();
+  }
+
+  /// Invoke the function of the erasure at the given index
+  ///
+  /// We define this out of class to be able to forward the qualified
+  /// erasure correctly.
+  template <std::size_t Index, typename Erasure, typename... Args>
+  static constexpr auto invoke(Erasure&& erasure, Args&&... args) {
+    auto const capacity = erasure.capacity();
+    return erasure.vtable_.template invoke<Index>(
+        std::forward<Erasure>(erasure).opaque_ptr(), capacity,
+        std::forward<Args>(args)...);
+  }
+};
+
+// A non owning erasure
+template </*bool IsOwning = false, */ typename Config, bool IsThrowing,
+          bool HasStrongExceptGuarantee, typename... Args>
+class erasure<false, Config,
+              property<IsThrowing, HasStrongExceptGuarantee, Args...>> {
+  template <bool, typename, typename>
+  friend class erasure;
+  template <std::size_t, typename, typename...>
+  friend class operator_impl;
+
+  using property_t = property<IsThrowing, HasStrongExceptGuarantee, Args...>;
+
+  using invoke_table_t = invocation_table::invoke_table<Args...>;
+  typename invoke_table_t::type invoke_table_;
+
+  /// The internal pointer to the non owned object
+  data_accessor view_;
+
+public:
+  // NOLINTNEXTLINE(cppcoreguidlines-pro-type-member-init)
+  constexpr erasure() noexcept
+      : invoke_table_(
+            invoke_table_t::template get_empty_invocation_table<IsThrowing>()),
+        view_(nullptr) {
+  }
+
+  // NOLINTNEXTLINE(cppcoreguidlines-pro-type-member-init)
+  constexpr erasure(std::nullptr_t) noexcept
+      : invoke_table_(
+            invoke_table_t::template get_empty_invocation_table<IsThrowing>()),
+        view_(nullptr) {
+  }
+
+  // NOLINTNEXTLINE(cppcoreguidlines-pro-type-member-init)
+  constexpr erasure(erasure&& right) noexcept
+      : invoke_table_(right.invoke_table_), view_(right.view_) {
+  }
+
+  constexpr erasure(erasure const& /*right*/) = default;
+
+  template <typename OtherConfig>
+  // NOLINTNEXTLINE(cppcoreguidlines-pro-type-member-init)
+  constexpr erasure(erasure<false, OtherConfig, property_t> right) noexcept
+      : invoke_table_(right.invoke_table_), view_(right.view_) {
+  }
+
+  template <typename T>
+  // NOLINTNEXTLINE(cppcoreguidlines-pro-type-member-init)
+  constexpr erasure(T&& object)
+      : invoke_table_(invoke_table_t::template get_invocation_view_table_of<
+                      std::decay_t<T>>()),
+        view_(address_taker<std::decay_t<T>>::take(std::forward<T>(object))) {
+  }
+
+  ~erasure() = default;
+
+  constexpr erasure&
+  operator=(std::nullptr_t) noexcept(HasStrongExceptGuarantee) {
+    invoke_table_ =
+        invoke_table_t::template get_empty_invocation_table<IsThrowing>();
+    view_.ptr_ = nullptr;
+    return *this;
+  }
+
+  constexpr erasure& operator=(erasure&& right) noexcept {
+    invoke_table_ = right.invoke_table_;
+    view_ = right.view_;
+    right = nullptr;
+    return *this;
+  }
+
+  constexpr erasure& operator=(erasure const& /*right*/) = default;
+
+  template <typename OtherConfig>
+  constexpr erasure&
+  operator=(erasure<true, OtherConfig, property_t> right) noexcept {
+    invoke_table_ = right.invoke_table_;
+    view_ = right.view_;
+    return *this;
+  }
+
+  template <typename T>
+  constexpr erasure& operator=(T&& object) {
+    invoke_table_ = invoke_table_t::template get_invocation_view_table_of<
+        std::decay_t<T>>();
+    view_.ptr_ = address_taker<std::decay_t<T>>::take(std::forward<T>(object));
+    return *this;
+  }
+
+  /// Returns true when the erasure doesn't hold any erased object
+  constexpr bool empty() const noexcept {
+    return view_.ptr_ == nullptr;
+  }
+
+  template <std::size_t Index, typename Erasure, typename... T>
+  static constexpr auto invoke(Erasure&& erasure, T&&... args) {
+    auto thunk = invoke_table_t::template fetch<Index>(erasure.invoke_table_);
+    return thunk(&(erasure.view_), 0UL, std::forward<T>(args)...);
+  }
+};
+} // namespace type_erasure
+
+/// Deduces to a true_type if the type T provides the given signature and the
+/// signature is noexcept correct callable.
+template <typename T, typename Signature,
+          typename Trait =
+              type_erasure::invocation_table::function_trait<Signature>>
+struct accepts_one
+    : std::integral_constant<
+          bool, invocation::can_invoke<typename Trait::template callable<T>,
+                                       typename Trait::arguments>::value &&
+                    invocation::is_noexcept_correct<
+                        Trait::is_noexcept::value,
+                        typename Trait::template callable<T>,
+                        typename Trait::arguments>::value> {};
+
+/// Deduces to a true_type if the type T provides all signatures
+template <typename T, typename Signatures, typename = void>
+struct accepts_all : std::false_type {};
+template <typename T, typename... Signatures>
+struct accepts_all<
+    T, identity<Signatures...>,
+    void_t<std::enable_if_t<accepts_one<T, Signatures>::value>...>>
+    : std::true_type {};
+
+template <typename Config, typename T>
+struct assert_wrong_copy_assign {
+  static_assert(!Config::is_copyable ||
+                    std::is_copy_constructible<std::decay_t<T>>::value,
+                "Can't wrap a non copyable object into a unique function!");
+
+  using type = void;
+};
+
+template <bool IsStrongExceptGuaranteed, typename T>
+struct assert_no_strong_except_guarantee {
+  static_assert(
+      !IsStrongExceptGuaranteed ||
+          (std::is_nothrow_move_constructible<T>::value &&
+           std::is_nothrow_destructible<T>::value),
+      "Can't wrap a object an object that has no strong exception guarantees "
+      "if this is required by the wrapper!");
+
+  using type = void;
+};
+
+/// SFINAES out if the given callable is not copyable correct to the left one.
+template <typename LeftConfig, typename RightConfig>
+using enable_if_copyable_correct_t =
+    std::enable_if_t<(!LeftConfig::is_copyable || RightConfig::is_copyable)>;
+
+template <typename LeftConfig, typename RightConfig>
+using is_owning_correct =
+    std::integral_constant<bool,
+                           (LeftConfig::is_owning == RightConfig::is_owning)>;
+
+/// SFINAES out if the given function2 is not owning correct to this one
+template <typename LeftConfig, typename RightConfig>
+using enable_if_owning_correct_t =
+    std::enable_if_t<is_owning_correct<LeftConfig, RightConfig>::value>;
+
+template <typename Config, bool IsThrowing, bool HasStrongExceptGuarantee,
+          typename... Args>
+class function<Config, property<IsThrowing, HasStrongExceptGuarantee, Args...>>
+    : type_erasure::invocation_table::operator_impl<
+          0U,
+          function<Config,
+                   property<IsThrowing, HasStrongExceptGuarantee, Args...>>,
+          Args...> {
+
+  template <typename, typename>
+  friend class function;
+
+  template <std::size_t, typename, typename...>
+  friend class type_erasure::invocation_table::operator_impl;
+
+  using property_t = property<IsThrowing, HasStrongExceptGuarantee, Args...>;
+  using erasure_t =
+      type_erasure::erasure<Config::is_owning, Config, property_t>;
+
+  template <typename T>
+  using enable_if_can_accept_all_t =
+      std::enable_if_t<accepts_all<std::decay_t<T>, identity<Args...>>::value>;
+
+  template <typename Function, typename = void>
+  struct is_convertible_to_this : std::false_type {};
+  template <typename RightConfig>
+  struct is_convertible_to_this<
+      function<RightConfig, property_t>,
+      void_t<enable_if_copyable_correct_t<Config, RightConfig>,
+             enable_if_owning_correct_t<Config, RightConfig>>>
+      : std::true_type {};
+
+  template <typename T>
+  using enable_if_not_convertible_to_this =
+      std::enable_if_t<!is_convertible_to_this<std::decay_t<T>>::value>;
+
+  template <typename T>
+  using enable_if_owning_t =
+      std::enable_if_t<std::is_same<T, T>::value && Config::is_owning>;
+
+  template <typename T>
+  using assert_wrong_copy_assign_t =
+      typename assert_wrong_copy_assign<Config, std::decay_t<T>>::type;
+
+  template <typename T>
+  using assert_no_strong_except_guarantee_t =
+      typename assert_no_strong_except_guarantee<HasStrongExceptGuarantee,
+                                                 std::decay_t<T>>::type;
+
+  erasure_t erasure_;
+
+public:
+  /// Default constructor which empty constructs the function
+  function() = default;
+  ~function() = default;
+
+  explicit constexpr function(function const& /*right*/) = default;
+  explicit constexpr function(function&& /*right*/) = default;
+
+  /// Copy construction from another copyable function
+  template <typename RightConfig,
+            std::enable_if_t<RightConfig::is_copyable>* = nullptr,
+            enable_if_copyable_correct_t<Config, RightConfig>* = nullptr,
+            enable_if_owning_correct_t<Config, RightConfig>* = nullptr>
+  constexpr function(function<RightConfig, property_t> const& right)
+      : erasure_(right.erasure_) {
+  }
+
+  /// Move construction from another function
+  template <typename RightConfig,
+            enable_if_copyable_correct_t<Config, RightConfig>* = nullptr,
+            enable_if_owning_correct_t<Config, RightConfig>* = nullptr>
+  constexpr function(function<RightConfig, property_t>&& right)
+      : erasure_(std::move(right.erasure_)) {
+  }
+
+  /// Construction from a callable object which overloads the `()` operator
+  template <typename T, //
+            enable_if_not_convertible_to_this<T>* = nullptr,
+            enable_if_can_accept_all_t<T>* = nullptr,
+            assert_wrong_copy_assign_t<T>* = nullptr,
+            assert_no_strong_except_guarantee_t<T>* = nullptr>
+  constexpr function(T&& callable) : erasure_(std::forward<T>(callable)) {
+  }
+  template <typename T, typename Allocator, //
+            enable_if_not_convertible_to_this<T>* = nullptr,
+            enable_if_can_accept_all_t<T>* = nullptr,
+            enable_if_owning_t<T>* = nullptr,
+            assert_wrong_copy_assign_t<T>* = nullptr,
+            assert_no_strong_except_guarantee_t<T>* = nullptr>
+  constexpr function(T&& callable, Allocator&& allocator)
+      : erasure_(std::forward<T>(callable),
+                 std::forward<Allocator>(allocator)) {
+  }
+
+  /// Empty constructs the function
+  constexpr function(std::nullptr_t np) : erasure_(np) {
+  }
+
+  function& operator=(function const& /*right*/) = default;
+  function& operator=(function&& /*right*/) = default;
+
+  /// Copy assigning from another copyable function
+  template <typename RightConfig,
+            std::enable_if_t<RightConfig::is_copyable>* = nullptr,
+            enable_if_copyable_correct_t<Config, RightConfig>* = nullptr,
+            enable_if_owning_correct_t<Config, RightConfig>* = nullptr>
+  function& operator=(function<RightConfig, property_t> const& right) {
+    erasure_ = right.erasure_;
+    return *this;
+  }
+
+  /// Move assigning from another function
+  template <typename RightConfig,
+            enable_if_copyable_correct_t<Config, RightConfig>* = nullptr,
+            enable_if_owning_correct_t<Config, RightConfig>* = nullptr>
+  function& operator=(function<RightConfig, property_t>&& right) {
+    erasure_ = std::move(right.erasure_);
+    return *this;
+  }
+
+  /// Move assigning from a callable object
+  template <typename T, // ...
+            enable_if_not_convertible_to_this<T>* = nullptr,
+            enable_if_can_accept_all_t<T>* = nullptr,
+            assert_wrong_copy_assign_t<T>* = nullptr,
+            assert_no_strong_except_guarantee_t<T>* = nullptr>
+  function& operator=(T&& callable) {
+    erasure_ = std::forward<T>(callable);
+    return *this;
+  }
+
+  /// Clears the function
+  function& operator=(std::nullptr_t np) {
+    erasure_ = np;
+    return *this;
+  }
+
+  /// Returns true when the function is empty
+  bool empty() const noexcept {
+    return erasure_.empty();
+  }
+
+  /// Returns true when the function isn't empty
+  explicit operator bool() const noexcept {
+    return !empty();
+  }
+
+  /// Assigns a new target with an optional allocator
+  template <typename T, typename Allocator = std::allocator<std::decay_t<T>>,
+            enable_if_not_convertible_to_this<T>* = nullptr,
+            enable_if_can_accept_all_t<T>* = nullptr,
+            assert_wrong_copy_assign_t<T>* = nullptr,
+            assert_no_strong_except_guarantee_t<T>* = nullptr>
+  void assign(T&& callable, Allocator&& allocator = Allocator{}) {
+    erasure_.assign(std::forward<T>(callable),
+                    std::forward<Allocator>(allocator));
+  }
+
+  /// Swaps this function with the given function
+  void swap(function& other) noexcept(HasStrongExceptGuarantee) {
+    if (&other == this) {
+      return;
+    }
+
+    function cache = std::move(other);
+    other = std::move(*this);
+    *this = std::move(cache);
+  }
+
+  /// Swaps the left function with the right one
+  friend void swap(function& left,
+                   function& right) noexcept(HasStrongExceptGuarantee) {
+    left.swap(right);
+  }
+
+  /// Calls the wrapped callable object
+  using type_erasure::invocation_table::operator_impl<
+      0U, function<Config, property_t>, Args...>::operator();
+};
+
+template <typename Config, typename Property>
+bool operator==(function<Config, Property> const& f, std::nullptr_t) {
+  return !bool(f);
+}
+
+template <typename Config, typename Property>
+bool operator!=(function<Config, Property> const& f, std::nullptr_t) {
+  return bool(f);
+}
+
+template <typename Config, typename Property>
+bool operator==(std::nullptr_t, function<Config, Property> const& f) {
+  return !bool(f);
+}
+
+template <typename Config, typename Property>
+bool operator!=(std::nullptr_t, function<Config, Property> const& f) {
+  return bool(f);
+}
+
+// Default object size of the function
+using object_size = std::integral_constant<std::size_t, 32U>;
+
+// Default capacity for small functor optimization
+using default_capacity =
+    std::integral_constant<std::size_t,
+                           object_size::value - (2 * sizeof(void*))>;
+} // namespace detail
+} // namespace abi_310
+
+/// Adaptable function wrapper base for arbitrary functional types.
+template <
+    /// This is a placeholder for future non owning support
+    bool IsOwning,
+    /// Defines whether the function is copyable or not
+    bool IsCopyable,
+    /// Defines the internal capacity of the function
+    /// for small functor optimization.
+    /// The size of the whole function object will be the capacity plus
+    /// the size of two pointers.
+    /// If the capacity is zero, the size will increase through one additional
+    /// pointer so the whole object has the size of 3 * sizeof(void*).
+    std::size_t Capacity,
+    /// Defines whether the function throws an exception on empty function
+    /// call, `std::abort` is called otherwise.
+    bool IsThrowing,
+    /// Defines whether all objects satisfy the strong exception guarantees,
+    /// which means the function type will satisfy the strong exception
+    /// guarantees too.
+    bool HasStrongExceptGuarantee,
+    /// Defines the signature of the function wrapper
+    typename... Signatures>
+using function_base = detail::function<
+    detail::config<IsOwning, IsCopyable, Capacity>,
+    detail::property<IsThrowing, HasStrongExceptGuarantee, Signatures...>>;
+
+/// An owning copyable function wrapper for arbitrary callable types.
+template <typename... Signatures>
+using function = function_base<true, true, detail::default_capacity::value,
+                               true, false, Signatures...>;
+
+/// An owning non copyable function wrapper for arbitrary callable types.
+template <typename... Signatures>
+using unique_function =
+    function_base<true, false, detail::default_capacity::value, true, false,
+                  Signatures...>;
+
+/// A non owning copyable function wrapper for arbitrary callable types.
+template <typename... Signatures>
+using function_view =
+    function_base<false, true, detail::default_capacity::value, true, false,
+                  Signatures...>;
+
+#if !defined(FU2_HAS_DISABLED_EXCEPTIONS)
+/// Exception type that is thrown when invoking empty function objects
+/// and exception support isn't disabled.
+///
+/// Exception suport is enabled if
+/// the template parameter 'Throwing' is set to true (default).
+///
+/// This type will default to std::bad_function_call if the
+/// functional header is used, otherwise the library provides its own type.
+///
+/// You may disable the inclusion of the functionl header
+/// through defining `FU2_WITH_NO_FUNCTIONAL_HEADER`.
+///
+using detail::type_erasure::invocation_table::bad_function_call;
+#endif
+
+/// Returns a callable object, which unifies all callable objects
+/// that were passed to this function.
+///
+///   ```cpp
+///   auto overloaded = fu2::overload([](std::true_type) { return true; },
+///                                   [](std::false_type) { return false; });
+///   ```
+///
+/// \param  callables A pack of callable objects with arbitrary signatures.
+///
+/// \returns          A callable object which exposes the
+///
+template <typename... T>
+constexpr auto overload(T&&... callables) {
+  return detail::overloading::overload(std::forward<T>(callables)...);
+}
+} // namespace fu2
+
+#undef FU2_EXPAND_QUALIFIERS
+#undef FU2_EXPAND_QUALIFIERS_NOEXCEPT
+
+#endif // FU2_INCLUDED_FUNCTION2_HPP_