33 template <
typename Ret,
typename... Args>
36 using Storage =
void*;
38 using Move = void (*) (Storage, Storage);
39 using Call = Ret (*) (Storage, Args...);
40 using Clear = void (*) (Storage);
42 constexpr Vtable (Move moveIn, Call callIn, Clear clearIn) noexcept
43 : move (moveIn), call (callIn), clear (clearIn) {}
47 Clear clear =
nullptr;
50 template <
typename Fn>
51 void move (
void* from,
void* to)
53 new (to) Fn (std::move (*
reinterpret_cast<Fn*
> (from)));
56 template <
typename Fn,
typename Ret,
typename... Args>
57 std::enable_if_t<std::is_same_v<Ret, void>, Ret> call (
void* s, Args... args)
59 (*
reinterpret_cast<Fn*
> (s)) (std::forward<Args> (args)...);
62 template <
typename Fn,
typename Ret,
typename... Args>
63 std::enable_if_t<! std::is_same_v<Ret, void>, Ret> call (
void* s, Args... args)
65 return (*
reinterpret_cast<Fn*
> (s)) (std::forward<Args> (args)...);
68 template <
typename Fn>
72 [[maybe_unused]]
auto& fn = *
reinterpret_cast<Fn*
> (s);
76 template <
typename Fn,
typename Ret,
typename... Args>
77 constexpr Vtable<Ret, Args...> makeVtable()
79 return { move <Fn>, call <Fn, Ret, Args...>, clear<Fn> };
83template <
size_t len,
typename T>
84class FixedSizeFunction;
98template <
size_t len,
typename Ret,
typename... Args>
99class FixedSizeFunction<len, Ret (Args...)>
102 using Storage = std::aligned_storage_t<len>;
104 template <
typename Item>
105 using Decay = std::decay_t<Item>;
107 template <
typename Item,
typename Fn = Decay<Item>>
108 using IntIfValidConversion = std::enable_if_t<
sizeof (Fn) <= len
109 &&
alignof (Fn) <=
alignof (Storage)
110 && ! std::is_same_v<FixedSizeFunction, Fn>,
118 FixedSizeFunction (std::nullptr_t) noexcept
119 : FixedSizeFunction() {}
121 FixedSizeFunction (
const FixedSizeFunction&) =
delete;
124 template <
typename Callable,
125 typename Fn = Decay<Callable>,
126 IntIfValidConversion<Callable> = 0>
129 static_assert (
sizeof (Fn) <= len,
130 "The requested function cannot fit in this FixedSizeFunction");
131 static_assert (
alignof (Fn) <=
alignof (Storage),
132 "FixedSizeFunction cannot accommodate the requested alignment requirements");
134 static constexpr auto vtableForCallable = detail::makeVtable<Fn, Ret, Args...>();
135 vtable = &vtableForCallable;
137 [[maybe_unused]]
auto* ptr =
new (&storage) Fn (std::forward<Callable> (callable));
138 jassert ((
void*) ptr == (
void*) &storage);
143 : vtable (other.vtable)
145 move (std::move (other));
149 template <
size_t otherLen, std::enable_if_t<(otherLen < len),
int> = 0>
150 FixedSizeFunction (FixedSizeFunction<otherLen, Ret (Args...)>&& other) noexcept
151 : vtable (other.vtable)
153 move (std::move (other));
157 FixedSizeFunction& operator= (std::
nullptr_t) noexcept
159 return *this = FixedSizeFunction();
162 FixedSizeFunction& operator= (const FixedSizeFunction&) = delete;
165 template <
typename Callable, IntIfVal
idConversion<Callable> = 0>
166 FixedSizeFunction& operator= (Callable&& callable)
168 return *
this = FixedSizeFunction (std::forward<Callable> (callable));
172 template <
size_t otherLen, std::enable_if_t<(otherLen < len),
int> = 0>
173 FixedSizeFunction& operator= (FixedSizeFunction<otherLen, Ret (Args...)>&& other) noexcept
175 return *this = FixedSizeFunction (std::move (other));
179 FixedSizeFunction& operator= (FixedSizeFunction&& other) noexcept
182 vtable = other.vtable;
183 move (std::move (other));
188 ~FixedSizeFunction() noexcept { clear(); }
193 Ret operator() (Args... args) const
195 if (vtable !=
nullptr)
196 return vtable->call (&storage, std::forward<Args> (args)...);
198 throw std::bad_function_call();
202 explicit operator bool() const noexcept {
return vtable !=
nullptr; }
205 template <
size_t,
typename>
206 friend class FixedSizeFunction;
208 void clear() noexcept
210 if (vtable !=
nullptr)
211 vtable->clear (&storage);
214 template <
size_t otherLen,
typename T>
215 void move (FixedSizeFunction<otherLen, T>&& other)
noexcept
217 if (vtable !=
nullptr)
218 vtable->move (&other.storage, &storage);
221 const detail::Vtable<Ret, Args...>* vtable =
nullptr;
222 mutable Storage storage;
225template <
size_t len,
typename T>
226bool operator!= (
const FixedSizeFunction<len, T>& fn, std::nullptr_t) {
return bool (fn); }
228template <
size_t len,
typename T>
229bool operator!= (std::nullptr_t,
const FixedSizeFunction<len, T>& fn) {
return bool (fn); }
231template <
size_t len,
typename T>
232bool operator== (
const FixedSizeFunction<len, T>& fn, std::nullptr_t) {
return ! (fn !=
nullptr); }
234template <
size_t len,
typename T>
235bool operator== (std::nullptr_t,
const FixedSizeFunction<len, T>& fn) {
return ! (fn !=
nullptr); }
FixedSizeFunction() noexcept=default
FixedSizeFunction(FixedSizeFunction &&other) noexcept
FixedSizeFunction(Callable &&callable)