OpenShot Audio Library | OpenShotAudio  0.6.0
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 
26 namespace juce
27 {
28 
29 #ifndef DOXYGEN
30 
31 namespace 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 
83 template <size_t len, typename T>
84 class FixedSizeFunction;
85 
86 #endif
87 
98 template <size_t len, typename Ret, typename... Args>
99 class FixedSizeFunction<len, Ret (Args...)>
100 {
101 private:
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 
113 public:
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 
204 private:
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 
225 template <size_t len, typename T>
226 bool operator!= (const FixedSizeFunction<len, T>& fn, std::nullptr_t) { return bool (fn); }
227 
228 template <size_t len, typename T>
229 bool operator!= (std::nullptr_t, const FixedSizeFunction<len, T>& fn) { return bool (fn); }
230 
231 template <size_t len, typename T>
232 bool operator== (const FixedSizeFunction<len, T>& fn, std::nullptr_t) { return ! (fn != nullptr); }
233 
234 template <size_t len, typename T>
235 bool operator== (std::nullptr_t, const FixedSizeFunction<len, T>& fn) { return ! (fn != nullptr); }
236 
237 } // namespace juce
FixedSizeFunction(FixedSizeFunction &&other) noexcept