15 template <DerivedType Type>
17 void (*move_to)(storage&, storage&)
noexcept;
18 void (*destroy)(storage&)
noexcept;
19 Return (*invoke)(storage
const&, Xs&&...)
noexcept(Noexcept);
23 struct vtable_base<DerivedType::Copyable> : vtable_base<DerivedType::MoveOnly> {
24 void (*copy_to)(storage
const&, storage&);
27 struct vtable : vtable_base<Type> {};
30 static constexpr size_t embedded_target_offset =
31 alignof(Fn) <=
sizeof(vtable*) ? 0 : (
alignof(Fn) -
sizeof(vtable*));
34 static constexpr size_t embedded_target_available_size = embedded_target_size - embedded_target_offset<Fn>;
37 static constexpr bool is_heap_target =
alignof(Fn) >
alignof(std::max_align_t)
38 ||
sizeof(Fn) > embedded_target_available_size<Fn>
39 || !std::is_nothrow_move_constructible_v<Fn>;
46 union alignas(max_align_t) {
48 char embedded_target[embedded_target_size];
53 [[nodiscard]]
void* embedded_target_ptr()
noexcept {
54 return &embedded_target + embedded_target_offset<Fn>;
58 [[nodiscard]] Fn* small_fn_ptr()
const noexcept {
59 return static_cast<Fn*
>(
const_cast<storage*
>(
this)->embedded_target_ptr<Fn>());
63 [[nodiscard]] Fn* large_fn_ptr()
const noexcept {
64 return static_cast<Fn*
>(heap_target);
67 void set_large_fn_ptr(
void*
const v)
noexcept { heap_target = v; }
69 template <
class Fn,
class FnInvQuals,
bool HeapTarget>
71 static Fn* target(storage
const& self) {
72 if constexpr (HeapTarget) {
73 return self.large_fn_ptr<Fn>();
75 return self.small_fn_ptr<Fn>();
79 static void copy_to(storage
const& self, storage& to) {
80 if constexpr (Type == DerivedType::Copyable) {
81 if constexpr (HeapTarget) {
82 to.set_large_fn_ptr(::new Fn(*target(self)));
84 ::new (to.embedded_target_ptr<Fn>()) Fn(*target(self));
89 static void move_to(storage& self, storage& to)
noexcept {
90 if constexpr (HeapTarget) {
91 to.set_large_fn_ptr(target(self));
92 self.set_large_fn_ptr(
nullptr);
94 auto const ptr = target(self);
95 ::new (to.embedded_target_ptr<Fn>()) Fn(std::move(*ptr));
100 static void destroy(storage& self)
noexcept {
101 if constexpr (HeapTarget) {
108 static Return invoke(storage
const& self, Xs&&... args)
noexcept(Noexcept) {
109 if constexpr (std::is_void_v<Return>) {
110 (void)std::invoke(
static_cast<FnInvQuals
>(*target(self)), std::forward<Xs>(args)...);
112 return std::invoke(
static_cast<FnInvQuals
>(*target(self)), std::forward<Xs>(args)...);
117 template <
class Fn,
class FnInvQuals>
118 [[nodiscard]]
static constexpr vtable create_vtable()
noexcept {
121 using impl_type = vtable_impl<Fn, FnInvQuals, is_heap_target<Fn>>;
122 impl.move_to = &impl_type::move_to;
123 impl.destroy = &impl_type::destroy;
124 impl.invoke = &impl_type::invoke;
125 if constexpr (Type == DerivedType::Copyable) {
126 impl.copy_to = &impl_type::copy_to;
131 template <
class Fn,
class FnInvQuals>
132 static constexpr vtable vfstorage = create_vtable<Fn, FnInvQuals>();
137 vtable
const& get_vtable()
const noexcept {
return *mStorage.vfptr; }
141 void construct_empty() { mStorage.vfptr =
nullptr; }
142 template <
class Fn,
class FnInvQuals,
class... Ys>
143 void construct_target(Ys&&... args) {
144 mStorage.vfptr = &vfstorage<Fn, FnInvQuals>;
145 if constexpr (is_heap_target<Fn>) {
146 auto ptr = std::make_unique<Fn>(std::forward<Ys>(args)...);
147 mStorage.set_large_fn_ptr(ptr.release());
149 ::new (mStorage.embedded_target_ptr<Fn>()) Fn(std::forward<Ys>(args)...);
153 auto get_invoke()
const noexcept {
157 return get_vtable().invoke;
161 explicit operator bool()
const noexcept {
return mStorage.vfptr !=
nullptr; }