VST3: fetch midi mappings all at once, use it for note/sound-off
[carla.git] / source / modules / juce_dsp / containers / juce_FixedSizeFunction.h
blob565f8658982cae2c2bd9b7e28060f3e7b5cdb872
1 /*
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
8 licensing.
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
21 DISCLAIMED.
23 ==============================================================================
26 namespace juce
28 namespace dsp
31 #ifndef DOXYGEN
33 namespace detail
35 template <typename Ret, typename... Args>
36 struct Vtable
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) {}
47 Move move = nullptr;
48 Call call = nullptr;
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>
71 void clear (void* s)
73 auto& fn = *reinterpret_cast<Fn*> (s);
74 fn.~Fn();
75 // I know this looks insane, for some reason MSVC 14 sometimes thinks fn is unreferenced
76 ignoreUnused (fn);
79 template <typename Fn, typename Ret, typename... Args>
80 constexpr Vtable<Ret, Args...> makeVtable()
82 return { move <Fn>, call <Fn, Ret, Args...>, clear<Fn> };
84 } // namespace detail
86 template <size_t len, typename T>
87 class FixedSizeFunction;
89 #endif
91 /**
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.
99 @tags{DSP}
101 template <size_t len, typename Ret, typename... Args>
102 class FixedSizeFunction<len, Ret (Args...)>
104 private:
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,
114 int>::type;
116 public:
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
184 clear();
185 vtable = other.vtable;
186 move (std::move (other));
187 return *this;
190 /** Destructor. */
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; }
207 private:
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); }