forked from Alepha/Alepha
585 lines
22 KiB
C++
585 lines
22 KiB
C++
static_assert( __cplusplus > 2020'99 );
|
|
|
|
#pragma once
|
|
|
|
#include <Alepha/Alepha.h>
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <string>
|
|
#include <exception>
|
|
#include <stdexcept>
|
|
#include <string_view>
|
|
#include <typeindex>
|
|
|
|
#include "Concepts.h"
|
|
|
|
namespace Alepha::Hydrogen ::detail:: Exception_m
|
|
{
|
|
inline namespace exports
|
|
{
|
|
/*!
|
|
* @file
|
|
*
|
|
* Exception grades -- Exceptions have different grades of severity.
|
|
*
|
|
* In Alepha, there are several "grades" of exception types which can be thrown. The grade of
|
|
* an exception is "branded" into its name as the last word in camel case.
|
|
*
|
|
* * `Exception`: All exceptions inherit from this interface. Catching this will
|
|
* catch anything which is part of this system. Normally you just ignore this grade.
|
|
* Code that needs to catch *everything* should not catch `Exception`, but `catch( ... )`
|
|
* instead. `Exception` is the mechanism by which various situations are reported.
|
|
* For comparison, Java calls this class `Throwable`.
|
|
*
|
|
* * `Condition`: An out-of-band message from functions which notify their callers of
|
|
* new information that affects the ability to fulfill the common case expected
|
|
* result. Note that this kind of `Exception` is not considered a contract `Violation`.
|
|
* This exception can be thrown as part of normal program operation -- it is a control
|
|
* flow device.
|
|
*
|
|
* * `Notification`: When a thread is interrupted as a notification, all `Exception`s thrown
|
|
* to do so are derived from this type. Alepha threads are setup to catch and discard
|
|
* `Exception`s of this grade in the thread start function. It is legal to catch `Exception`s
|
|
* of this type type and silence it; however, `Notification` typically means that the
|
|
* target thread needs to change its behaviour. (Note that `ThreadInterrupt` is entirely
|
|
* independent from the Alepha exception hierarchy -- this helps ensure that the thread
|
|
* termination mechanism works correctly.)
|
|
*
|
|
* * `Error`: This is the exception grade you would typically want to recover from.
|
|
* Catch this grade, in most circumstances. They should contain sufficient information in their
|
|
* data pack to facilitate a proper programmatic recovery. All exceptions of this grade
|
|
* will also have `std::exception` as one of its bases, thus code which is unaware of
|
|
* Alepha exceptions, but handles basic standard exceptions cleanly, will work just fine.
|
|
* When an `Error` models something that the standard library models, such as
|
|
* `std::bad_alloc`, then that `Error` will be eligible for catch by that base as well.
|
|
*
|
|
* * `CriticalError`: This exception grade represents a form of moderately-unrecoverable condition.
|
|
* The `CriticalError` grade typically indicates a condition that prevents the current thread or
|
|
* program state from being easily transitioned to a recovered state. However, a very
|
|
* large state transform, such as an unwind to the top-of-thread-callstack handler, may
|
|
* be able to recover. For example, no more available operating system file handles.
|
|
* Tearing down several client handlers in a multi-client server might alleviate this condition.
|
|
*
|
|
* * `Violation`: This exception grade represents an impossible to recover from condition.
|
|
* Think of the handler for `Violation` as-if it were a `[[noreturn]]` function. Catch
|
|
* handlers for this grade should only clean up resources which might cause persistent
|
|
* state corruption. A program probably SHOULD ignore these and allow a core dump to
|
|
* be emitted. An example of this might be: Runtime detection of dereference of a
|
|
* raw pointer set to `nullptr`. This would typically indicate some kind of program
|
|
* bug. `Violation::~Violation` is setup to call `abort()` when called. In some sense
|
|
* this type is what `std::logic_error` is often used to represent.
|
|
*/
|
|
|
|
template< typename ... Bases >
|
|
struct bases : virtual public Bases... {};
|
|
|
|
template< typename unique, typename GradeType, typename Bases >
|
|
class synthetic_any_tagged_type
|
|
{
|
|
};
|
|
|
|
template< typename unique_handle, typename GradeType, typename ... Bases >
|
|
class synthetic_exception
|
|
: virtual public bases< GradeType, Bases... >
|
|
{
|
|
public:
|
|
using grade_type= GradeType;
|
|
|
|
class any_tagged_type
|
|
: virtual public bases< synthetic_exception, typename GradeType::any_tagged_type, typename Bases::any_tagged_type... >
|
|
{
|
|
public:
|
|
using grade_type= GradeType;
|
|
};
|
|
|
|
template< typename tag >
|
|
class tagged_type
|
|
: virtual public bases< synthetic_exception, any_tagged_type, typename GradeType::template tagged_type< tag >, typename Bases::template tagged_type< tag >... >
|
|
{
|
|
public:
|
|
using grade_type= GradeType;
|
|
};
|
|
};
|
|
|
|
class Exception;
|
|
class Condition;
|
|
class Notification;
|
|
class Error;
|
|
class CriticalError;
|
|
class Violation;
|
|
|
|
using Grades= TypeList
|
|
<
|
|
Exception,
|
|
Condition,
|
|
Notification,
|
|
Error,
|
|
CriticalError,
|
|
Violation
|
|
>;
|
|
|
|
template< typename T >
|
|
concept ExceptionGrade= list_contains_v< Grades, T >;
|
|
|
|
template< typename unique_handle, ExceptionGrade GradeType, typename ... Bases >
|
|
using create_exception= synthetic_exception< unique_handle, GradeType, Bases ... >;
|
|
|
|
template< typename Exc >
|
|
using AnyTagged= typename Exc::any_tagged_type;
|
|
|
|
template< typename Exc, typename tag >
|
|
using Tagged= typename Exc::template tagged_type< tag >;
|
|
|
|
class Exception
|
|
{
|
|
public:
|
|
using grade_type= Exception;
|
|
|
|
class any_tagged_type;
|
|
template< typename Tag > class tagged_type;
|
|
|
|
virtual ~Exception()= default;
|
|
virtual const char *message() const noexcept= 0;
|
|
|
|
template< typename Target >
|
|
const Target &
|
|
as() const
|
|
{
|
|
if( not is_a< Target >() )
|
|
{
|
|
// TODO: Structured exception recovery here...
|
|
}
|
|
|
|
return dynamic_cast< const Target & >( *this );
|
|
}
|
|
|
|
template< typename Target >
|
|
bool
|
|
is_a() const noexcept
|
|
{
|
|
return dynamic_cast< const Target * >( this );
|
|
}
|
|
};
|
|
class Exception::any_tagged_type
|
|
: virtual public grade_type
|
|
{
|
|
public:
|
|
virtual std::type_index tag() const noexcept= 0;
|
|
};
|
|
template< typename Tag >
|
|
class Exception::tagged_type
|
|
: virtual public grade_type, virtual public grade_type::any_tagged_type
|
|
{
|
|
public:
|
|
std::type_index
|
|
tag() const noexcept final
|
|
{
|
|
return typeid( std::type_identity< Tag > );
|
|
}
|
|
};
|
|
using AnyTaggedException= AnyTagged< Exception >;
|
|
template< typename tag >
|
|
using TaggedException= Tagged< Exception, tag >;
|
|
|
|
// `Condition`s are "events" that indicate a need
|
|
// for special control flow changes.
|
|
//
|
|
// They must be handled, but they do not represent
|
|
// an error -- just a "time to change your focus".
|
|
class Condition
|
|
: public virtual Exception
|
|
{
|
|
public:
|
|
using grade_type= Condition;
|
|
|
|
class any_tagged_type;
|
|
template< typename tag >
|
|
class tagged_type;
|
|
};
|
|
class Condition::any_tagged_type
|
|
: public virtual bases< grade_type, Exception::any_tagged_type > {};
|
|
template< typename tag >
|
|
class Condition::tagged_type
|
|
: public virtual bases< grade_type::any_tagged_type, Exception::tagged_type< tag > > {};
|
|
using AnyTaggedCondition= Condition::any_tagged_type;
|
|
template< typename tag >
|
|
using TaggedCondition= Condition::tagged_type< tag >;
|
|
|
|
|
|
// `Notification`s are "events" or "interrupts" that
|
|
// if ignored will gracefully terminate the current
|
|
// thread, but not halt the program.
|
|
class Notification
|
|
: public virtual Exception
|
|
{
|
|
public:
|
|
using grade_type= Notification;
|
|
|
|
class any_tagged_type;
|
|
template< typename tag >
|
|
class tagged_type;
|
|
};
|
|
class Notification::any_tagged_type
|
|
: public virtual bases< grade_type, Exception::any_tagged_type > {};
|
|
template< typename tag >
|
|
class Notification::tagged_type
|
|
: public virtual bases< grade_type::any_tagged_type, Exception::tagged_type< tag > > {};
|
|
using AnyTaggedNotification= Notification::any_tagged_type;
|
|
template< typename tag >
|
|
using TaggedNotification= Notification::tagged_type< tag >;
|
|
|
|
// `Error`s are recoverable at any point.
|
|
class ErrorBridgeInterface
|
|
{
|
|
public:
|
|
virtual const char *what() const noexcept= 0;
|
|
};
|
|
class Error
|
|
: virtual public bases< Exception >, virtual private ErrorBridgeInterface
|
|
{
|
|
public:
|
|
using grade_type= Error;
|
|
using ErrorBridgeInterface::what;
|
|
|
|
class any_tagged_type;
|
|
template< typename tag >
|
|
class tagged_type;
|
|
};
|
|
class Error::any_tagged_type : virtual public bases< grade_type, Exception::any_tagged_type > {};
|
|
template< typename tag >
|
|
class Error::tagged_type
|
|
: virtual public bases< grade_type::any_tagged_type, Exception::tagged_type< tag > > {};
|
|
using AnyTaggedError= Error::any_tagged_type;
|
|
template< typename tag >
|
|
using TaggedError= Error::tagged_type< tag >;
|
|
|
|
// `CriticalError`s are only really recoverable by terminating
|
|
// the major procedure underway. Like terminating the
|
|
// entire thread or similar. Essentially, arbitrarily
|
|
// localized recovery is impossible.
|
|
class CriticalError
|
|
: virtual public bases< Exception >
|
|
{
|
|
public:
|
|
using grade_type= CriticalError;
|
|
|
|
class any_tagged_type;
|
|
template< typename tag >
|
|
class tagged_type;
|
|
};
|
|
class CriticalError::any_tagged_type
|
|
: virtual public bases< grade_type, Exception::any_tagged_type > {};
|
|
template< typename tag >
|
|
class CriticalError::tagged_type
|
|
: public virtual bases< grade_type::any_tagged_type, Exception::tagged_type< tag > > {};
|
|
using AnyTaggedCriticalError= CriticalError::any_tagged_type;
|
|
template< typename tag >
|
|
using TaggedCriticalError= CriticalError::tagged_type< tag >;
|
|
|
|
// `Violation`s are unrecoverable events which happen to
|
|
// the process. They are impossible to recover from.
|
|
// Handlers for this should be treated almost like
|
|
// `[[noreturn]]` functions, such as `std::terminate_handler`.
|
|
// Mostly one would catch this class if they intended to
|
|
// perform a bit of local persistent state sanitization
|
|
// which is somewhat different to the normal dtors in scope
|
|
// and then continue the unwind process
|
|
class Violation
|
|
: virtual public bases< Exception >
|
|
{
|
|
private:
|
|
bool active= true;
|
|
|
|
public:
|
|
using grade_type= Violation;
|
|
class any_tagged_type;
|
|
template< typename tag >
|
|
class tagged_type;
|
|
|
|
~Violation() override { if( not active ) abort(); }
|
|
|
|
Violation()= default;
|
|
|
|
Violation( const Violation © )= delete;
|
|
Violation( Violation © ) : active( copy.active ) { copy.active= false; }
|
|
};
|
|
class Violation::any_tagged_type : virtual public bases< grade_type, Exception::any_tagged_type > {};
|
|
template< typename tag >
|
|
class Violation::tagged_type : virtual public bases< grade_type::any_tagged_type, Exception::tagged_type< tag > > {};
|
|
using AnyTaggedViolation= Violation::any_tagged_type;
|
|
template< typename tag >
|
|
using TaggedViolation= Violation::tagged_type< tag >;
|
|
|
|
template< typename T >
|
|
concept DerivedFromError= std::is_base_of_v< Error, T >;
|
|
|
|
class NamedResourceStorage;
|
|
class NamedResourceInterface
|
|
{
|
|
public:
|
|
using storage_type= NamedResourceStorage;
|
|
|
|
virtual ~NamedResourceInterface()= default;
|
|
virtual std::string_view resourceName() const noexcept= 0;
|
|
};
|
|
class NamedResourceStorage
|
|
: virtual public NamedResourceInterface
|
|
{
|
|
private:
|
|
std::string storage;
|
|
|
|
public:
|
|
std::string_view resourceName() const noexcept final { return storage; }
|
|
};
|
|
class NamedResourceException : public virtual create_exception< struct named_resource_throwable, Exception >, virtual public NamedResourceInterface {};
|
|
using AnyTaggedNamedResourceException= NamedResourceException::any_tagged_type;
|
|
template< typename tag >
|
|
using TaggedNamedResourceException= NamedResourceException::tagged_type< tag >;
|
|
|
|
using NamedResourceNotification= create_exception< struct named_resource_notification, Notification, NamedResourceException >;
|
|
using AnyTaggedNamedResourceNotification= NamedResourceNotification::any_tagged_type;
|
|
template< typename tag >
|
|
using TaggedNamedResourceNotification= NamedResourceNotification::tagged_type< tag >;
|
|
|
|
using NamedResourceError= create_exception< struct named_resource_exception, Error, NamedResourceException >;
|
|
using AnyTaggedNamedResourceError= NamedResourceError::any_tagged_type;
|
|
template< typename tag >
|
|
using TaggedNamedResourceError= NamedResourceError::tagged_type< tag >;
|
|
|
|
using NamedResourceCriticalError= create_exception< struct named_resource_error, CriticalError, NamedResourceException >;
|
|
using AnyTaggedNamedResourceCriticalError= NamedResourceCriticalError::any_tagged_type;
|
|
template< typename tag >
|
|
using TaggedNamedResourceCriticalError= NamedResourceCriticalError::tagged_type< tag >;
|
|
|
|
using NamedResourceViolation= create_exception< struct named_resource_violation, Violation, NamedResourceException >;
|
|
using AnyTaggedNamedResourceViolation= NamedResourceViolation::any_tagged_type;
|
|
template< typename tag >
|
|
using TaggedNamedResourceViolation= NamedResourceViolation::tagged_type< tag >;
|
|
|
|
class OutOfRangeException
|
|
: virtual public create_exception< struct out_of_range_throwable, Exception > {};
|
|
using AnyTaggedOutOfRangeException= OutOfRangeException::any_tagged_type;
|
|
template< typename tag >
|
|
using TaggedOutOfRangeException= OutOfRangeException::tagged_type< tag >;
|
|
|
|
using OutOfRangeError= create_exception< struct out_of_range_throwable, Error, OutOfRangeException >;
|
|
using AnyTaggedOutOfRangeError= OutOfRangeError::any_tagged_type;
|
|
template< typename tag >
|
|
using TaggedOutOfRangeError= OutOfRangeError::tagged_type< tag >;
|
|
|
|
using OutOfRangeCriticalError= create_exception< struct out_of_range_throwable, CriticalError, OutOfRangeException >;
|
|
using AnyTaggedOutOfRangeCriticalError= OutOfRangeCriticalError::any_tagged_type;
|
|
template< typename tag >
|
|
using TaggedOutOfRangeCriticalError= OutOfRangeCriticalError::tagged_type< tag >;
|
|
|
|
using OutOfRangeViolation= create_exception< struct out_of_range_throwable, Violation, OutOfRangeException >;
|
|
using AnyTaggedOutOfRangeViolation= OutOfRangeViolation::any_tagged_type;
|
|
template< typename tag >
|
|
using TaggedOutOfRangeViolation= OutOfRangeViolation::tagged_type< tag >;
|
|
|
|
class IndexedRangeInformationStorage;
|
|
class IndexedRangeInformationInterface
|
|
{
|
|
public:
|
|
using storage_type= IndexedRangeInformationStorage;
|
|
virtual ~IndexedRangeInformationInterface()= default;
|
|
virtual std::size_t requested() const noexcept= 0;
|
|
virtual std::size_t lowerBound() const noexcept= 0;
|
|
virtual std::size_t upperBound() const noexcept= 0;
|
|
};
|
|
class IndexedRangeInformationStorage
|
|
: virtual public IndexedRangeInformationInterface
|
|
{
|
|
private:
|
|
std::size_t bottom;
|
|
std::size_t top;
|
|
std::size_t request;
|
|
|
|
public:
|
|
std::size_t lowerBound() const noexcept override { return bottom; }
|
|
std::size_t upperBound() const noexcept override { return top; }
|
|
std::size_t requested() const noexcept override { return request; }
|
|
};
|
|
class IndexOutOfRangeException
|
|
: virtual public create_exception< struct index_out_of_range_throwable, Exception, OutOfRangeException > {};
|
|
using AnyTaggedIndexOutOfRangeException= IndexOutOfRangeException::any_tagged_type;
|
|
template< typename tag >
|
|
using TaggedIndexOutOfRangeException= IndexOutOfRangeException::tagged_type< tag >;
|
|
|
|
class IndexOutOfRangeError
|
|
: virtual public create_exception< struct index_out_of_range_throwable, Error, OutOfRangeError, IndexOutOfRangeException > {};
|
|
using AnyTaggedIndexOutOfRangeException= IndexOutOfRangeException::any_tagged_type;
|
|
template< typename tag >
|
|
using TaggedIndexOutOfRangeException= IndexOutOfRangeException::tagged_type< tag >;
|
|
|
|
class IndexOutOfRangeCriticalError
|
|
: virtual public create_exception< struct index_out_of_range_throwable, CriticalError, OutOfRangeCriticalError, IndexOutOfRangeException > {};
|
|
using AnyTaggedIndexOutOfRangeCriticalError= IndexOutOfRangeCriticalError::any_tagged_type;
|
|
template< typename tag >
|
|
using TaggedIndexOutOfRangeCriticalError= IndexOutOfRangeCriticalError::tagged_type< tag >;
|
|
|
|
|
|
class IndexOutOfRangeViolation
|
|
: virtual public create_exception< struct index_out_of_range_throwable, Violation, OutOfRangeViolation, IndexOutOfRangeException > {};
|
|
using AnyTaggedIndexOutOfRangeViolation= IndexOutOfRangeViolation::any_tagged_type;
|
|
template< typename tag >
|
|
using TaggedIndexOutOfRangeViolation= IndexOutOfRangeViolation::tagged_type< tag >;
|
|
|
|
|
|
class AllocationAmountStorage;
|
|
class AllocationAmountInterface
|
|
{
|
|
public:
|
|
using storage_type= AllocationAmountStorage;
|
|
virtual ~AllocationAmountInterface()= default;
|
|
virtual std::size_t allocationAmount() const noexcept= 0;
|
|
virtual void setAllocationAmount( std::size_t ) noexcept= 0;
|
|
};
|
|
class AllocationAmountStorage
|
|
: virtual public AllocationAmountInterface
|
|
{
|
|
private:
|
|
std::size_t amount;
|
|
|
|
public:
|
|
std::size_t allocationAmount() const noexcept final { return amount; }
|
|
|
|
void setAllocationAmount( const std::size_t amount ) noexcept { this->amount= amount; }
|
|
};
|
|
class AllocationException
|
|
: virtual public create_exception< struct allocation_throwable, Exception >, virtual public AllocationAmountInterface {};
|
|
using AnyTaggedAllocationException= AllocationException::any_tagged_type;
|
|
template< typename tag >
|
|
using TaggedAllocationException= AllocationException::tagged_type< tag >;
|
|
|
|
using AllocationError= create_exception< struct allocation_exception, Error, AllocationException >;
|
|
using AnyTaggedAllocationError= AllocationError::any_tagged_type;
|
|
template< typename tag >
|
|
using TaggedAllocationError= AllocationError::tagged_type< tag >;
|
|
|
|
using AllocationCriticalError= create_exception< struct allocation_error, CriticalError, AllocationException >;
|
|
using AnyTaggedAllocationCriticalError= AllocationCriticalError::any_tagged_type;
|
|
template< typename tag >
|
|
using TaggedAllocationCriticalError= AllocationCriticalError::tagged_type< tag >;
|
|
|
|
using AllocationViolation= create_exception< struct allocation_violation, Violation, AllocationException >;
|
|
using AnyTaggedAllocationViolation= AllocationViolation::any_tagged_type;
|
|
template< typename tag >
|
|
using TaggedAllocationViolation= AllocationViolation::tagged_type< tag >;
|
|
|
|
class MessageStorage
|
|
: virtual public Exception
|
|
{
|
|
protected:
|
|
std::string storage;
|
|
|
|
MessageStorage()= default;
|
|
explicit MessageStorage( std::string storage ) : storage( std::move( storage ) ) {}
|
|
|
|
public:
|
|
const char *message() const noexcept { return storage.c_str(); }
|
|
};
|
|
|
|
template< typename std_exception >
|
|
class GenericExceptionBridge
|
|
: virtual public std_exception, public virtual ErrorBridgeInterface, virtual public Exception
|
|
{
|
|
public:
|
|
const char *what() const noexcept override { return message(); }
|
|
};
|
|
|
|
template< typename Kind >
|
|
auto
|
|
build_exception( std::string message )
|
|
{
|
|
if constexpr( false ) {}
|
|
else if constexpr( std::is_base_of_v< AllocationError, Kind > )
|
|
{
|
|
class Undergird
|
|
: virtual public Kind, virtual protected GenericExceptionBridge< std::bad_alloc >,
|
|
virtual protected MessageStorage, virtual protected AllocationAmountStorage,
|
|
virtual public AllocationAmountInterface,
|
|
virtual public std::bad_alloc
|
|
{};
|
|
|
|
class Error
|
|
: virtual private Undergird, virtual public Kind, public virtual std::bad_alloc
|
|
{
|
|
public:
|
|
explicit Error( std::string message ) : MessageStorage( std::move( message ) ) {}
|
|
|
|
using Exception::message;
|
|
using std::exception::what;
|
|
};
|
|
|
|
return Error{ std::move( message ) };
|
|
}
|
|
else if constexpr( std::is_base_of_v< IndexOutOfRangeError, Kind > )
|
|
{
|
|
class Undergird
|
|
: virtual public Kind, virtual protected GenericExceptionBridge< std::out_of_range >,
|
|
virtual protected MessageStorage, virtual protected IndexedRangeInformationStorage,
|
|
virtual public std::out_of_range
|
|
{};
|
|
|
|
class Error
|
|
: virtual private Undergird, virtual public Kind, public virtual std::out_of_range
|
|
{
|
|
public:
|
|
explicit Error( std::string message ) : MessageStorage( std::move( message ) ) {}
|
|
using Exception::message;
|
|
using std::exception::what;
|
|
};
|
|
|
|
return Error{ std::move( message ) };
|
|
}
|
|
else if constexpr( std::is_base_of_v< Error, Kind > )
|
|
{
|
|
class Undergird
|
|
: virtual public Kind, virtual protected GenericExceptionBridge< std::exception >,
|
|
virtual protected MessageStorage, virtual public std::exception
|
|
{};
|
|
|
|
class Error
|
|
: virtual private Undergird,
|
|
virtual public Kind,
|
|
virtual public std::exception
|
|
{
|
|
public:
|
|
explicit Error( std::string message ) : MessageStorage( std::move( message ) ) {}
|
|
using Exception::message;
|
|
using std::exception::what;
|
|
};
|
|
|
|
return Error{ std::move( message ) };
|
|
}
|
|
else if constexpr( true )
|
|
{
|
|
class Thrown
|
|
: virtual public Kind, virtual private MessageStorage
|
|
{
|
|
public:
|
|
explicit Thrown( std::string message ) : MessageStorage( std::move( message ) ) {}
|
|
using Exception::message;
|
|
};
|
|
|
|
return Thrown{ std::move( message ) };
|
|
}
|
|
}
|
|
|
|
using FinishedException= create_exception< struct finished_exception, Exception >;
|
|
using AnyTaggedFinishedException= AnyTagged< FinishedException >;
|
|
template< typename tag > using TaggedFinishedException= Tagged< FinishedException, tag >;
|
|
|
|
using FinishedCondition= create_exception< struct finished_condition, Condition, FinishedException >;
|
|
using AnyTaggedFinishedCondition= AnyTagged< FinishedCondition >;
|
|
template< typename tag > using TaggedFinishedCondition= Tagged< FinishedCondition, tag >;
|
|
}
|
|
}
|
|
|
|
namespace Alepha::Hydrogen::inline exports::inline Exception_m
|
|
{
|
|
using namespace detail::Exception_m::exports;
|
|
}
|