63 constexpr static bool maybe_empty =
64 std::is_pointer_v<std::decay_t<F>> || std::is_member_pointer_v<std::decay_t<F>> ||
65 std::is_same_v<std::function<R(Args...)>, std::decay_t<F>>;
68 constexpr static auto is_empty(
const F& f) -> std::enable_if_t<maybe_empty<F>,
bool> {
73 constexpr static auto is_empty(
const F&) -> std::enable_if_t<!maybe_empty<F>,
bool> {
78 void (*dtor)(
void*)
noexcept;
79 void (*move_ctor)(
void*,
void*)
noexcept;
80 const std::type_info& (*target_type)()
noexcept;
81 void* (*pointer)(
void*)
noexcept;
82 const void* (*const_pointer)(
const void*)
noexcept;
85 using invoke_t = R (*)(
void*, Args...)
noexcept(NoExcept);
87 template <
class F,
bool Small>
91 struct model<F, true> {
93 model(G&& f) : _f(std::forward<G>(f)) {}
94 model(model&&)
noexcept =
delete;
96 static void dtor(
void* self)
noexcept {
static_cast<model*
>(self)->~model(); }
97 static void move_ctor(
void* self,
void* p)
noexcept {
98 new (p) model(std::move(
static_cast<model*
>(self)->_f));
109 static auto invoke(
void* self, Args... args)
noexcept(NoExcept) -> R {
110 return (
static_cast<model*
>(self)->_f)(std::forward<Args>(args)...);
113 static auto target_type()
noexcept ->
const std::type_info& {
return typeid(F); }
114 static auto pointer(
void* self)
noexcept ->
void* {
return &
static_cast<model*
>(self)->_f; }
115 static auto const_pointer(
const void* self)
noexcept ->
const void* {
116 return &
static_cast<const model*
>(self)->_f;
118#if defined(__GNUC__) && __GNUC__ < 7 && !defined(__clang__)
119 static const concept_t _vtable;
120 static const invoke_t _invoke;
122 static constexpr concept_t _vtable = {dtor, move_ctor, target_type, pointer, const_pointer};
123 static constexpr invoke_t _invoke = invoke;
129 struct model<F, false> {
131 model(G&& f) : _p(std::make_unique<F>(std::forward<G>(f))) {}
132 model(model&&)
noexcept =
default;
134 static void dtor(
void* self)
noexcept {
static_cast<model*
>(self)->~model(); }
135 static void move_ctor(
void* self,
void* p)
noexcept {
136 new (p) model(std::move(*
static_cast<model*
>(self)));
146 static auto invoke(
void* self, Args... args)
noexcept(NoExcept) -> R {
147 return (*
static_cast<model*
>(self)->_p)(std::forward<Args>(args)...);
150 static auto target_type()
noexcept ->
const std::type_info& {
return typeid(F); }
151 static auto pointer(
void* self)
noexcept ->
void* {
152 return static_cast<model*
>(self)->_p.get();
154 static auto const_pointer(
const void* self)
noexcept ->
const void* {
155 return static_cast<const model*
>(self)->_p.get();
158#if defined(__GNUC__) && __GNUC__ < 7 && !defined(__clang__)
159 static const concept_t _vtable;
160 static const invoke_t _invoke;
162 static constexpr concept_t _vtable = {dtor, move_ctor, target_type, pointer, const_pointer};
163 static constexpr invoke_t _invoke = invoke;
166 std::unique_ptr<F> _p;
170 static void dtor(
void*)
noexcept {}
171 static void move_ctor(
void*,
void*)
noexcept {}
173 static auto invoke(
void*, Args...)
noexcept(NoExcept) -> R {
174 if constexpr (NoExcept) {
176 throw std::bad_function_call();
181 throw std::bad_function_call();
184 static auto target_type_()
noexcept ->
const std::type_info& {
return typeid(void); }
185 static auto pointer(
void*)
noexcept ->
void* {
return nullptr; }
186 static auto const_pointer(
const void*)
noexcept ->
const void* {
return nullptr; }
188#if defined(__GNUC__) && __GNUC__ < 7 && !defined(__clang__)
189 static const concept_t _vtable;
191 static constexpr concept_t _vtable = {dtor, move_ctor, target_type_, pointer, const_pointer};
210 static constexpr size_t max_align =
alignof(std::max_align_t);
211 static constexpr size_t small_size =
212 std::max(max_align * 2,
sizeof(
void*) * 8) - std::max(max_align,
sizeof(
void*) * 2);
214 const concept_t* _vtable_ptr = &_vtable;
215 invoke_t _invoke = invoke;
216 alignas(std::max_align_t) std::array<unsigned char, small_size> _model;
219 using result_type = R;
221 constexpr task_()
noexcept =
default;
222 constexpr task_(std::nullptr_t) noexcept : task_() {}
223 task_(
const task_&) =
delete;
224 task_(
const task_&&) =
delete;
225 task_(task_&& x) noexcept : _vtable_ptr(x._vtable_ptr), _invoke(x._invoke) {
226 _vtable_ptr->move_ctor(&x._model, &_model);
230 std::enable_if_t<!NoExcept || std::is_nothrow_invocable_v<F, Args...>,
bool> =
true>
232 using small_t = model<std::decay_t<F>,
true>;
233 using large_t = model<std::decay_t<F>,
false>;
234 using model_t = std::conditional_t<(
sizeof(small_t) <= small_size) &&
235 (
alignof(small_t) <=
alignof(
decltype(_model))),
238 if (is_empty(f))
return;
240 new (&_model) model_t(std::forward<F>(f));
241 _vtable_ptr = &model_t::_vtable;
242 _invoke = &model_t::invoke;
245 ~task_() { _vtable_ptr->dtor(&_model); };
247 auto operator=(
const task_&) -> task_& =
delete;
249 auto operator=(task_&& x)
noexcept -> task_& {
250 _vtable_ptr->dtor(&_model);
251 _vtable_ptr = x._vtable_ptr;
253 _vtable_ptr->move_ctor(&x._model, &_model);
257 auto operator=(std::nullptr_t)
noexcept -> task_& {
return *
this = task_(); }
260 auto operator=(F&& f)
261 -> std::enable_if_t<!NoExcept || std::is_nothrow_invocable_v<
decltype(f), Args...>,
263 return *
this = task_(std::forward<F>(f));
266 void swap(
task_& x)
noexcept { std::swap(*
this, x); }
268 explicit operator bool()
const {
return _vtable_ptr->const_pointer(&_model) !=
nullptr; }
270 [[nodiscard]]
auto target_type() const noexcept -> const std::type_info& {
271 return _vtable_ptr->target_type();
275 auto target() -> T* {
276 return (target_type() ==
typeid(T)) ?
static_cast<T*
>(_vtable_ptr->pointer(&_model)) :
281 [[nodiscard]] [[nodiscard]] [[nodiscard]]
auto target() const -> const T* {
282 return (target_type() ==
typeid(T)) ?
283 static_cast<const T*
>(_vtable_ptr->const_pointer(&_model)) :
287 template <
class... Brgs>
288 auto operator()(Brgs&&... brgs)
noexcept(NoExcept) {
289 return _invoke(&_model, std::forward<Brgs>(brgs)...);
292 friend inline void swap(
task_& x,
task_& y)
noexcept {
return x.swap(y); }
293 friend inline auto operator==(
const task_& x, std::nullptr_t) ->
bool {
294 return !
static_cast<bool>(x);
296 friend inline auto operator==(std::nullptr_t,
const task_& x) ->
bool {
297 return !
static_cast<bool>(x);
299 friend inline auto operator!=(
const task_& x, std::nullptr_t) ->
bool {
300 return static_cast<bool>(x);
302 friend inline auto operator!=(std::nullptr_t,
const task_& x) ->
bool {
303 return static_cast<bool>(x);