2 ==============================================================================
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
7 JUCE is an open source library subject to commercial or open-source
10 By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11 Agreement and JUCE Privacy Policy.
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
23 ==============================================================================
35 template <typename Ret
, typename
... Args
>
38 using Storage
= void*;
40 using Move
= void (*) (Storage
, Storage
);
41 using Call
= Ret (*) (Storage
, Args
...);
42 using Clear
= void (*) (Storage
);
44 constexpr Vtable (Move moveIn
, Call callIn
, Clear clearIn
) noexcept
45 : move (moveIn
), call (callIn
), clear (clearIn
) {}
49 Clear clear
= nullptr;
52 template <typename Fn
>
53 void move (void* from
, void* to
)
55 new (to
) Fn (std::move (*reinterpret_cast<Fn
*> (from
)));
58 template <typename Fn
, typename Ret
, typename
... Args
>
59 typename
std::enable_if
<std::is_same
<Ret
, void>::value
, Ret
>::type
call (void* s
, Args
... args
)
61 (*reinterpret_cast<Fn
*> (s
)) (args
...);
64 template <typename Fn
, typename Ret
, typename
... Args
>
65 typename
std::enable_if
<! std::is_same
<Ret
, void>::value
, Ret
>::type
call (void* s
, Args
... args
)
67 return (*reinterpret_cast<Fn
*> (s
)) (std::forward
<Args
> (args
)...);
70 template <typename Fn
>
73 auto& fn
= *reinterpret_cast<Fn
*> (s
);
75 // I know this looks insane, for some reason MSVC 14 sometimes thinks fn is unreferenced
79 template <typename Fn
, typename Ret
, typename
... Args
>
80 constexpr Vtable
<Ret
, Args
...> makeVtable()
82 return { move
<Fn
>, call
<Fn
, Ret
, Args
...>, clear
<Fn
> };
86 template <size_t len
, typename T
>
87 class FixedSizeFunction
;
92 A type similar to `std::function` that holds a callable object.
94 Unlike `std::function`, the callable object will always be stored in
95 a buffer of size `len` that is internal to the FixedSizeFunction instance.
96 This in turn means that creating a FixedSizeFunction instance will never allocate,
97 making FixedSizeFunctions suitable for use in realtime contexts.
101 template <size_t len
, typename Ret
, typename
... Args
>
102 class FixedSizeFunction
<len
, Ret (Args
...)>
105 using Storage
= typename
std::aligned_storage
<len
>::type
;
107 template <typename Item
>
108 using Decay
= typename
std::decay
<Item
>::type
;
110 template <typename Item
, typename Fn
= Decay
<Item
>>
111 using IntIfValidConversion
= typename
std::enable_if
<sizeof (Fn
) <= len
112 && alignof (Fn
) <= alignof (Storage
)
113 && ! std::is_same
<FixedSizeFunction
, Fn
>::value
,
117 /** Create an empty function. */
118 FixedSizeFunction() noexcept
= default;
120 /** Create an empty function. */
121 FixedSizeFunction (std::nullptr_t
) noexcept
122 : FixedSizeFunction() {}
124 FixedSizeFunction (const FixedSizeFunction
&) = delete;
126 /** Forwards the passed Callable into the internal storage buffer. */
127 template <typename Callable
,
128 typename Fn
= Decay
<Callable
>,
129 IntIfValidConversion
<Callable
> = 0>
130 FixedSizeFunction (Callable
&& callable
)
132 static_assert (sizeof (Fn
) <= len
,
133 "The requested function cannot fit in this FixedSizeFunction");
134 static_assert (alignof (Fn
) <= alignof (Storage
),
135 "FixedSizeFunction cannot accommodate the requested alignment requirements");
137 static constexpr auto vtableForCallable
= detail::makeVtable
<Fn
, Ret
, Args
...>();
138 vtable
= &vtableForCallable
;
140 auto* ptr
= new (&storage
) Fn (std::forward
<Callable
> (callable
));
141 jassertquiet ((void*) ptr
== (void*) &storage
);
144 /** Move constructor. */
145 FixedSizeFunction (FixedSizeFunction
&& other
) noexcept
146 : vtable (other
.vtable
)
148 move (std::move (other
));
151 /** Converting constructor from smaller FixedSizeFunctions. */
152 template <size_t otherLen
, typename
std::enable_if
<(otherLen
< len
), int>::type
= 0>
153 FixedSizeFunction (FixedSizeFunction
<otherLen
, Ret (Args
...)>&& other
) noexcept
154 : vtable (other
.vtable
)
156 move (std::move (other
));
159 /** Nulls this instance. */
160 FixedSizeFunction
& operator= (std::nullptr_t
) noexcept
162 return *this = FixedSizeFunction();
165 FixedSizeFunction
& operator= (const FixedSizeFunction
&) = delete;
167 /** Assigns a new callable to this instance. */
168 template <typename Callable
, IntIfValidConversion
<Callable
> = 0>
169 FixedSizeFunction
& operator= (Callable
&& callable
)
171 return *this = FixedSizeFunction (std::forward
<Callable
> (callable
));
174 /** Move assignment from smaller FixedSizeFunctions. */
175 template <size_t otherLen
, typename
std::enable_if
<(otherLen
< len
), int>::type
= 0>
176 FixedSizeFunction
& operator= (FixedSizeFunction
<otherLen
, Ret (Args
...)>&& other
) noexcept
178 return *this = FixedSizeFunction (std::move (other
));
181 /** Move assignment operator. */
182 FixedSizeFunction
& operator= (FixedSizeFunction
&& other
) noexcept
185 vtable
= other
.vtable
;
186 move (std::move (other
));
191 ~FixedSizeFunction() noexcept
{ clear(); }
193 /** If this instance is currently storing a callable object, calls that object,
194 otherwise throws `std::bad_function_call`.
196 Ret
operator() (Args
... args
) const
198 if (vtable
!= nullptr)
199 return vtable
->call (&storage
, std::forward
<Args
> (args
)...);
201 throw std::bad_function_call();
204 /** Returns true if this instance currently holds a callable. */
205 explicit operator bool() const noexcept
{ return vtable
!= nullptr; }
208 template <size_t, typename
>
209 friend class FixedSizeFunction
;
211 void clear() noexcept
213 if (vtable
!= nullptr)
214 vtable
->clear (&storage
);
217 template <size_t otherLen
, typename T
>
218 void move (FixedSizeFunction
<otherLen
, T
>&& other
) noexcept
220 if (vtable
!= nullptr)
221 vtable
->move (&other
.storage
, &storage
);
224 const detail::Vtable
<Ret
, Args
...>* vtable
= nullptr;
225 mutable Storage storage
;
228 template <size_t len
, typename T
>
229 bool operator!= (const FixedSizeFunction
<len
, T
>& fn
, std::nullptr_t
) { return bool (fn
); }
231 template <size_t len
, typename T
>
232 bool operator!= (std::nullptr_t
, const FixedSizeFunction
<len
, T
>& fn
) { return bool (fn
); }
234 template <size_t len
, typename T
>
235 bool operator== (const FixedSizeFunction
<len
, T
>& fn
, std::nullptr_t
) { return ! (fn
!= nullptr); }
237 template <size_t len
, typename T
>
238 bool operator== (std::nullptr_t
, const FixedSizeFunction
<len
, T
>& fn
) { return ! (fn
!= nullptr); }