OpenShot Audio Library | OpenShotAudio 0.4.0
 
Loading...
Searching...
No Matches
juce_FixedSizeFunction.h
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11 Agreement and JUCE Privacy Policy.
12
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
15
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
18
19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21 DISCLAIMED.
22
23 ==============================================================================
24*/
25
26namespace juce
27{
28
29#ifndef DOXYGEN
30
31namespace detail
32{
33 template <typename Ret, typename... Args>
34 struct Vtable
35 {
36 using Storage = void*;
37
38 using Move = void (*) (Storage, Storage);
39 using Call = Ret (*) (Storage, Args...);
40 using Clear = void (*) (Storage);
41
42 constexpr Vtable (Move moveIn, Call callIn, Clear clearIn) noexcept
43 : move (moveIn), call (callIn), clear (clearIn) {}
44
45 Move move = nullptr;
46 Call call = nullptr;
47 Clear clear = nullptr;
48 };
49
50 template <typename Fn>
51 void move (void* from, void* to)
52 {
53 new (to) Fn (std::move (*reinterpret_cast<Fn*> (from)));
54 }
55
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)
58 {
59 (*reinterpret_cast<Fn*> (s)) (std::forward<Args> (args)...);
60 }
61
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)
64 {
65 return (*reinterpret_cast<Fn*> (s)) (std::forward<Args> (args)...);
66 }
67
68 template <typename Fn>
69 void clear (void* s)
70 {
71 // I know this looks insane, for some reason MSVC 14 sometimes thinks fn is unreferenced
72 [[maybe_unused]] auto& fn = *reinterpret_cast<Fn*> (s);
73 fn.~Fn();
74 }
75
76 template <typename Fn, typename Ret, typename... Args>
77 constexpr Vtable<Ret, Args...> makeVtable()
78 {
79 return { move <Fn>, call <Fn, Ret, Args...>, clear<Fn> };
80 }
81} // namespace detail
82
83template <size_t len, typename T>
84class FixedSizeFunction;
85
86#endif
87
98template <size_t len, typename Ret, typename... Args>
99class FixedSizeFunction<len, Ret (Args...)>
100{
101private:
102 using Storage = std::aligned_storage_t<len>;
103
104 template <typename Item>
105 using Decay = std::decay_t<Item>;
106
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>,
111 int>;
112
113public:
115 FixedSizeFunction() noexcept = default;
116
118 FixedSizeFunction (std::nullptr_t) noexcept
119 : FixedSizeFunction() {}
120
121 FixedSizeFunction (const FixedSizeFunction&) = delete;
122
124 template <typename Callable,
125 typename Fn = Decay<Callable>,
126 IntIfValidConversion<Callable> = 0>
127 FixedSizeFunction (Callable&& callable)
128 {
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");
133
134 static constexpr auto vtableForCallable = detail::makeVtable<Fn, Ret, Args...>();
135 vtable = &vtableForCallable;
136
137 [[maybe_unused]] auto* ptr = new (&storage) Fn (std::forward<Callable> (callable));
138 jassert ((void*) ptr == (void*) &storage);
139 }
140
142 FixedSizeFunction (FixedSizeFunction&& other) noexcept
143 : vtable (other.vtable)
144 {
145 move (std::move (other));
146 }
147
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)
152 {
153 move (std::move (other));
154 }
155
157 FixedSizeFunction& operator= (std::nullptr_t) noexcept
158 {
159 return *this = FixedSizeFunction();
160 }
161
162 FixedSizeFunction& operator= (const FixedSizeFunction&) = delete;
163
165 template <typename Callable, IntIfValidConversion<Callable> = 0>
166 FixedSizeFunction& operator= (Callable&& callable)
167 {
168 return *this = FixedSizeFunction (std::forward<Callable> (callable));
169 }
170
172 template <size_t otherLen, std::enable_if_t<(otherLen < len), int> = 0>
173 FixedSizeFunction& operator= (FixedSizeFunction<otherLen, Ret (Args...)>&& other) noexcept
174 {
175 return *this = FixedSizeFunction (std::move (other));
176 }
177
179 FixedSizeFunction& operator= (FixedSizeFunction&& other) noexcept
180 {
181 clear();
182 vtable = other.vtable;
183 move (std::move (other));
184 return *this;
185 }
186
188 ~FixedSizeFunction() noexcept { clear(); }
189
193 Ret operator() (Args... args) const
194 {
195 if (vtable != nullptr)
196 return vtable->call (&storage, std::forward<Args> (args)...);
197
198 throw std::bad_function_call();
199 }
200
202 explicit operator bool() const noexcept { return vtable != nullptr; }
203
204private:
205 template <size_t, typename>
206 friend class FixedSizeFunction;
207
208 void clear() noexcept
209 {
210 if (vtable != nullptr)
211 vtable->clear (&storage);
212 }
213
214 template <size_t otherLen, typename T>
215 void move (FixedSizeFunction<otherLen, T>&& other) noexcept
216 {
217 if (vtable != nullptr)
218 vtable->move (&other.storage, &storage);
219 }
220
221 const detail::Vtable<Ret, Args...>* vtable = nullptr;
222 mutable Storage storage;
223};
224
225template <size_t len, typename T>
226bool operator!= (const FixedSizeFunction<len, T>& fn, std::nullptr_t) { return bool (fn); }
227
228template <size_t len, typename T>
229bool operator!= (std::nullptr_t, const FixedSizeFunction<len, T>& fn) { return bool (fn); }
230
231template <size_t len, typename T>
232bool operator== (const FixedSizeFunction<len, T>& fn, std::nullptr_t) { return ! (fn != nullptr); }
233
234template <size_t len, typename T>
235bool operator== (std::nullptr_t, const FixedSizeFunction<len, T>& fn) { return ! (fn != nullptr); }
236
237} // namespace juce