Audacity  3.0.3
AttachedVirtualFunction.h
Go to the documentation of this file.
1 /*!********************************************************************
2 
3 Audacity: A Digital Audio Editor
4 
5 @file AttachedVirtualFunction.h
6 @brief Utility for non-intrusive definition of a new method on a base class
7 
8 Paul Licameli
9 
10 **********************************************************************/
11 
12 #ifndef __AUDACITY_ATTACHED_VIRTUAL_FUNCTION__
13 #define __AUDACITY_ATTACHED_VIRTUAL_FUNCTION__
14 
15 
16 #include <functional>
17 #include <mutex>
18 #include <type_traits>
19 #include <utility>
20 #include "InconsistencyException.h"
21 
23 
159 template< typename Tag, typename Return, typename This, typename... Arguments >
161 {
162 public:
163 
165  using Object = This;
167  using Function = std::function< Return( Object&, Arguments... ) >;
169 
172  static Function Implementation();
173 
175 
177  {
178  static std::once_flag flag;
179  std::call_once( flag, []{ Register<This>( Implementation() ); } );
180  }
181 
183 
187  template<
188  typename Subclass, typename Overridden = AttachedVirtualFunction >
189  struct Override : Overridden
190  {
192  using Object = Subclass;
194  using Function = std::function< Return( Object&, Arguments... ) >;
195 
196  // Check that inheritance is correct
197  static_assert(
198  std::is_base_of< typename Overridden::Object, Object >::value,
199  "overridden class must be a base of the overriding class"
200  );
201 
203  static Function Implementation();
205  static Return Callthrough(
206  typename Overridden::Object &object, Arguments &&...arguments )
207  {
208  return Overridden::Implementation()(
209  object, std::forward< Arguments >( arguments )... );
210  }
212 
214  {
215  static std::once_flag flag;
216  std::call_once( flag, []{
217  // Register in the table an adaptor thunk that downcasts the object
218  auto implementation = Implementation();
219  Register< Subclass >( [=]( This &obj, Arguments &&...arguments ){
220  return implementation(
221  static_cast< Subclass& >( obj ),
222  std::forward< Arguments >( arguments )... );
223  });
224  });
225  }
226  };
227 
229  static Return Call(
230  This &obj,
231  Arguments &&...arguments
232  )
233  {
234  try {
235  // Note that the constructors of this class and overrides cause
236  // the registry to be topologically sorted, with functions for
237  // less-derived classes earlier in the table; so take the last
238  // one that matches the object. (The object might not be of the exact
239  // class corresponding to any of the overrides, which is why this
240  // solution involves calling the predicates generated in Register,
241  // and wouldn't work just with hashing on std::type_index; but perhaps
242  // such a cache could be memo-ized)
243  auto &registry = GetRegistry();
244  auto iter = registry.rbegin(), end = registry.rend();
245  for ( ; iter != end; ++iter ) {
246  auto &entry = *iter;
247  if ( entry.predicate( &obj ) )
248  // This might throw std::bad_function_call on a null function
249  return entry.function(
250  obj, std::forward< Arguments >( arguments )... );
251  }
252  // If not found, also throw
253  throw std::bad_function_call{};
254  }
255  catch ( const std::bad_function_call& ) {
256  // No matching case found with a non-null function.
257  // Translate the exception
259  }
260  }
261 
262 private:
263  template< typename Subclass >
264  static void Register( const Function &function )
265  {
266  // Push back a dynamic type test and corresponding function body
267  GetRegistry().push_back({
268  []( This *b ){ return dynamic_cast< Subclass * >( b ) != nullptr; },
269  function
270  });
271  }
272 
273  using Predicate = std::function< bool( This* ) >;
274 
276  struct Entry
277  {
279  Function function;
280  };
281 
282  using Registry = std::vector< Entry >;
284  {
285  static Registry registry;
286  return registry;
287  }
288 };
289 
290 #endif
AttachedVirtualFunction::Object
This Object
This member name is declared in this class template and redeclared in each override.
Definition: AttachedVirtualFunction.h:165
Registry
Definition: Menus.h:36
AttachedVirtualFunction::Call
static Return Call(This &obj, Arguments &&...arguments)
Invoke the method – but only after static initialization time.
Definition: AttachedVirtualFunction.h:229
flag
static std::once_flag flag
Definition: WaveformView.cpp:1113
AttachedVirtualFunction::Entry
Member of registry of implementations of the method.
Definition: AttachedVirtualFunction.h:277
AttachedVirtualFunction
Class template generates single-dispatch, open method registry tables.
Definition: AttachedVirtualFunction.h:161
InconsistencyException.h
MessageBoxException for violation of preconditions or assertions.
AttachedVirtualFunction::Register
static void Register(const Function &function)
Definition: AttachedVirtualFunction.h:264
AttachedVirtualFunction::Override::Implementation
static Function Implementation()
A function returning a std::function that must be defined so that the program links.
Definition: LabelTrackControls.cpp:182
AttachedVirtualFunction::Entry::predicate
Predicate predicate
Definition: AttachedVirtualFunction.h:278
AttachedVirtualFunction::AttachedVirtualFunction
AttachedVirtualFunction()
At least one static instance must be created; more instances are harmless.
Definition: AttachedVirtualFunction.h:176
THROW_INCONSISTENCY_EXCEPTION
#define THROW_INCONSISTENCY_EXCEPTION
Throw InconsistencyException, using C++ preprocessor to identify the source code location.
Definition: InconsistencyException.h:79
AttachedVirtualFunction::Implementation
static Function Implementation()
A function returning a std::function, which you must define so that the program links.
Definition: TimeShiftHandle.cpp:260
AttachedVirtualFunction::Predicate
std::function< bool(This *) > Predicate
Definition: AttachedVirtualFunction.h:273
AttachedVirtualFunction::Override::Callthrough
static Return Callthrough(typename Overridden::Object &object, Arguments &&...arguments)
May be used in the body of the overriding function, defining it in terms of the overridden one.
Definition: AttachedVirtualFunction.h:205
AttachedVirtualFunction::Override::Override
Override()
At least one static instance must be created; more instances are harmless.
Definition: AttachedVirtualFunction.h:213
AttachedVirtualFunction::Override
For defining overrides of the method.
Definition: AttachedVirtualFunction.h:190
AttachedVirtualFunction::GetRegistry
static Registry & GetRegistry()
Definition: AttachedVirtualFunction.h:283
AttachedVirtualFunction::Function
std::function< Return(Object &, Arguments...) > Function
This member name is declared in this class template and redeclared in each override.
Definition: AttachedVirtualFunction.h:167