text: #ifndef __AUDACITY_EXCEPTION__
  #define __AUDACITY_EXCEPTION__
  
  /**********************************************************************
  
   Audacity: A Digital Audio Editor
  
   AudacityException.h
  
   Paul Licameli
   
   Define the root of a hierarchy of classes that are thrown and caught
   by Audacity.
   
   Define some subclasses.  Not all subclasses need be defined here.
  
   **********************************************************************/
  
  #include "MemoryX.h"
  #include <wx/app.h>
  
  class wxString;
  
  class AudacityException /* not final */
  {
  public:
     AudacityException() {}
     virtual ~AudacityException() = 0;
  
     // This is intended as a "polymorphic move copy constructor"
     // which leaves this "empty".
     // We would not need this if we had std::exception_ptr
     virtual std::unique_ptr< AudacityException > Move() = 0;
  
     // Action to do in the main thread at idle time of the event loop.
     virtual void DelayedHandlerAction() = 0;
  
  protected:
     // Make this protected to prevent slicing copies
     AudacityException( AudacityException&& ) {}
     AudacityException( const AudacityException& ) = default;
     AudacityException &operator = (AudacityException &&) { return *this;}
     AudacityException &operator = ( const AudacityException & ) PROHIBITED;
  };
  
  // A subclass of AudacityException whose delayed handler action displays
  // a message box.  The message is specified by further subclasses.
  // Not more than one message box will be displayed for each pass through
  // the main event idle loop.
  class MessageBoxException /* not final */ : public AudacityException
  {
     // Do not allow subclasses to change this behavior further, except
     // by overriding ErrorMessage()
     using AudacityException::DelayedHandlerAction;
     void DelayedHandlerAction() override;
  
  protected:
     // If default-constructed with empty caption, it makes no message box.
     explicit MessageBoxException( const wxString &caption = wxString{} );
     ~MessageBoxException() override;
  
     MessageBoxException( const MessageBoxException& );
     MessageBoxException &operator = ( MessageBoxException && );
  
     // Format a default, internationalized error message for this exception.
     virtual wxString ErrorMessage() const = 0;
  
  private:
     wxString caption;
     mutable bool moved { false };
  };
  
  // MessageBoxException that shows a given, unvarying string.
  class SimpleMessageBoxException /* not final */ : public MessageBoxException
  {
  public:
     explicit SimpleMessageBoxException( const wxString &message_,
        const wxString &caption = _("Message") )
        : MessageBoxException{ caption }
        , message{ message_ }
     {}
     ~SimpleMessageBoxException() override;
  
     SimpleMessageBoxException( const SimpleMessageBoxException& ) = default;
     SimpleMessageBoxException &operator = (
        SimpleMessageBoxException && ) PROHIBITED;
  
     std::unique_ptr< AudacityException > Move() override;
  
     // Format a default, internationalized error message for this exception.
     virtual wxString ErrorMessage() const override;
  
  private:
     wxString message;
  };
  
  struct DefaultDelayedHandlerAction
  {
     void operator () (AudacityException *pException) const
     {
        if ( pException )
           pException->DelayedHandlerAction();
     }
  };
  
  // Helpers for defining GuardedCall:
  
  // Call one function object,
  // then another unless the first throws, return result of first
  template <typename R> struct Sequencer {
     template <typename F1, typename Argument, typename F2>
     R operator () (const F1 &f1, Argument &&a, const F2 &f2)
     {
        auto result = f1( std::forward<Argument>(a) );
        f2();
        return result;
     }
  };
  // template specialization to allow R to be void
  template <> struct Sequencer<void> {
     template <typename F1, typename Argument, typename F2>
     void operator () (const F1 &f1, Argument &&a, const F2 &f2)
     {
        f1( std::forward<Argument>(a) );
        f2();
     }
  };
  
  // Classes that can supply the second argument of GuardedCall:
  // Frequently useful converter of all exceptions to some failure constant
  template <typename R> struct SimpleGuard
  {
     explicit SimpleGuard( R value ) : m_value{ value } {}
     R operator () ( AudacityException * ) const { return m_value; }
     const R m_value;
  };
  
  // Simple guard specialization that returns bool, and defines Default
  template<> struct SimpleGuard<bool>
  {
     explicit SimpleGuard( bool value ) : m_value{ value } {}
     bool operator () ( AudacityException * ) const { return m_value; }
     static SimpleGuard Default()
        { return SimpleGuard{ false }; }
     const bool m_value;
  };
  
  // Simple guard specialization that returns nothing, and defines Default
  template<> struct SimpleGuard<void>
  {
     SimpleGuard() {}
     void operator () ( AudacityException * ) const {}
     static SimpleGuard Default() { return {}; }
  };
  
  template < typename R >
  SimpleGuard< R > MakeSimpleGuard( R value )
  { return SimpleGuard< R >{ value }; }
  
  inline SimpleGuard< void > MakeSimpleGuard() { return {}; }
  
  /**
   * Call the body function (usually a lambda) inside a try block.
   *
   * The handler intercepts exceptions, and is passed nullptr if the
   * exception is of a type not defined by Audacity.  It may return a value
   * for the guarded call or throw the same or another exception.
   * It executes in the same thread as the body.
   *
   * If the handler catches non-null and does not throw, then delayedHandler
   * executes later in the main thread, in idle time of the event loop.
   */
  template <
     typename R, // return type
  
     typename F1, // function object with signature R()
  
     typename F2 = SimpleGuard< R >, // function object
        // with signature R( AudacityException * )
  
     typename F3 =
        DefaultDelayedHandlerAction // Any( AudacityException * ), ignore return
  >
  R GuardedCall
     ( const F1 &body,
       const F2 &handler = F2::Default(),
       const F3 &delayedHandler = {} )
  {
     try { return body(); }
     catch ( AudacityException &e ) {
        return Sequencer<R>{}( handler, &e,
           [&] {
              auto pException =
                 std::shared_ptr< AudacityException > { e.Move().release() };
              wxTheApp->CallAfter( [=] { // capture pException by value
                 delayedHandler( pException.get() );
              } );
           }
        );
     }
     catch ( ... ) {
        return handler( nullptr );
     }
  }
  
  #endif
  