22 static constexpr std::size_t storage_size = InlineSize <
sizeof(
void*) ?
sizeof(
void*) : InlineSize;
26 auto (*invoke)(
void*, Args&&...) -> R;
27 void (*destroy)(
void*)
noexcept;
28 void (*move)(
void*,
void*)
noexcept;
32 static constexpr bool stores_inline = InlineSize != 0 &&
sizeof(F) <= storage_size &&
alignof(F) <=
alignof(
void*)
33 && std::is_nothrow_move_constructible_v<F>;
37 table()
noexcept -> operations
const*
39 if constexpr (stores_inline<F>)
41 static constexpr operations value{ [](
void* storage, Args&&... args) -> R
43 if constexpr (std::is_void_v<R>)
44 std::invoke(*
static_cast<F*
>(storage), std::forward<Args>(args)...);
46 return std::invoke(*
static_cast<F*
>(storage),
47 std::forward<Args>(args)...);
49 [](
void* storage)
noexcept {
static_cast<F*
>(storage)->~F(); },
50 [](
void* destination,
void* source)
noexcept
52 ::new (destination) F(std::move(*
static_cast<F*
>(source)));
53 static_cast<F*
>(source)->~F();
59 static constexpr operations value{ [](
void* storage, Args&&... args) -> R
61 auto& callable = **std::launder(
static_cast<F**
>(storage));
62 if constexpr (std::is_void_v<R>)
63 std::invoke(callable, std::forward<Args>(args)...);
65 return std::invoke(callable, std::forward<Args>(args)...);
67 [](
void* storage)
noexcept
69 auto pointer = std::launder(
static_cast<F**
>(storage));
73 [](
void* destination,
void* source)
noexcept
75 auto source_pointer = std::launder(
static_cast<F**
>(source));
76 ::new (destination) F*(*source_pointer);
77 *source_pointer =
nullptr;
87 template <
typename F,
typename Value = std::decay_t<F>,
88 std::enable_if_t<!std::is_same_v<remove_cvref_t<F>, move_only_function>
89 && std::is_invocable_r_v<R, Value&, Args...>,
93 if constexpr (std::is_pointer_v<Value> || std::is_member_pointer_v<Value>)
94 if (function ==
nullptr)
97 operations_ = table<Value>();
98 if constexpr (stores_inline<Value>)
99 ::new (storage_) Value(std::forward<F>(function));
101 ::new (storage_) Value*(
new Value(std::forward<F>(function)));
109 if (operations_ !=
nullptr)
111 operations_->move(storage_,
other.storage_);
112 other.operations_ =
nullptr;
122 operations_ =
other.operations_;
123 if (operations_ !=
nullptr)
125 operations_->move(storage_,
other.storage_);
126 other.operations_ =
nullptr;
138 operator bool() const noexcept
140 return operations_ !=
nullptr;
146 if (operations_ ==
nullptr)
147 throw std::bad_function_call();
148 if constexpr (std::is_void_v<R>)
149 operations_->invoke(storage_, std::forward<Args>(args)...);
151 return operations_->invoke(storage_, std::forward<Args>(args)...);
157 if (operations_ !=
nullptr)
159 operations_->destroy(storage_);
160 operations_ =
nullptr;
165 operations
const* operations_{
nullptr };
166 alignas(
void*)
unsigned char storage_[storage_size]{};